diff --git a/hipamd/src/hip_code_object.cpp b/hipamd/src/hip_code_object.cpp index 7070c4e5aa..0d5fb1b4da 100644 --- a/hipamd/src/hip_code_object.cpp +++ b/hipamd/src/hip_code_object.cpp @@ -67,6 +67,11 @@ struct __ClangOffloadBundleHeader { namespace hip { +bool CodeObject::IsClangOffloadMagicBundle(const void* data) { + std::string magic(reinterpret_cast(data), bundle_magic_string_size); + return magic.compare(CLANG_OFFLOAD_BUNDLER_MAGIC_STR) ? false : true; +} + uint64_t CodeObject::ElfSize(const void* emi) { return amd::Elf::getElfSize(emi); } static bool getProcName(uint32_t EFlags, std::string& proc_name, bool& xnackSupported, diff --git a/hipamd/src/hip_code_object.hpp b/hipamd/src/hip_code_object.hpp index efbfbc4d19..db1225af39 100644 --- a/hipamd/src/hip_code_object.hpp +++ b/hipamd/src/hip_code_object.hpp @@ -64,6 +64,8 @@ class CodeObject { static uint64_t ElfSize(const void* emi); + static bool IsClangOffloadMagicBundle(const void* data); + protected: //Given an ptr to image or file, extracts to code object //for corresponding devices diff --git a/hipamd/src/hip_fatbin.cpp b/hipamd/src/hip_fatbin.cpp index d542151164..4ecb9b6cdc 100644 --- a/hipamd/src/hip_fatbin.cpp +++ b/hipamd/src/hip_fatbin.cpp @@ -1,5 +1,6 @@ #include "hip_fatbin.hpp" +#include #include "hip_code_object.hpp" namespace hip { @@ -12,8 +13,9 @@ FatBinaryDeviceInfo::~FatBinaryDeviceInfo() { } } -FatBinaryInfo::FatBinaryInfo(const char* fname, const void* image) - : fdesc_(amd::Os::FDescInit()), fsize_(0), image_(image), uri_(std::string()) { +FatBinaryInfo::FatBinaryInfo(const char* fname, const void* image) : fdesc_(amd::Os::FDescInit()), + fsize_(0), foffset_(0), image_(image), image_mapped_(false), + uri_(std::string()) { if (fname != nullptr) { fname_ = std::string(fname); @@ -31,7 +33,7 @@ FatBinaryInfo::~FatBinaryInfo() { } if (fdesc_ > 0) { - if (fsize_ && !amd::Os::MemoryUnmapFile(image_, fsize_)) { + if (fsize_ && image_mapped_ && !amd::Os::MemoryUnmapFile(image_, fsize_)) { guarantee(false, "Cannot unmap file"); } if (!amd::Os::CloseFileHandle(fdesc_)) { @@ -46,7 +48,185 @@ FatBinaryInfo::~FatBinaryInfo() { uri_ = std::string(); } +hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector& devices) { + amd_comgr_data_t data_object; + amd_comgr_status_t comgr_status = AMD_COMGR_STATUS_SUCCESS; + hipError_t hip_status = hipSuccess; + amd_comgr_code_object_info_t* query_list_array = nullptr; + + // If image was passed as a pointer to our hipMod* api, we can try to extract the file name + // if it was mapped by the app. Otherwise use the COMGR data API. + if (fname_.size() == 0) { + if (image_ == nullptr) { + LogError("Both Filename and image cannot be null"); + return hipErrorInvalidValue; + } + + if(!amd::Os::FindFileNameFromAddress(image_, &fname_, &foffset_)) { + fname_ = std::string(""); + foffset_ = 0; + } + } + + // If file name & path are available (or it is passed to you), then get the file desc to use + // COMGR file slice APIs. + if (fname_.size() > 0) { + // Get File Handle & size of the file. + if (!amd::Os::GetFileHandle(fname_.c_str(), &fdesc_, &fsize_)) + return hipErrorFileNotFound; + + // If the file name exists but the file size is 0, the something wrong with the file or its path + if (fsize_ == 0) + return hipErrorInvalidValue; + + // If image_ is nullptr, then file path is passed via hipMod* APIs, so map the file. + if (image_ == nullptr && !amd::Os::MemoryMapFileDesc(fdesc_, fsize_, foffset_, &image_) + && (image_mapped_ = true)) { + LogError("Cannot map the file descriptor"); + amd::Os::CloseFileHandle(fdesc_); + return hipErrorInvalidValue; + } + } + + // At this line, image should be a valid ptr. + guarantee(image_ != nullptr, "Image cannot be nullptr, file did not map for some reason"); + + do { + + // If the image ptr is not clang offload bundle then just directly point the image. + if (!CodeObject::IsClangOffloadMagicBundle(image_)) { + for (size_t dev_idx=0; dev_idx < devices.size(); ++dev_idx) { + fatbin_dev_info_[devices[dev_idx]->deviceId()] + = new FatBinaryDeviceInfo(image_, CodeObject::ElfSize(image_), 0); + fatbin_dev_info_[devices[dev_idx]->deviceId()]->program_ + = new amd::Program(*devices[dev_idx]->asContext()); + if (fatbin_dev_info_[devices[dev_idx]->deviceId()]->program_ == nullptr) { + hip_status = hipErrorOutOfMemory; + break; + } + } + break; + } + + // Create a data object, if it fails return error + if ((comgr_status = amd_comgr_create_data(AMD_COMGR_DATA_KIND_FATBIN, &data_object)) + != AMD_COMGR_STATUS_SUCCESS) { + LogPrintfError("Creating data object failed with status %d ", comgr_status); + hip_status = hipErrorInvalidValue; + break; + } + +#if !defined(_WIN32) + // Using the file descriptor and file size, map the data object. + if (fdesc_ > 0) { + guarantee(fsize_ > 0, "Cannot have a file size of 0"); + if ((comgr_status = amd_comgr_set_data_from_file_slice(data_object, fdesc_, foffset_, + fsize_)) != AMD_COMGR_STATUS_SUCCESS) { + LogPrintfError("Setting data from file slice failed with status %d ", comgr_status); + hip_status = hipErrorInvalidValue; + break; + } + } else +#endif + if (image_ != nullptr) { + // Using the image ptr, map the data object. + if ((comgr_status = amd_comgr_set_data(data_object, 4096, + reinterpret_cast(image_))) != AMD_COMGR_STATUS_SUCCESS) { + LogPrintfError("Setting data from file slice failed with status %d ", comgr_status); + hip_status = hipErrorInvalidValue; + break; + } + } else { + guarantee(false, "Cannot have both fname_ and image_ as nullptr"); + } + + // Find the unique number of ISAs needed for this COMGR query. + std::unordered_map> unique_isa_names; + for (size_t dev_idx = 0; dev_idx < devices.size(); ++dev_idx) { + std::string device_name = devices[dev_idx]->devices()[0]->isa().isaName(); + if (unique_isa_names.cend() == unique_isa_names.find(device_name)) { + unique_isa_names.insert({device_name, std::make_pair(0,0)}); + } + } + + // Create a query list using COMGR info for unique ISAs. + query_list_array = new amd_comgr_code_object_info_t[unique_isa_names.size()]; + auto isa_it = unique_isa_names.begin(); + for (size_t isa_idx = 0; isa_idx < unique_isa_names.size(); ++isa_idx) { + std::advance(isa_it, isa_idx); + query_list_array[isa_idx].isa = isa_it->first.c_str(); + query_list_array[isa_idx].size = 0; + query_list_array[isa_idx].offset = 0; + } + + // Look up the code object info passing the query list. + if ((comgr_status = amd_comgr_lookup_code_object(data_object, query_list_array, + unique_isa_names.size())) != AMD_COMGR_STATUS_SUCCESS) { + LogPrintfError("Setting data from file slice failed with status %d ", comgr_status); + hip_status = hipErrorInvalidValue; + break; + } + + for (size_t isa_idx = 0; isa_idx < unique_isa_names.size(); ++isa_idx) { + auto unique_it = unique_isa_names.find(query_list_array[isa_idx].isa); + guarantee(unique_isa_names.cend() != unique_it, "Cannot find unique isa"); + unique_it->second = std::pair + (static_cast(query_list_array[isa_idx].size), + static_cast(query_list_array[isa_idx].offset)); + } + + for (size_t dev_idx = 0; dev_idx < devices.size(); ++dev_idx) { + std::string device_name = devices[dev_idx]->devices()[0]->isa().isaName(); + auto dev_it = unique_isa_names.find(device_name); + guarantee(unique_isa_names.cend() != dev_it, + "Cannot find the device name in the unique device name"); + fatbin_dev_info_[devices[dev_idx]->deviceId()] + = new FatBinaryDeviceInfo(reinterpret_cast
(const_cast(image_)) + + dev_it->second.second, dev_it->second.first, + dev_it->second.second); + fatbin_dev_info_[devices[dev_idx]->deviceId()]->program_ + = new amd::Program(*devices[dev_idx]->asContext()); + } + + } while(0); + + if (query_list_array) { + delete[] query_list_array; + } + + // Clean up file and memory resouces if hip_status failed for some reason. + if (hip_status != hipSuccess && hip_status != hipErrorInvalidKernelFile) { + if (image_mapped_) { + if (!amd::Os::MemoryUnmapFile(image_, fsize_)) + guarantee(false, "Cannot unmap the file"); + + image_ = nullptr; + image_mapped_ = false; + } + + if (fdesc_ > 0) { + guarantee(fsize_ > 0, "Size has to greater than 0 too"); + if (!amd::Os::CloseFileHandle(fdesc_)) + guarantee(false, "Cannot close the file handle"); + + fdesc_ = 0; + fsize_ = 0; + } + + if ((comgr_status = amd_comgr_release_data(data_object)) != AMD_COMGR_STATUS_SUCCESS) { + LogPrintfError("Releasing COMGR data failed with status %d ", comgr_status); + return hipErrorInvalidValue; + } + } + + return hip_status; +} + hipError_t FatBinaryInfo::ExtractFatBinary(const std::vector& devices) { + if (!HIP_USE_RUNTIME_UNBUNDLER) { + return ExtractFatBinaryUsingCOMGR(devices); + } + hipError_t hip_error = hipSuccess; std::vector> code_objs; diff --git a/hipamd/src/hip_fatbin.hpp b/hipamd/src/hip_fatbin.hpp index 219a96e802..d903550d81 100644 --- a/hipamd/src/hip_fatbin.hpp +++ b/hipamd/src/hip_fatbin.hpp @@ -39,6 +39,7 @@ public: ~FatBinaryInfo(); // Loads Fat binary from file or image, unbundles COs for devices. + hipError_t ExtractFatBinaryUsingCOMGR(const std::vector& devices); hipError_t ExtractFatBinary(const std::vector& devices); hipError_t AddDevProgram(const int device_id); hipError_t BuildProgram(const int device_id); @@ -71,9 +72,11 @@ private: std::string fname_; // File name amd::Os::FileDesc fdesc_; // File descriptor size_t fsize_; // Total file size + size_t foffset_; // File Offset where the fat binary is present. // Even when file is passed image will be mmapped till ~desctructor. const void* image_; // Image + bool image_mapped_; // flag to detect if image is mapped // Only used for FBs where image is directly passed std::string uri_; // Uniform resource indicator