Files
rocm-systems/rocclr/runtime/device/hsa/hsaprogram.cpp
T
foreman 3e74ee1f88 P4 to Git Change 1086296 by emankov@em-hsa-amd on 2014/10/10 07:46:11
ECR #333753 - HSA RT/Performance: Elimination of HSAIL text usage in RT (part 2)

	(as it's already done for gpuprogram.cpp)

	Extracting HSAIL from the binary and parsing it for the kernel names in RT were replaced with aclQueryInfo call for RT_KERNEL_NAMES. Kernel names are obtained now from the corresponding metadata symbols names, which are already presented in BIF at kernel finalization stage.

	Side effect: performance improvement

	Next Step: Performance: Stop obligatory BRIG disassembling to HSAIL and insertion into BIF (previously was needed only by RT).

	testing: pre check-in

	Reviewers: Stanislav Mekhanoshin, German Andryeyev, Brian Sumner

Affected files ...

... //depot/stg/opencl/drivers/opencl/runtime/device/hsa/hsaprogram.cpp#37 edit
... //depot/stg/opencl/drivers/opencl/runtime/device/hsa_foundation/hsaprogram.cpp#6 edit
2014-10-10 07:57:34 -04:00

727 righe
27 KiB
C++

//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef WITHOUT_FSA_BACKEND
#include "device/hsa/hsaprogram.hpp"
#include "compiler/lib/loaders/elf/elf.hpp"
#include "compiler/lib/utils/options.hpp"
#include "runtime/device/hsa/hsakernel.hpp"
#include "runtime/device/hsa/hsacompilerlib.hpp"
#include "runtime/device/hsa/oclhsa_common.hpp"
#include "utils/bif_section_labels.hpp"
#include "utils/libUtils.h"
#include <string>
#include <vector>
#include <cstring>
#include <fstream>
#include <sstream>
#include <iostream>
#include <istream>
#endif // WITHOUT_FSA_BACKEND
namespace oclhsa {
#ifndef WITHOUT_FSA_BACKEND
/* Temporary log function for the compiler library */
static void logFunction(const char *msg, size_t size) {
std::cout << "Compiler Library log :" << msg << std::endl;
}
FSAILProgram::~FSAILProgram() {
unloadBrig();
acl_error error;
// Free the elf binary
if (binaryElf_ != NULL) {
error = g_complibApi._aclBinaryFini(binaryElf_);
if (error != ACL_SUCCESS) {
LogWarning( "Error while destroying the acl binary \n" );
}
}
}
FSAILProgram::FSAILProgram(oclhsa::NullDevice& device): device::Program(device),
llvmBinary_(),
binaryElf_(NULL),
device_(device),
isBrigLoaded_(false)
{
memset(&binOpts_, 0, sizeof(binOpts_));
binOpts_.struct_size = sizeof(binOpts_);
//binOpts_.elfclass = LP64_SWITCH( ELFCLASS32, ELFCLASS64 );
//Setting as 32 bit because hsail64 returns an invalid aclTargetInfo
//when aclGetTargetInfo is called - EPR# 377910
binOpts_.elfclass = ELFCLASS32;
binOpts_.bitness = ELFDATA2LSB;
binOpts_.alloc = &::malloc;
binOpts_.dealloc = &::free;
}
bool FSAILProgram::initClBinary(char *binaryIn, size_t size) { // Save the
// original
// binary that
// isn't owned
// by ClBinary
clBinary()->saveOrigBinary(binaryIn, size);
char *bin = binaryIn;
size_t sz = size;
int encryptCode;
char *decryptedBin;
size_t decryptedSize;
if (!clBinary()->decryptElf(binaryIn, size,
&decryptedBin, &decryptedSize, &encryptCode)) {
return false;
}
if (decryptedBin != NULL) {
// It is decrypted binary.
bin = decryptedBin;
sz = decryptedSize;
}
// Both 32-bit and 64-bit are allowed!
if (!amd::isElfMagic(bin)) {
// Invalid binary.
if (decryptedBin != NULL) {
delete[]decryptedBin;
}
return false;
}
clBinary()->setFlags(encryptCode);
return clBinary()->setBinary(bin, sz, (decryptedBin != NULL));
}
bool FSAILProgram::initBuild(amd::option::Options *options) {
if (!device::Program::initBuild(options)) {
return false;
}
// Need to get device information from CAL !?!?
// Needs the device pointer from CAL to send to options class
//
// Shreyas: Commenting this might cause a bug - keeping this fro now
// options->setPerBuildInfo("hsa",
// binary_.getEncryptCode()
// );
// Elf Binary setup
std::string outFileName;
// true means fsail required
clBinary()->init(options, true);
if (options->isDumpFlagSet(amd::option::DUMP_BIF)) {
outFileName = options->getDumpFileName(".bin");
}
bool useELF64 = getCompilerOptions()->oVariables->EnableGpuElf64;
if (!clBinary()->setElfOut(useELF64 ? ELFCLASS64 : ELFCLASS32,
(outFileName.size() >
0) ? outFileName.c_str() : NULL)) {
LogError("Setup elf out for gpu failed");
return false;
}
return true;
}
// ! post-compile setup for GPU
bool FSAILProgram::finiBuild(bool isBuildGood) {
clBinary()->resetElfOut();
clBinary()->resetElfIn();
if (!isBuildGood) {
// Prevent the encrypted binary form leaking out
clBinary()->setBinary(NULL, 0);
}
return device::Program::finiBuild(isBuildGood);
}
static char *readFile(std::string source_filename, size_t &size) {
FILE *fp = ::fopen(source_filename.c_str(), "rb");
unsigned int length;
size_t offset = 0;
char *ptr;
if (!fp) {
return NULL;
}
// obtain file size.
::fseek(fp, 0, SEEK_END);
length = ::ftell(fp);
::rewind(fp);
ptr = reinterpret_cast<char *>(malloc(offset + length + 1));
if (length != fread(&ptr[offset], 1, length, fp)) {
free(ptr);
return NULL;
}
ptr[offset + length] = '\0';
size = offset + length;
::fclose(fp);
return ptr;
}
aclType FSAILProgram::getNextCompilationStageFromBinary() {
acl_error errorCode;
size_t secSize = 0;
aclType from = ACL_TYPE_DEFAULT;
// Checking llvmir in .llvmir section
bool isLlvmirText = true;
const void *llvmirText = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclLLVMIR,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isLlvmirText = false;
}
// Checking compile & link options in .comment section
bool isOpts = true;
const void *opts = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclCOMMENT,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isOpts = false;
}
if (isLlvmirText) {
from = ACL_TYPE_LLVMIR_BINARY;
} else {
if (!isLlvmirText) {
buildLog_ +="Error while linking : \
Invalid binary (Missing LLVMIR section)\n" ;
}
if (!isOpts) {
buildLog_ +="Warning while linking : \
Invalid binary (Missing COMMENT section)\n" ;
}
return ACL_TYPE_DEFAULT;
}
bool isHsailText = true;
// Checking HSAIL in .cg section
const void *hsailText = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclCODEGEN,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isHsailText = false;
}
// Checking BRIG STRTAB in .brig_strtab section
bool isBrigStrtab = true;
const void *brigStrtab = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclBRIGstrs,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isBrigStrtab = false;
}
// Checking BRIG CODE in .brig_code section
bool isBrigCode = true;
const void *brigCode = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclBRIGcode,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isBrigCode = false;
}
// Checking BRIG OPERANDS in .brig_operands section
bool isBrigOps = true;
const void *brigOps = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclBRIGoprs,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isBrigOps = false;
}
if (isHsailText && isBrigStrtab && isBrigCode && isBrigOps) {
from = ACL_TYPE_HSAIL_BINARY;
} else if (!isHsailText && !isBrigStrtab && !isBrigCode && !isBrigOps) {
from = ACL_TYPE_LLVMIR_BINARY;
} else {
if (!isHsailText) {
buildLog_ +="Error while linking : \
Invalid binary (Missing CG section)\n" ;
}
if (!isBrigStrtab) {
buildLog_ +="Error while linking : \
Invalid binary (Missing BRIG_STRTAB section)\n" ;
}
if (!isBrigCode) {
buildLog_ +="Error while linking : \
Invalid binary (Missing BRIG_CODE section)\n" ;
}
if (!isBrigOps) {
buildLog_ +="Error while linking : \
Invalid binary (Missing BRIG_OPERANDS section)\n" ;
}
return ACL_TYPE_DEFAULT;
}
// Checking ISA in .text section
bool isShaderIsa = true;
const void *shaderIsa = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&secSize,
aclTEXT,
&errorCode);
if (errorCode != ACL_SUCCESS) {
isShaderIsa = false;
}
if (isShaderIsa && from == ACL_TYPE_LLVMIR_BINARY) {
from = ACL_TYPE_DEFAULT;
}
return from;
}
bool FSAILProgram::updateAclBinaryWithKernelIsaAndDebug(std::string kernelName){
assert(brig_.loadmap_section != NULL);
aclBinary * internalAclBinary = reinterpret_cast<aclBinary*>(brig_.loadmap_section);
std::string openClKernelName("&__OpenCL_" + kernelName + "_kernel");
const oclBIFSymbolStruct* isaSymbolStruct = findBIF30SymStruct(symISABinary);
assert(isaSymbolStruct && "symbol not found");
std::string kernelIsaSymbol = isaSymbolStruct->str[PRE] +
openClKernelName + isaSymbolStruct->str[POST];
const oclBIFSymbolStruct* debugSymbolStruct = findBIF30SymStruct(symDebugInfo);
assert(debugSymbolStruct && "symbol not found");
//For debug symbols, the PRE is used for BRIG debug and the POST is used for
//ISA debug
std::string kernelIsaDebugSymbol = debugSymbolStruct->str[POST] + openClKernelName;
//Extract the ISA section
size_t symbolSize;
acl_error errorCode;
const void* isaSymbol = g_complibApi._aclExtractSymbol(device().compiler(),
internalAclBinary,
&symbolSize,
aclTEXT,
kernelIsaSymbol.c_str(),
&errorCode);
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Failed to extract ISA for kernel";
return false;
}
//Insert the ISA section
errorCode = g_complibApi._aclInsertSymbol(device().compiler(),
binaryElf_,
isaSymbol,
symbolSize,
aclTEXT,
kernelIsaSymbol.c_str());
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Failed to insert ISA for kernel";
return false;
}
const void* debugSymbol = g_complibApi._aclExtractSymbol(device().compiler(),
internalAclBinary,
&symbolSize,
aclHSADEBUG,
kernelIsaDebugSymbol.c_str(),
&errorCode);
//If debug information is available
if (errorCode == ACL_SUCCESS) {
//Update binary with the debug section for the kernel
errorCode = g_complibApi._aclInsertSymbol(device().compiler(),
binaryElf_,
debugSymbol,
symbolSize,
aclHSADEBUG,
kernelIsaDebugSymbol.c_str());
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Failed to insert debug information for kernel";
return false;
}
}
return true;
}
bool FSAILProgram::ExtractSymbolAndCopy(aclSections id,
const char *symbol_name,
void** address_to_copy,
size_t* symbol_size_bytes,
bool verify) {
acl_error error_code;
*symbol_size_bytes = 0;
const void* symbol_data = g_complibApi._aclExtractSymbol(
device().compiler(),
binaryElf_,
symbol_size_bytes,
id,
symbol_name,
&error_code);
//If the section is not mandatory and the section does not exist
//skip this section
if (error_code != ACL_SUCCESS) {
if (!verify) {
return true;
}
std::string error = "Could not find Brig Directive in BIFF: ";
error += symbol_name;
LogError(error.c_str());
buildLog_ += error;
return false;
}
*address_to_copy = malloc(*symbol_size_bytes);
if (*address_to_copy == NULL) {
LogError(" Failed to allocate memory");
return false;
}
memcpy(*address_to_copy, symbol_data, *symbol_size_bytes);
return true;
}
bool FSAILProgram::saveBinaryAndSetType(type_t type) {
//Write binary to memory
void *rawBinary = NULL;
size_t size;
if (g_complibApi._aclWriteToMem(binaryElf_, &rawBinary, &size)
!= ACL_SUCCESS) {
buildLog_ += "Failed to write binary to memory \n";
return false;
}
clBinary()->saveBIFBinary((char*)rawBinary, size);
//Set the type of binary
setType(type);
//Free memory containing rawBinary
binaryElf_->binOpts.dealloc(rawBinary);
return true;
}
bool FSAILProgram::linkImpl(const std::vector<Program *> &inputPrograms,
amd::option::Options *options,
bool createLibrary) {
std::vector<device::Program *>::const_iterator it
= inputPrograms.begin();
std::vector<device::Program *>::const_iterator itEnd
= inputPrograms.end();
acl_error errorCode;
// For each program we need to extract the LLVMIR and create
// aclBinary for each
std::vector<aclBinary *> binaries_to_link;
for (size_t i = 0; it != itEnd; ++it, ++i) {
FSAILProgram *program = (FSAILProgram *)*it;
// Check if the program was created with clCreateProgramWIthBinary
binary_t binary = program->binary();
if ((binary.first != NULL) && (binary.second > 0)) {
// Binary already exists -- we can also check if there is no
// opencl source code
// Need to check if LLVMIR exists in the binary
// If LLVMIR does not exist then is it valid
// We need to pull out all the compiled kernels
// We cannot do this at present because we need at least
// Hsail text to pull the kernels oout
void *mem = const_cast<void *>(binary.first);
binaryElf_ = g_complibApi._aclReadFromMem(mem,
binary.second,
&errorCode);
if (errorCode != ACL_SUCCESS) {
LogWarning("Error while linking : Could not read from raw binary");
return false;
}
}
// At this stage each FSAILProgram contains a valid binary_elf
// Check if LLVMIR is in the binary
// @TODO - Memory leak , cannot free this buffer
// need to fix this.. File EPR on compiler library
size_t llvmirSize = 0;
const void *llvmirText = g_complibApi._aclExtractSection(device().compiler(),
binaryElf_,
&llvmirSize,
aclLLVMIR,
&errorCode);
if (errorCode != ACL_SUCCESS) {
buildLog_ +="Error while linking : \
Invalid binary (Missing LLVMIR section)" ;
return false;
}
// Create a new aclBinary for each LLVMIR and save it in a list
aclBIFVersion ver = g_complibApi._aclBinaryVersion(binaryElf_);
aclBinary *bin = g_complibApi._aclCreateFromBinary(binaryElf_, ver);
binaries_to_link.push_back(bin);
}
// At this stage each FSAILProgram in the list has an aclBinary initialized
// and contains LLVMIR
// We can now go ahead and link them.
if (binaries_to_link.size() > 1) {
errorCode = g_complibApi._aclLink(device().compiler(),
binaries_to_link[0],
binaries_to_link.size() - 1,
&binaries_to_link[1],
ACL_TYPE_LLVMIR_BINARY,
"-create-library",
NULL);
}
else {
errorCode = g_complibApi._aclLink(device().compiler(),
binaries_to_link[0],
0,
NULL,
ACL_TYPE_LLVMIR_BINARY,
"-create-library",
NULL);
}
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Failed to link programs";
return false;
}
// Store the newly linked aclBinary for this program.
binaryElf_ = binaries_to_link[0];
// Free all the other aclBinaries
for (size_t i = 1; i < binaries_to_link.size(); i++) {
g_complibApi._aclBinaryFini(binaries_to_link[i]);
}
if (createLibrary) {
saveBinaryAndSetType(TYPE_LIBRARY);
return true;
}
// Now call linkImpl with the new options
return linkImpl(options);
}
bool FSAILProgram::loadBrig() {
//Copy all the sections into BRIG
memset(&brig_, 0 ,sizeof(HsaBrig));
bool codeStatus = ExtractSymbolAndCopy(aclBRIGcode,
"__BRIG__code",
&brig_.code_section,
&brig_.code_section_byte_size,
true
);
bool oprStatus = ExtractSymbolAndCopy(aclBRIGoprs,
"__BRIG__operands",
&brig_.operand_section,
&brig_.operand_section_byte_size,
true
);
bool strStatus = ExtractSymbolAndCopy(aclBRIGstrs,
"__BRIG__strtab",
&brig_.string_section,
&brig_.string_section_byte_size,
true
);
bool dbgStatus = ExtractSymbolAndCopy(aclHSADEBUG ,
"__debug_brig__",
&brig_.debug_section,
&brig_.debug_section_byte_size,
false
);
if (!codeStatus || !oprStatus || !strStatus || !dbgStatus) {
LogError("Failed to Extract one or more BRIG sections");
buildLog_ += "Error: Failed to Extract one or more BRIG sections";
return false;
}
if(hsacoreapi->HsaLoadBrig(device_.getBackendDevice(), &brig_)
!= kHsaStatusSuccess){
return false;
}
isBrigLoaded_ = true;
return true;
}
bool FSAILProgram::unloadBrig() {
if (isBrigLoaded_ == true) {
HsaStatus status = hsacoreapi->HsaUnloadBrig(&brig_);
if (status != kHsaStatusSuccess){
return false;
}
//Destroy the BRIG
free(brig_.code_section);
free(brig_.operand_section);
free(brig_.string_section);
free(brig_.debug_section);
}
return true;
}
bool FSAILProgram::linkImpl(amd::option::Options *options) {
acl_error errorCode;
aclType continueCompileFrom = ACL_TYPE_LLVMIR_BINARY;
//If the binaryElf_ is not set then program must have been created
// using clCreateProgramWithBinary
if (!binaryElf_) {
binary_t binary = this->binary();
if ((binary.first != NULL) && (binary.second > 0)) {
// Binary already exists -- we can also check if there is no
// opencl source code
// Need to check if LLVMIR exists in the binary
// If LLVMIR does not exist then is it valid
// We need to pull out all the compiled kernels
// We cannot do this at present because we need at least
// Hsail text to pull the kernels oout
void *mem = const_cast<void *>(binary.first);
binaryElf_ = g_complibApi._aclReadFromMem(mem,
binary.second,
&errorCode);
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Error while converting to BRIG: aclBinary init failure \n" ;
LogWarning("aclBinaryInit failed");
return false;
}
// Check that all needed section also exist in binaryElf_
// No any validity checks here
continueCompileFrom = getNextCompilationStageFromBinary();
if (ACL_TYPE_DEFAULT == continueCompileFrom) {
return false;
}
if (ACL_TYPE_HSAIL_BINARY == continueCompileFrom) {
// Save binary in the interface class
// Also load compile & link options from binary into Program class members:
// compileOptions_ & linkOptions_
setBinary(static_cast<char*>(mem), binary.second);
// Compare options loaded from binary with current ones
// If they differ then recompile from ACL_TYPE_LLVMIR_BINARY
// @TODO It is needed to compare options taking into account that:
// 1. options are order independent;
// 2. (may be not trivial) compare only options that affect binary
std::string curOptions = options->origOptionStr + hsailOptions();
if (compileOptions_ + linkOptions_ != curOptions) {
continueCompileFrom = ACL_TYPE_LLVMIR_BINARY;
}
}
}
}
// Compilation from ACL_TYPE_LLVMIR_BINARY to ACL_TYPE_CG in cases:
// 1. if the program is not created with binary;
// 2. if the program is created with binary and contains only .llvmir & .comment
// 3. if the program is created with binary, contains all brig sections,
// but the binary's compile & link options differ from current ones (recompilation);
if (ACL_TYPE_LLVMIR_BINARY == continueCompileFrom) {
std::string curOptions = options->origOptionStr + hsailOptions();
errorCode = g_complibApi._aclCompile(device().compiler(),
binaryElf_,
curOptions.c_str(),
ACL_TYPE_LLVMIR_BINARY,
ACL_TYPE_CG,
logFunction);
}
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Error while converting to BRIG: Compiling LLVMIR to BRIG \n" ;
return false;
}
//Stop compilation if it is an offline device - HSA runtime does not
//support ISA compiled offline
if (!dev().isOnline()) {
return true;
}
const HsaDevice *hsaDevice = dev().getBackendDevice();
if (!loadBrig()) {
buildLog_ += "Error while loading BRIG" ;
return false;
}
size_t kernelNamesSize = 0;
errorCode = aclQueryInfo(dev().compiler(), binaryElf_, RT_KERNEL_NAMES, NULL, NULL, &kernelNamesSize);
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Error while Finalization phase: kernel names query from the ELF failed\n";
return false;
}
if (kernelNamesSize > 0) {
char* kernelNames = new char[kernelNamesSize];
errorCode = aclQueryInfo(dev().compiler(), binaryElf_, RT_KERNEL_NAMES, NULL, kernelNames, &kernelNamesSize);
if (errorCode != ACL_SUCCESS) {
buildLog_ += "Error while Finalization phase: kernel's Metadata is corrupted in the ELF\n";
delete kernelNames;
return false;
}
std::vector<std::string> vKernels = splitSpaceSeparatedString(kernelNames);
delete kernelNames;
std::vector<std::string>::iterator it = vKernels.begin();
bool dynamicParallelism = false;
for (it; it != vKernels.end(); ++it) {
std::string kernelName = *it;
Kernel *aKernel = new oclhsa::Kernel(kernelName,
this,
&brig_,
options->origOptionStr + hsailOptions());
if (!aKernel->init() ) {
return false;
}
aKernel->setUniformWorkGroupSize(options->oVariables->UniformWorkGroupSize);
// Update the binary in the FSAILProgram to save the ISA and debug information.
// This is so the debugger and the profiler can use the a single aclBinary for all their needs.
if (!updateAclBinaryWithKernelIsaAndDebug(kernelName)) {
return false;
}
kernels()[kernelName] = aKernel;
}
}
saveBinaryAndSetType(TYPE_EXECUTABLE);
buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler());
return true;
}
bool FSAILProgram::createBinary(amd::option::Options *options) {
return false;
}
bool FSAILProgram::initClBinary() {
if (clBinary_ == NULL) {
clBinary_ = new ClBinary(static_cast<const Device &>(device()));
if (clBinary_ == NULL) {
return false;
}
}
return true;
}
void FSAILProgram::releaseClBinary() {
if (clBinary_ != NULL) {
delete clBinary_;
clBinary_ = NULL;
}
}
std::string FSAILProgram::hsailOptions() {
std::string hsailOptions;
//Set options for the standard device specific options
//This is just for legacy compiler code
// All our devices support these options now
hsailOptions.append(" -DFP_FAST_FMAF=1");
hsailOptions.append(" -DFP_FAST_FMA=1");
//TODO(sramalin) : Query the device for opencl version
// and only set if -cl-std wasn't specified in
// original build options (app)
//hsailOptions.append(" -cl-std=CL1.2");
//check if the host is 64 bit or 32 bit
LP64_ONLY(hsailOptions.append(" -m64"));
//Now append each extension supported by the device
// one by one
std::string token;
std::istringstream iss("");
iss.str(device().info().extensions_);
while (getline(iss, token, ' ')) {
if (!token.empty()) {
hsailOptions.append(" -D");
hsailOptions.append(token);
hsailOptions.append("=1");
}
}
return hsailOptions;
}
#endif // WITHOUT_FSA_BACKEND
} // namespace hsa