[clang] f6ace23 - [amdgpu-arch] Dynamically load the HSA runtime if not found during the build

Joseph Huber via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 16 11:13:55 PST 2023


Author: Joseph Huber
Date: 2023-01-16T13:13:45-06:00
New Revision: f6ace23172e5930be0e7cc602f50e1e9c54d7a9a

URL: https://github.com/llvm/llvm-project/commit/f6ace23172e5930be0e7cc602f50e1e9c54d7a9a
DIFF: https://github.com/llvm/llvm-project/commit/f6ace23172e5930be0e7cc602f50e1e9c54d7a9a.diff

LOG: [amdgpu-arch] Dynamically load the HSA runtime if not found during the build

We use the `amdgpu-arch` tool to query the installed GPUs at runtime.
One problem is that this tool is currently not build if the person
building the LLVM binary does not have the HSA runtime on their system.
This means that if someone built and distrubted an installation of LLVM
without HSA, then the user will not be able to use it even if they have
it on their system.

This patch makes us build this tool unconditionally and adds extra logic
to dynamically load HSA if it's present.

Reviewed By: JonChesterfield

Differential Revision: https://reviews.llvm.org/D141859

Added: 
    

Modified: 
    clang/tools/amdgpu-arch/AMDGPUArch.cpp
    clang/tools/amdgpu-arch/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/tools/amdgpu-arch/AMDGPUArch.cpp b/clang/tools/amdgpu-arch/AMDGPUArch.cpp
index 8398f6e81a229..caf8562c4e9dc 100644
--- a/clang/tools/amdgpu-arch/AMDGPUArch.cpp
+++ b/clang/tools/amdgpu-arch/AMDGPUArch.cpp
@@ -11,6 +11,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include <memory>
+#include <string>
+#include <vector>
+
 #if defined(__has_include)
 #if __has_include("hsa/hsa.h")
 #define HSA_HEADER_FOUND 1
@@ -26,11 +32,62 @@
 #endif
 
 #if !HSA_HEADER_FOUND
-int main() { return 1; }
-#else
+// Forward declaration of the status enumeration used by HSA.
+typedef enum {
+  HSA_STATUS_SUCCESS = 0x0,
+} hsa_status_t;
 
-#include <string>
-#include <vector>
+// Forward declaration of the device types used by HSA.
+typedef enum {
+  HSA_DEVICE_TYPE_CPU = 0,
+  HSA_DEVICE_TYPE_GPU = 1,
+} hsa_device_type_t;
+
+// Forward declaration of the agent information types we use.
+typedef enum {
+  HSA_AGENT_INFO_NAME = 0,
+  HSA_AGENT_INFO_DEVICE = 17,
+} hsa_agent_info_t;
+
+typedef struct hsa_agent_s {
+  uint64_t handle;
+} hsa_agent_t;
+
+hsa_status_t (*hsa_init)();
+hsa_status_t (*hsa_shut_down)();
+hsa_status_t (*hsa_agent_get_info)(hsa_agent_t, hsa_agent_info_t, void *);
+hsa_status_t (*hsa_iterate_agents)(hsa_status_t (*callback)(hsa_agent_t,
+                                                            void *),
+                                   void *);
+
+constexpr const char *DynamicHSAPath = "libhsa-runtime64.so";
+
+llvm::Error loadHSA() {
+  std::string ErrMsg;
+  auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
+      llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicHSAPath, &ErrMsg));
+  if (!DynlibHandle->isValid()) {
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "Failed to 'dlopen' %s\n", DynamicHSAPath);
+  }
+#define DYNAMIC_INIT(SYMBOL)                                                   \
+  {                                                                            \
+    void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL);               \
+    if (!SymbolPtr)                                                            \
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),           \
+                                     "Failed to 'dlsym' " #SYMBOL);            \
+    SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr);                    \
+  }
+  DYNAMIC_INIT(hsa_init);
+  DYNAMIC_INIT(hsa_shut_down);
+  DYNAMIC_INIT(hsa_agent_get_info);
+  DYNAMIC_INIT(hsa_iterate_agents);
+#undef DYNAMIC_INIT
+  return llvm::Error::success();
+}
+#else
+llvm::Error loadHSA() { return llvm::Error::success(); }
+#endif
 
 static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) {
   hsa_device_type_t DeviceType;
@@ -53,7 +110,13 @@ static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) {
   return HSA_STATUS_SUCCESS;
 }
 
-int main() {
+int main(int argc, char *argv[]) {
+  // Attempt to load the HSA runtime.
+  if (llvm::Error Err = loadHSA()) {
+    logAllUnhandledErrors(std::move(Err), llvm::errs());
+    return 1;
+  }
+
   hsa_status_t Status = hsa_init();
   if (Status != HSA_STATUS_SUCCESS) {
     return 1;
@@ -74,5 +137,3 @@ int main() {
   hsa_shut_down();
   return 0;
 }
-
-#endif

diff  --git a/clang/tools/amdgpu-arch/CMakeLists.txt b/clang/tools/amdgpu-arch/CMakeLists.txt
index caead440c5ccf..a5361e65758b1 100644
--- a/clang/tools/amdgpu-arch/CMakeLists.txt
+++ b/clang/tools/amdgpu-arch/CMakeLists.txt
@@ -6,14 +6,13 @@
 # //
 # //===----------------------------------------------------------------------===//
 
-find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
-if (NOT ${hsa-runtime64_FOUND})
-  message(STATUS "Not building amdgpu-arch: hsa-runtime64 not found")
-  return()
-endif()
+set(LLVM_LINK_COMPONENTS Support)
 
 add_clang_tool(amdgpu-arch AMDGPUArch.cpp)
 
-set_target_properties(amdgpu-arch PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON)
-
-clang_target_link_libraries(amdgpu-arch PRIVATE hsa-runtime64::hsa-runtime64)
+# If we find the HSA runtime we link with it directly.
+find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
+if (${hsa-runtime64_FOUND})
+  set_target_properties(amdgpu-arch PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON)
+  clang_target_link_libraries(amdgpu-arch PRIVATE hsa-runtime64::hsa-runtime64)
+endif()


        


More information about the cfe-commits mailing list