From 07e57a1f0df71d55b339fd68ddc6ab474c53e444 Mon Sep 17 00:00:00 2001 From: "Chaudhary, Jatin Jaikishan" Date: Mon, 14 Apr 2025 23:40:52 +0100 Subject: [PATCH] SWDEV-517941 - use device bitcode before spirv (#95) Also add flag: HIP_FORCE_SPIRV_CODEOBJECT to allow override to force use SPIRV. * use cache for already compiled code objects * address review comments and use the two spirv isa names --- hipamd/src/hip_fatbin.cpp | 108 +++++++++++++++++++++++--------------- rocclr/utils/flags.hpp | 2 + 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/hipamd/src/hip_fatbin.cpp b/hipamd/src/hip_fatbin.cpp index 65b92f93d9..4f374d11e8 100644 --- a/hipamd/src/hip_fatbin.cpp +++ b/hipamd/src/hip_fatbin.cpp @@ -317,9 +317,15 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vectordevices()[0]->isa().isaName(); unique_isa_names.insert({device_name, std::make_pair(0, 0)}); } - // Add the spirv target - const std::string spirv_isa_name = "spirv64-amd-amdhsa--amdgcnspirv"; - unique_isa_names.insert({spirv_isa_name, std::make_pair(0, 0)}); + + // there are two spirv targets, spirv64-amd-amdhsa--amdgcnspirv and + // spirv64-amd-amdhsa-unknown-amdgcnspirv. + // eventually we will remove spirv64-amd-amdhsa--amdgcnspirv + const std::vector spirv_isa_names = {"spirv64-amd-amdhsa--amdgcnspirv", + "spirv64-amd-amdhsa-unknown-amdgcnspirv"}; + for (const auto& spirv_isa_name : spirv_isa_names) { + unique_isa_names.insert({spirv_isa_name, std::make_pair(0, 0)}); + } // Create a query list using COMGR info for unique ISAs. std::vector query_list_array; @@ -347,45 +353,36 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vector(item.offset)); } - // if we have SPIRV isa, we will use Comgr to create isa for all devices. - auto spirv_isa_handle = unique_isa_names.find(spirv_isa_name); - bool spirv_isa_found = spirv_isa_handle->second.first != 0; - - if (!spirv_isa_found) { - for (auto device : devices) { - std::string device_name = device->devices()[0]->isa().isaName(); - auto dev_it = unique_isa_names.find(device_name); - // If the size is 0, then Comgr API could not find the CO for this GPU device/ISA - if (dev_it->second.first == 0) { - LogPrintfError("Cannot find CO in the bundle %s for ISA: %s", fname_.c_str(), - device_name.c_str()); - hip_status = hipErrorNoBinaryForGpu; - ListAllDeviceWithNoCOFromBundle(unique_isa_names); - break; - } - guarantee(unique_isa_names.cend() != dev_it, - "Cannot find the device name in the unique device name"); - fatbin_dev_info_[device->deviceId()] = new FatBinaryDeviceInfo( - reinterpret_cast
(const_cast(image_)) + dev_it->second.second, - dev_it->second.first, dev_it->second.second); - fatbin_dev_info_[device->deviceId()]->program_ = new amd::Program(*(device->asContext())); + bool spirv_isa_found = false; + decltype(unique_isa_names.begin()) spirv_isa_handle; + for (const auto& spirv_isa_name : spirv_isa_names) { + auto iter = unique_isa_names.find(spirv_isa_name); + if (iter->second.first != 0) { + spirv_isa_found = true; + spirv_isa_handle = iter; } - } else { - LogPrintfDebug("%s", "SPIRV isa found"); + } - comgr_helper::ComgrDataSetUniqueHandle spirv_data_set, bc_data_set; + bool compile_spv_bitcode_res = false; + std::once_flag spirv_to_bc_flag; + + comgr_helper::ComgrDataSetUniqueHandle bc_data_set; + std::unordered_map> compiled_co; // code object cache + + auto compile_spv_bitcode = [&]() { + comgr_helper::ComgrDataSetUniqueHandle spirv_data_set; comgr_helper::ComgrDataUniqueHandle spirv_data; comgr_helper::ComgrActionInfoUniqueHandle action; if (comgr_status = spirv_data_set.Create(); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to create SPIRV Data set"); - break; + return; } if (comgr_status = spirv_data.Create(AMD_COMGR_DATA_KIND_SPIRV); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to create SPIRV Data"); - break; + return; } if (comgr_status = @@ -394,43 +391,64 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vectorsecond.second /* buffer */); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to assign data in comgr"); - break; + return; } if (comgr_status = amd::Comgr::set_data_name(spirv_data.get(), "hip_code_object.spv"); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to set data name"); - break; + return; } if (comgr_status = amd::Comgr::data_set_add(spirv_data_set.get(), spirv_data.get()); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to add spir data"); - break; + return; } if (comgr_status = action.Create(); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to create action"); - break; + return; } if (comgr_status = bc_data_set.Create(); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to create bitcode data set"); - break; + return; } if (comgr_status = amd::Comgr::do_action(AMD_COMGR_ACTION_TRANSLATE_SPIRV_TO_BC, action.get(), spirv_data_set.get(), bc_data_set.get()); comgr_status != AMD_COMGR_STATUS_SUCCESS) { LogError("Failed to compile to ll"); - break; + return; } + compile_spv_bitcode_res = true; + }; - // System might report multiple devices of same name, we do not want to recompile for all - // these. store code objects after compiling them to reuse. - std::unordered_map> compiled_co; + LogPrintfInfo("Searching for code objects, HIP_FORCE_SPIRV_CODEOBJECT: %d", + HIP_FORCE_SPIRV_CODEOBJECT); + + for (auto device : devices) { + std::string device_name = device->devices()[0]->isa().isaName(); + auto dev_it = unique_isa_names.find(device_name); + // If the size is not 0, that means we found the native isa code object + if (dev_it->second.first != 0 && !HIP_FORCE_SPIRV_CODEOBJECT) { + LogPrintfInfo("Using Native code object: %s", device->devices()[0]->isa().targetId()); + guarantee(unique_isa_names.cend() != dev_it, + "Cannot find the device name in the unique device name"); + fatbin_dev_info_[device->deviceId()] = new FatBinaryDeviceInfo( + reinterpret_cast
(const_cast(image_)) + dev_it->second.second, + dev_it->second.first, dev_it->second.second); + fatbin_dev_info_[device->deviceId()]->program_ = new amd::Program(*(device->asContext())); + } else if (spirv_isa_found) { + // Compile to bitcode once + std::call_once(spirv_to_bc_flag, compile_spv_bitcode); + + if(!compile_spv_bitcode_res) { + hip_status = hipErrorInvalidValue; + break; + } - for (auto device : devices) { std::string target_id = device->devices()[0]->isa().targetId(); if (auto code_iter = compiled_co.find(target_id); code_iter != compiled_co.end()) { // We have already compiled for it, lets reuse the code object @@ -451,7 +469,6 @@ hipError_t FatBinaryInfo::ExtractFatBinaryUsingCOMGR(const std::vectordeviceId()] = new FatBinaryDeviceInfo(co, elf_size, 0); fatbin_dev_info_[device->deviceId()]->program_ = new amd::Program(*(device->asContext())); + // Save the compiled code object compiled_co[target_id] = std::make_pair(co, elf_size); + } else { + // We found neither a compatible code object nor SPIRV + LogPrintfError( + "No compatible code objects found for: %s, value of HIP_FORCE_SPIRV_CODEOBJECT: %d", + device->devices()[0]->isa().targetId(), HIP_FORCE_SPIRV_CODEOBJECT); + hip_status = hipErrorInvalidValue; + break; } } } while (0); if (comgr_status != AMD_COMGR_STATUS_SUCCESS) { + LogError("comgr API call failed"); hip_status = hipErrorInvalidValue; } diff --git a/rocclr/utils/flags.hpp b/rocclr/utils/flags.hpp index 24903a48fa..e04ebc6d0b 100644 --- a/rocclr/utils/flags.hpp +++ b/rocclr/utils/flags.hpp @@ -278,6 +278,8 @@ release(bool, DEBUG_HIP_DYNAMIC_QUEUES, true, \ release(uint, DEBUG_HIP_7_PREVIEW, 0, \ "Enables specific backward incompatible changes support before 7.0," \ "using the mask. By default the changes are disabled and is set to 0")\ +release(bool, HIP_FORCE_SPIRV_CODEOBJECT, false, \ + "Force use of SPIRV instead of device specific code object.") \ namespace amd {