[clang] 661d91a - [clang] Make amdgpu-arch tool work on Windows

Yaxun Liu via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 7 21:32:33 PDT 2023


Author: Yaxun (Sam) Liu
Date: 2023-07-08T00:01:02-04:00
New Revision: 661d91a0fd4ad80ecc49ebb9e0fff01b4de2ce1c

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

LOG: [clang] Make amdgpu-arch tool work on Windows

Currently amdgpu-arch tool detects AMD GPU by dynamically
loading HSA runtime shared library and using HSA API's,
which is not available on Windows.

This patch makes it work on Windows by dynamically loading
HIP runtime dll and using HIP API's.

Reviewed by: Matt Arsenault, Joseph Huber, Johannes Doerfert

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

Added: 
    clang/tools/amdgpu-arch/AMDGPUArchByHIP.cpp
    clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp

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 17d188adc3b7d9..7ae57b7877e1fe 100644
--- a/clang/tools/amdgpu-arch/AMDGPUArch.cpp
+++ b/clang/tools/amdgpu-arch/AMDGPUArch.cpp
@@ -6,18 +6,13 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements a tool for detecting name of AMDGPU installed in system
-// using HSA. This tool is used by AMDGPU OpenMP driver.
+// This file implements a tool for detecting name of AMDGPU installed in system.
+// This tool is used by AMDGPU OpenMP and HIP driver.
 //
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/Version.h"
 #include "llvm/Support/CommandLine.h"
-#include "llvm/Support/DynamicLibrary.h"
-#include "llvm/Support/Error.h"
-#include <memory>
-#include <string>
-#include <vector>
 
 using namespace llvm;
 
@@ -30,76 +25,8 @@ static void PrintVersion(raw_ostream &OS) {
   OS << clang::getClangToolFullVersion("amdgpu-arch") << '\n';
 }
 
-typedef enum {
-  HSA_STATUS_SUCCESS = 0x0,
-} hsa_status_t;
-
-typedef enum {
-  HSA_DEVICE_TYPE_CPU = 0,
-  HSA_DEVICE_TYPE_GPU = 1,
-} hsa_device_type_t;
-
-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 (*)(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", 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();
-}
-
-static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) {
-  hsa_device_type_t DeviceType;
-  hsa_status_t Status =
-      hsa_agent_get_info(Agent, HSA_AGENT_INFO_DEVICE, &DeviceType);
-
-  // continue only if device type if GPU
-  if (Status != HSA_STATUS_SUCCESS || DeviceType != HSA_DEVICE_TYPE_GPU) {
-    return Status;
-  }
-
-  std::vector<std::string> *GPUs =
-      static_cast<std::vector<std::string> *>(Data);
-  char GPUName[64];
-  Status = hsa_agent_get_info(Agent, HSA_AGENT_INFO_NAME, GPUName);
-  if (Status != HSA_STATUS_SUCCESS) {
-    return Status;
-  }
-  GPUs->push_back(GPUName);
-  return HSA_STATUS_SUCCESS;
-}
+int printGPUsByHSA();
+int printGPUsByHIP();
 
 int main(int argc, char *argv[]) {
   cl::HideUnrelatedOptions(AMDGPUArchCategory);
@@ -117,29 +44,10 @@ int main(int argc, char *argv[]) {
     return 0;
   }
 
-  // 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;
-  }
-
-  std::vector<std::string> GPUs;
-  Status = hsa_iterate_agents(iterateAgentsCallback, &GPUs);
-  if (Status != HSA_STATUS_SUCCESS) {
-    return 1;
-  }
-
-  for (const auto &GPU : GPUs)
-    printf("%s\n", GPU.c_str());
-
-  if (GPUs.size() < 1)
-    return 1;
+#ifndef _WIN32
+  if (!printGPUsByHSA())
+    return 0;
+#endif
 
-  hsa_shut_down();
-  return 0;
+  return printGPUsByHIP();
 }

