diff --git a/runtime/hsa-runtime/core/runtime/runtime.cpp b/runtime/hsa-runtime/core/runtime/runtime.cpp index 9fce3dee69..6e3cc13839 100644 --- a/runtime/hsa-runtime/core/runtime/runtime.cpp +++ b/runtime/hsa-runtime/core/runtime/runtime.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include "core/common/shared.h" #include "core/inc/hsa_ext_interface.h" @@ -1493,53 +1494,118 @@ void Runtime::LoadTools() { typedef Agent* (*tool_wrap_t)(Agent*); typedef void (*tool_add_t)(Runtime*); - // Load tool libs + std::vector failed; + + //Get loaded libs and filter to tool libraries. + struct lib_t { + lib_t(os::LibHandle lib, uint32_t order, std::string name) : lib_(lib), order_(order), name_(name) {} + os::LibHandle lib_; + uint32_t order_; + std::string name_; + }; + + std::list sorted; + uint32_t env_count=0; + + // Load env var tool lib names and determine ordering offset. std::string tool_names = flag_.tools_lib_names(); + std::vector names; if (tool_names != "") { - std::vector names = parse_tool_names(tool_names); - std::vector failed; - for (auto& name : names) { - os::LibHandle tool = os::LoadLib(name); + names = parse_tool_names(tool_names); + env_count = names.size(); + } - if (tool != NULL) { - tool_libs_.push_back(tool); + // Discover loaded tools. + std::vector loaded = os::GetLoadedLibs(); + for(auto& handle : loaded) { + const uint32_t* order = (const uint32_t*)os::GetExportAddress(handle, "HSA_AMD_TOOL_PRIORITY"); + if(order) { + sorted.push_back(lib_t(handle, *order+env_count, os::GetLibraryName(handle))); + } else { + os::CloseLib(handle); + } + } + + // Load env var tools. + env_count=0; + for (auto& name : names) { + os::LibHandle tool = os::LoadLib(name); - rocr::AMD::callback_t ld = (tool_init_t)os::GetExportAddress(tool, "OnLoad"); - if (ld) { - if (!ld(&hsa_api_table_.hsa_api, - hsa_api_table_.hsa_api.version.major_id, - failed.size(), &failed[0])) { - failed.push_back(name.c_str()); - os::CloseLib(tool); - continue; - } - } + if (tool != nullptr) { + sorted.push_back(lib_t(tool, env_count, name)); + env_count++; + } else { + failed.push_back(name.c_str()); + if (flag().report_tool_load_failures()) + fprintf(stderr, "Tool lib \"%s\" failed to load.\n", name.c_str()); + } + } - rocr::AMD::callback_t wrap = - (tool_wrap_t)os::GetExportAddress(tool, "WrapAgent"); - if (wrap) { - std::vector* agent_lists[2] = {&cpu_agents_, - &gpu_agents_}; - for (std::vector* agent_list : agent_lists) { - for (size_t agent_idx = 0; agent_idx < agent_list->size(); - ++agent_idx) { + if(!sorted.empty()) { + // Close duplicate handles + sorted.sort([](const lib_t& lhs, const lib_t& rhs) { + if(lhs.lib_ == rhs.lib_) + return lhs.order_ < rhs.order_; + return lhs.lib_ < rhs.lib_; + }); + + os::LibHandle current = sorted.front().lib_; + auto it = sorted.begin(); + it++; + while(it != sorted.end()) { + if(it->lib_==current) { + os::CloseLib(current); + auto rem = it; + it = sorted.erase(rem); + } else { + current = it->lib_; + it++; + } + } + + // Sort to load order + sorted.sort([](const lib_t& lhs, const lib_t& rhs) { + return lhs.order_ < rhs.order_; + }); + + for(auto& lib : sorted) { + auto& tool = lib.lib_; + + rocr::AMD::callback_t ld = (tool_init_t)os::GetExportAddress(tool, "OnLoad"); + if (!ld) { + failed.push_back(lib.name_.c_str()); + os::CloseLib(tool); + continue; + } + if (!ld(&hsa_api_table_.hsa_api, + hsa_api_table_.hsa_api.version.major_id, + failed.size(), &failed[0])) { + failed.push_back(lib.name_.c_str()); + os::CloseLib(tool); + continue; + } + tool_libs_.push_back(tool); + + rocr::AMD::callback_t wrap = + (tool_wrap_t)os::GetExportAddress(tool, "WrapAgent"); + if (wrap) { + std::vector* agent_lists[2] = {&cpu_agents_, + &gpu_agents_}; + for (std::vector* agent_list : agent_lists) { + for (size_t agent_idx = 0; agent_idx < agent_list->size(); + ++agent_idx) { Agent* agent = wrap(agent_list->at(agent_idx)); if (agent != NULL) { assert(agent->IsValid() && - "Agent returned from WrapAgent is not valid"); + "Agent returned from WrapAgent is not valid"); agent_list->at(agent_idx) = agent; } - } } } + } - rocr::AMD::callback_t add = (tool_add_t)os::GetExportAddress(tool, "AddAgent"); - if (add) add(this); - } - else { - if (flag().report_tool_load_failures()) - fprintf(stderr, "Tool lib \"%s\" failed to load.\n", name.c_str()); - } + rocr::AMD::callback_t add = (tool_add_t)os::GetExportAddress(tool, "AddAgent"); + if (add) add(this); } } } diff --git a/runtime/hsa-runtime/core/util/lnx/os_linux.cpp b/runtime/hsa-runtime/core/util/lnx/os_linux.cpp index 6b48fd39fb..14cbdea69e 100644 --- a/runtime/hsa-runtime/core/util/lnx/os_linux.cpp +++ b/runtime/hsa-runtime/core/util/lnx/os_linux.cpp @@ -200,6 +200,35 @@ void* GetExportAddress(LibHandle lib, std::string export_name) { void CloseLib(LibHandle lib) { dlclose(*(void**)&lib); } +std::vector GetLoadedLibs() { + + std::vector ret; + std::vector names; + auto callback = [&](dl_phdr_info* info) { + if(info->dlpi_name[0] != '\0') + names.push_back(info->dlpi_name); + }; + typedef decltype(callback) call_t; + + dl_iterate_phdr([](dl_phdr_info* info, size_t size, void* data){ + auto& call = *(call_t*)data; + call(info); + return 0; + }, &callback); + + for(auto& name : names) + ret.push_back(LoadLib(name)); + + return ret; +} + +std::string GetLibraryName(LibHandle lib) { + link_map *map; + if(dlinfo(lib, RTLD_DI_LINKMAP, &map)!=0) + return ""; + return map->l_name; +} + Mutex CreateMutex() { pthread_mutex_t* mutex = new pthread_mutex_t; pthread_mutex_init(mutex, NULL); diff --git a/runtime/hsa-runtime/core/util/os.h b/runtime/hsa-runtime/core/util/os.h index 21f6687ffa..aa0c8d565f 100644 --- a/runtime/hsa-runtime/core/util/os.h +++ b/runtime/hsa-runtime/core/util/os.h @@ -46,6 +46,7 @@ #define HSA_RUNTIME_CORE_UTIL_OS_H_ #include +#include #include "utils.h" namespace rocr { @@ -85,6 +86,15 @@ void* GetExportAddress(LibHandle lib, std::string export_name); /// @param: lib(Input), library handle which will be unloaded. void CloseLib(LibHandle lib); +/// @brief: Lists libraries in the process +/// @return: List of library handles +std::vector GetLoadedLibs(); + +/// @brief: Returns the library's path name. +/// @param: lib(Input), libray handle +/// @return: Path name of library +std::string GetLibraryName(LibHandle lib); + /// @brief: Creates a mutex, will return NULL if failed. /// @param: void. /// @return: Mutex. diff --git a/runtime/hsa-runtime/core/util/win/os_win.cpp b/runtime/hsa-runtime/core/util/win/os_win.cpp index f42f05fc85..f5fb05840c 100644 --- a/runtime/hsa-runtime/core/util/win/os_win.cpp +++ b/runtime/hsa-runtime/core/util/win/os_win.cpp @@ -82,6 +82,15 @@ void* GetExportAddress(LibHandle lib, std::string export_name) { void CloseLib(LibHandle lib) { FreeLibrary(*(::HMODULE*)&lib); } +std::vector GetLoadedLibs() { + // Use EnumProcessModulesEx + static_assert(false, "Not implemented."); +} + +std::string GetLibraryName(LibHandle lib) { + static_assert(false, "Not implemented."); +} + Mutex CreateMutex() { return CreateEvent(NULL, false, true, NULL); } bool TryAcquireMutex(Mutex lock) {