Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 49 additions & 54 deletions projects/clr/hipamd/src/hip_fatbin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ kpack_cache_t getHipKpackCache() {
} // namespace
#endif

FatBinaryInfo::FatBinaryInfo(const char* fname, const void* image)
: foffset_(0), image_(image), image_mapped_(false), uri_(std::string()) {
FatBinaryInfo::FatBinaryInfo(const char* fname, const void* image) : uri_(std::string()) {
if (fname != nullptr) {
fname_ = std::string(fname);
} else {
Expand Down Expand Up @@ -77,25 +76,6 @@ FatBinaryInfo::~FatBinaryInfo() {
delete[] reinterpret_cast<const char*>(i);
}
}
ReleaseImageAndFile();
}

void FatBinaryInfo::ReleaseImageAndFile() {
// Release image_ and ufd_
if (ufd_) {
if (image_mapped_ && !amd::Os::MemoryUnmapFile(image_, ufd_->fsize_)) {
guarantee(false, "Cannot unmap the file");
}

if (!PlatformState::Instance().CloseUniqueFileHandle(ufd_)) {
guarantee(false, "Cannot close file for fdesc: %d", ufd_->fdesc_);
}

ufd_ = nullptr;
image_ = nullptr;
uri_ = std::string();
image_mapped_ = false;
}
}

void ListAllDeviceWithNoCOFromBundle(
Expand Down Expand Up @@ -401,49 +381,34 @@ static bool PopulateCodeObjectMap(
}

hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Device*>& devices) {
if (fname_.empty() && image_ == nullptr) {
if (fname_.empty() && managed_image_.getImage() == nullptr) {
LogError("Both Filename and image cannot be null");
return hipErrorInvalidValue;
}

if (image_ != nullptr) {
if (!amd::Os::FindFileNameFromAddress(image_, &fname_, &foffset_)) {
if (managed_image_.getImage() != nullptr) {
if (!amd::Os::FindFileNameFromAddress(managed_image_.getImage(), &fname_, &foffset_)) {
fname_ = std::string("");
foffset_ = 0;
}
} else {
ufd_ = PlatformState::Instance().GetUniqueFileHandle(fname_.c_str());
if (ufd_ == nullptr) {
return hipErrorFileNotFound;
}

// If the file name exists but the file size is 0, the something wrong with the file or its path
if (ufd_->fsize_ == 0) {
return hipErrorInvalidImage;
}

// If image_ is nullptr, then file path is passed via hipMod* APIs, so map the file.
if (!amd::Os::MemoryMapFileDesc(ufd_->fdesc_, ufd_->fsize_, foffset_, &image_)) {
LogError("Cannot map the file descriptor");
PlatformState::Instance().CloseUniqueFileHandle(ufd_);
return hipErrorInvalidValue;
}

image_mapped_ = true;
hipError_t status = managed_image_.map(fname_, foffset_);
if (status != hipSuccess) return status;
}
guarantee(image_ != nullptr, "Image cannot be nullptr, file:%s did not map for some reason",
fname_.c_str());
guarantee(managed_image_.getImage() != nullptr,
"Image cannot be nullptr, file:%s did not map for some reason", fname_.c_str());

bool is_compressed = IsCodeObjectCompressed(image_),
is_uncompressed = IsCodeObjectUncompressed(image_);
bool is_compressed = IsCodeObjectCompressed(managed_image_.getImage()),
is_uncompressed = IsCodeObjectUncompressed(managed_image_.getImage());

// It better be elf if its neither compressed nor uncompressed
if (!is_compressed && !is_uncompressed) {
if (IsCodeObjectElf(image_)) {
if (IsCodeObjectElf(managed_image_.getImage())) {
// Load the binary directly
auto elf_size = amd::Elf::getElfSize(image_);
auto elf_size = amd::Elf::getElfSize(managed_image_.getImage());
for (size_t i = 0; i < devices.size(); i++) {
if (hipSuccess != AddDevProgram(devices[i], image_, elf_size, 0))
if (hipSuccess != AddDevProgram(devices[i], managed_image_.getImage(), elf_size, 0))
return hipErrorInvalidImage;
}
return hipSuccess; // We are done since it was already ELF
Expand Down Expand Up @@ -471,15 +436,16 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector<hip::Devi

std::map<std::string, std::pair<const void*, size_t>> code_obj_map; //!< code object map
if (is_compressed) {
if (!UncompressAndPopulateCodeObject(image_, unique_isa_names, code_obj_map)) {
if (!UncompressAndPopulateCodeObject(managed_image_.getImage(), unique_isa_names,
code_obj_map)) {
return hipErrorInvalidImage;
}
// For compressed code objects, we use comgr to extract and make a copy.
// Track these to release later
std::for_each(code_obj_map.begin(), code_obj_map.end(),
[&](const auto& info) { code_obj_allocations_.insert(info.second.first); });
} else { // uncompressed code object
if (!PopulateCodeObjectMap(image_, unique_isa_names, code_obj_map)) {
if (!PopulateCodeObjectMap(managed_image_.getImage(), unique_isa_names, code_obj_map)) {
return hipErrorInvalidImage;
}
}
Expand Down Expand Up @@ -740,10 +706,9 @@ hipError_t FatBinaryInfo::AddDevProgram(hip::Device* device, const void* binary_
if (program == nullptr) {
return hipErrorOutOfMemory;
}
if (CL_SUCCESS !=
program->addDeviceProgram(*ctx->devices()[0], binary_image, binary_size, false, nullptr,
nullptr, (ufd_ != nullptr ? ufd_->fdesc_ : amd::Os::FDescInit()),
binary_offset, uri_)) {
if (CL_SUCCESS != program->addDeviceProgram(
*ctx->devices()[0], binary_image, binary_size, false, nullptr, nullptr,
managed_image_.getFileDescOrDefault(), binary_offset, uri_)) {
return hipErrorInvalidKernelFile;
}
return hipSuccess;
Expand Down Expand Up @@ -772,4 +737,34 @@ hipError_t FatBinaryInfo::BuildProgram(const int device_id) {
}
return hipSuccess;
}

FatBinaryInfo::ManagedImage::~ManagedImage() {
// If there is a descriptor, it means the file is mapped and needs to be unmapped.
if (ufd_ && !amd::Os::MemoryUnmapFile(image_, ufd_->fsize_))
guarantee(false, "Cannot unmap the file");
}

amd::Os::FileDesc FatBinaryInfo::ManagedImage::getFileDescOrDefault() const {
return ufd_ ? ufd_->fdesc_ : amd::Os::FDescInit();
}

hipError_t FatBinaryInfo::ManagedImage::map(const std::string& fname, size_t foffset) {
std::shared_ptr<ManagedUniqueFD> tempUfd;
hipError_t status = PlatformState::Instance().GetManagedImage(fname.c_str(), tempUfd);

if (status != hipSuccess) {
LogError("Failed to get managed image");
return status;
}

const void* image = nullptr;
if (!amd::Os::MemoryMapFileDesc(tempUfd->fdesc_, tempUfd->fsize_, foffset, &image)) {
LogError("Cannot map the file descriptor");
return hipErrorInvalidValue;
}

ufd_ = std::move(tempUfd);
image_ = image;
return hipSuccess;
}
} // namespace hip
30 changes: 23 additions & 7 deletions projects/clr/hipamd/src/hip_fatbin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <optional>

// Forward declaration for Unique FD
struct UniqueFD;
struct ManagedUniqueFD;

namespace hip {

Expand All @@ -34,6 +34,10 @@ class FatBinaryInfo {
explicit FatBinaryInfo(KpackParams kpack_params);
~FatBinaryInfo();

// Due self-managed ownerships, this class cannot be copy constructed or assigned.
FatBinaryInfo(const FatBinaryInfo&) = delete;
FatBinaryInfo& operator=(const FatBinaryInfo&) = delete;

hipError_t ExtractFatBinaryUsingCOMGR(const std::vector<hip::Device*>& devices);
hipError_t ExtractKpackBinary(const std::vector<hip::Device*>& devices);
hipError_t AddDevProgram(hip::Device* device, const void* binary_image, size_t binary_size,
Expand Down Expand Up @@ -68,14 +72,27 @@ class FatBinaryInfo {
std::recursive_mutex& FatBinaryLock() { return fb_lock_; }

private:
void ReleaseImageAndFile();

std::string fname_; //!< File name
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
// Helper class that ensures that mapped images get unmapped.
struct ManagedImage {
ManagedImage() {}
~ManagedImage();

ManagedImage(const ManagedImage&) = delete;
ManagedImage& operator=(const ManagedImage&) = delete;

amd::Os::FileDesc getFileDescOrDefault() const;

const void* getImage() const { return image_; }

hipError_t map(const std::string& fname, size_t foffset);

private:
std::shared_ptr<ManagedUniqueFD> ufd_ = nullptr; //!< Unique file descriptor
const void* image_ = nullptr; //!< image
} managed_image_; //!< Managed file descriptor and mapping for fat binary file

// Only used for FBs where image is directly passed
std::string uri_; //!< Uniform resource indicator
Expand All @@ -85,7 +102,6 @@ class FatBinaryInfo {

std::vector<amd::Program*> dev_programs_; //!< Program info per Device

std::shared_ptr<UniqueFD> ufd_; //!< Unique file descriptor
std::recursive_mutex fb_lock_; //!< Lock for the fat binary access
std::unordered_set<const void*> code_obj_allocations_; //!< Track allocations for code objects
};
Expand Down
57 changes: 36 additions & 21 deletions projects/clr/hipamd/src/hip_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ hipError_t ihipOccupancyMaxActiveBlocksPerMultiprocessor(
}
} // namespace hip_impl

// ================================================================================================
ManagedUniqueFD::~ManagedUniqueFD() {
hip::PlatformState::Instance().DropUniqueFileHandle(fpath_);
if (!amd::Os::CloseFileHandle(fdesc_)) guarantee(false, "Cannot close the file handle");
}

namespace hip {
constexpr unsigned __hipFatMAGIC2 = 0x48495046; // "HIPF"

Expand Down Expand Up @@ -998,38 +1004,47 @@ void PlatformState::PopExec(ihipExec_t& exec) {
}

// ================================================================================================
std::shared_ptr<UniqueFD> PlatformState::GetUniqueFileHandle(const std::string& file_path) {
hipError_t PlatformState::GetManagedImage(const std::string& file_path,
std::shared_ptr<ManagedUniqueFD>& out) {
std::scoped_lock lock(ufd_lock_);

std::shared_ptr<ManagedUniqueFD> ufd = nullptr;
auto it = ufd_map_.find(file_path);
if (it != ufd_map_.end()) {
return it->second;
// Try to lock the weak pointer to get a shared pointer. If it fails, it means the file was
// unmapped and the unique fd was destroyed and is on the way out, so we need to create a new
// one.
out = it->second.lock();
}

// Get the file desc and file size from amd::Os API
amd::Os::FileDesc fdesc;
size_t fsize = 0;
if (!amd::Os::GetFileHandle(file_path.c_str(), &fdesc, &fsize)) {
return nullptr;
if (out == nullptr) {
// Get the file desc and file size from amd::Os API
amd::Os::FileDesc fdesc;
size_t fsize = 0;
if (!amd::Os::GetFileHandle(file_path.c_str(), &fdesc, &fsize)) {
return hipErrorFileNotFound;
}

out = std::make_shared<ManagedUniqueFD>(file_path, fdesc, fsize);
ufd_map_.emplace(file_path, out);
}

auto ufd = std::make_shared<UniqueFD>(file_path, fdesc, fsize);
ufd_map_.emplace(file_path, ufd);
return ufd;

if (out == nullptr) {
return hipErrorFileNotFound;
}

// If the file name exists but the file size is 0, the something wrong with the file or its path
if (out->fsize_ == 0) {
return hipErrorInvalidImage;
}

return hipSuccess;
}

// ================================================================================================
bool PlatformState::CloseUniqueFileHandle(const std::shared_ptr<UniqueFD>& ufd) {
void PlatformState::DropUniqueFileHandle(const std::string& file_path) {
std::scoped_lock lock(ufd_lock_);

// if use_count is 2, then there is 1 entry in the map and the current entry is the last close.
if (ufd.use_count() == 2) {
ufd_map_.erase(ufd->fpath_);
if (!amd::Os::CloseFileHandle(ufd->fdesc_)) {
return false;
}
}
return true;
ufd_map_.erase(file_path);
}

// ================================================================================================
Expand Down
16 changes: 10 additions & 6 deletions projects/clr/hipamd/src/hip_platform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ hipError_t ihipOccupancyMaxActiveBlocksPerMultiprocessor(
hipFunction_t func, int inputBlockSize, size_t dynamicSMemSize, bool bCalcPotentialBlkSz);
} // namespace hip_impl

// Unique file descriptor class
struct UniqueFD {
UniqueFD(const std::string& fpath, amd::Os::FileDesc fdesc, size_t fsize)
// Unique file descriptor class that closes the file descriptor when destructed.
struct ManagedUniqueFD {
ManagedUniqueFD(const std::string& fpath, amd::Os::FileDesc fdesc, size_t fsize)
: fpath_(fpath), fdesc_(fdesc), fsize_(fsize) {}
~ManagedUniqueFD();

ManagedUniqueFD(const ManagedUniqueFD&) = delete;
ManagedUniqueFD& operator=(const ManagedUniqueFD&) = delete;

const std::string fpath_; //!< File path of this unique file
const amd::Os::FileDesc fdesc_; //!< File Descriptor
Expand Down Expand Up @@ -66,8 +70,8 @@ class PlatformState {
void ConfigureCall(dim3 gridDim, dim3 blockDim, size_t sharedMem, hipStream_t stream);
void PopExec(ihipExec_t& exec);

std::shared_ptr<UniqueFD> GetUniqueFileHandle(const std::string& file_path);
bool CloseUniqueFileHandle(const std::shared_ptr<UniqueFD>& ufd);
hipError_t GetManagedImage(const std::string& file_path, std::shared_ptr<ManagedUniqueFD>& out);
void DropUniqueFileHandle(const std::string& file_path);

// Logging lock accessor
std::recursive_mutex& GetLogLock() { return lg_lock_; }
Expand Down Expand Up @@ -116,7 +120,7 @@ class PlatformState {
//! Texture reference map: texRef -> (module, name)
std::unordered_map<textureReference*, std::pair<hipModule_t, std::string>> texRef_map_;
//! Unique File Descriptor Map
std::unordered_map<std::string, std::shared_ptr<UniqueFD>> ufd_map_;
std::unordered_map<std::string, std::weak_ptr<ManagedUniqueFD>> ufd_map_;
void* dynamicLibraryHandle_{nullptr}; //!< Handle to dynamic library
//! Library function map: kernel -> library
std::unordered_map<hipKernel_t, hipLibrary_t> library_functions_;
Expand Down
Loading