diff  --git a/clang/tools/amdgpu-arch/AMDGPUArchByHIP.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByHIP.cpp
new file mode 100644
index 00000000000000..7c9071be09188d
--- /dev/null
+++ b/clang/tools/amdgpu-arch/AMDGPUArchByHIP.cpp
@@ -0,0 +1,96 @@
+//===- AMDGPUArch.cpp - list AMDGPU installed ----------*- C++ -*---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a tool for detecting name of AMDGPU installed in system
+// using HIP runtime. This tool is used by AMDGPU OpenMP and HIP driver.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+typedef struct {
+  char padding[396];
+  char gcnArchName[256];
+  char padding2[1024];
+} hipDeviceProp_t;
+
+typedef enum {
+  hipSuccess = 0,
+} hipError_t;
+
+typedef hipError_t (*hipGetDeviceCount_t)(int *);
+typedef hipError_t (*hipDeviceGet_t)(int *, int);
+typedef hipError_t (*hipGetDeviceProperties_t)(hipDeviceProp_t *, int);
+
+int printGPUsByHIP() {
+#ifdef _WIN32
+  constexpr const char *DynamicHIPPath = "amdhip64.dll";
+#else
+  constexpr const char *DynamicHIPPath = "libamdhip64.so";
+#endif
+
+  std::string ErrMsg;
+  auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
+      llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicHIPPath, &ErrMsg));
+  if (!DynlibHandle->isValid()) {
+    llvm::errs() << "Failed to load " << DynamicHIPPath << ": " << ErrMsg
+                 << '\n';
+    return 1;
+  }
+
+#define DYNAMIC_INIT_HIP(SYMBOL)                                               \
+  {                                                                            \
+    void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL);               \
+    if (!SymbolPtr) {                                                          \
+      llvm::errs() << "Failed to find symbol " << #SYMBOL << '\n';             \
+      return 1;                                                                \
+    }                                                                          \
+    SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr);                    \
+  }
+
+  hipGetDeviceCount_t hipGetDeviceCount;
+  hipDeviceGet_t hipDeviceGet;
+  hipGetDeviceProperties_t hipGetDeviceProperties;
+
+  DYNAMIC_INIT_HIP(hipGetDeviceCount);
+  DYNAMIC_INIT_HIP(hipDeviceGet);
+  DYNAMIC_INIT_HIP(hipGetDeviceProperties);
+
+#undef DYNAMIC_INIT_HIP
+
+  int deviceCount;
+  hipError_t err = hipGetDeviceCount(&deviceCount);
+  if (err != hipSuccess) {
+    llvm::errs() << "Failed to get device count\n";
+    return 1;
+  }
+
+  for (int i = 0; i < deviceCount; ++i) {
+    int deviceId;
+    err = hipDeviceGet(&deviceId, i);
+    if (err != hipSuccess) {
+      llvm::errs() << "Failed to get device id for ordinal " << i << '\n';
+      return 1;
+    }
+
+    hipDeviceProp_t prop;
+    err = hipGetDeviceProperties(&prop, deviceId);
+    if (err != hipSuccess) {
+      llvm::errs() << "Failed to get device properties for device " << deviceId
+                   << '\n';
+      return 1;
+    }
+    llvm::outs() << prop.gcnArchName << '\n';
+  }
+
+  return 0;
+}

diff  --git a/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp
new file mode 100644
index 00000000000000..f82a4890f46551
--- /dev/null
+++ b/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp
@@ -0,0 +1,122 @@
+//===- AMDGPUArchLinux.cpp - list AMDGPU installed ------*- C++ -*---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a tool for detecting name of AMDGPU installed in system
+// using HSA on Linux. This tool is used by AMDGPU OpenMP and HIP driver.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+typedef enum {
+  HSA_STATUS_SUCCESS = 0x0,
+} hsa_status_t;
+
+typedef enum {
+  HSA_DEVICE_TYPE_CPU = 0,
+  HSA_DEVICE_TYPE_GPU = 1,
+} hsa_device_type_t;
+
+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 (*)(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", 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();
+}
+
+static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) {
+  hsa_device_type_t DeviceType;
+  hsa_status_t Status =
+      hsa_agent_get_info(Agent, HSA_AGENT_INFO_DEVICE, &DeviceType);
+
+  // continue only if device type if GPU
+  if (Status != HSA_STATUS_SUCCESS || DeviceType != HSA_DEVICE_TYPE_GPU) {
+    return Status;
+  }
+
+  std::vector<std::string> *GPUs =
+      static_cast<std::vector<std::string> *>(Data);
+  char GPUName[64];
+  Status = hsa_agent_get_info(Agent, HSA_AGENT_INFO_NAME, GPUName);
+  if (Status != HSA_STATUS_SUCCESS) {
+    return Status;
+  }
+  GPUs->push_back(GPUName);
+  return HSA_STATUS_SUCCESS;
+}
+
+int printGPUsByHSA() {
+  // 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;
+  }
+
+  std::vector<std::string> GPUs;
+  Status = hsa_iterate_agents(iterateAgentsCallback, &GPUs);
+  if (Status != HSA_STATUS_SUCCESS) {
+    return 1;
+  }
+
+  for (const auto &GPU : GPUs)
+    llvm::outs() << GPU << '\n';
+
+  if (GPUs.size() < 1)
+    return 1;
+
+  hsa_shut_down();
+  return 0;
+}

diff  --git a/clang/tools/amdgpu-arch/CMakeLists.txt b/clang/tools/amdgpu-arch/CMakeLists.txt
index 6363eda49abe08..1657c701251308 100644
--- a/clang/tools/amdgpu-arch/CMakeLists.txt
+++ b/clang/tools/amdgpu-arch/CMakeLists.txt
@@ -8,6 +8,6 @@
 
 set(LLVM_LINK_COMPONENTS Support)
 
-add_clang_tool(amdgpu-arch AMDGPUArch.cpp)
+add_clang_tool(amdgpu-arch AMDGPUArch.cpp AMDGPUArchByHSA.cpp AMDGPUArchByHIP.cpp)
 
 target_link_libraries(amdgpu-arch PRIVATE clangBasic)


        


More information about the cfe-commits mailing list