[clang] [amdgpu-arch] Replace use of HSA with reading sysfs directly (PR #116651)
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 18 08:55:15 PST 2024
https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/116651
>From c95e80939c8189def053556a232ba611d6dc02cc Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 18 Nov 2024 10:34:23 -0600
Subject: [PATCH 1/2] [amdgpu-arch] Replcae use of HSA with reading sysfs
directly
Summary:
For Linux systems, we currently use the HSA library to determine the
installed GPUs. However, this isn't really necessary and adds a
dependency on the HSA runtime as well as a lot of overhead. Instead,
this patch uses the `sysfs` interface exposed by `amdkfd` to do this
directly.
---
clang/tools/amdgpu-arch/AMDGPUArch.cpp | 4 +-
clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp | 122 --------------------
clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp | 74 ++++++++++++
clang/tools/amdgpu-arch/CMakeLists.txt | 2 +-
4 files changed, 77 insertions(+), 125 deletions(-)
delete mode 100644 clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp
create mode 100644 clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp
diff --git a/clang/tools/amdgpu-arch/AMDGPUArch.cpp b/clang/tools/amdgpu-arch/AMDGPUArch.cpp
index 7ae57b7877e1fe..6c10cbc5c46a83 100644
--- a/clang/tools/amdgpu-arch/AMDGPUArch.cpp
+++ b/clang/tools/amdgpu-arch/AMDGPUArch.cpp
@@ -25,7 +25,7 @@ static void PrintVersion(raw_ostream &OS) {
OS << clang::getClangToolFullVersion("amdgpu-arch") << '\n';
}
-int printGPUsByHSA();
+int printGPUsByKFD();
int printGPUsByHIP();
int main(int argc, char *argv[]) {
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
}
#ifndef _WIN32
- if (!printGPUsByHSA())
+ if (!printGPUsByKFD())
return 0;
#endif
diff --git a/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp
deleted file mode 100644
index 432f2c414ed244..00000000000000
--- a/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-//===- AMDGPUArchByHSA.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/AMDGPUArchByKFD.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp
new file mode 100644
index 00000000000000..c7590572de63d4
--- /dev/null
+++ b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp
@@ -0,0 +1,74 @@
+//===- AMDGPUArchByKFD.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 AMD GPUs installed in
+// system using the Linux sysfs interface for the AMD KFD driver.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <memory>
+#include <string>
+
+using namespace llvm;
+
+constexpr const char *KFD_SYSFS_NODE_PATH =
+ "/sys/devices/virtual/kfd/kfd/topology/nodes";
+
+constexpr static long getMajor(long Ver) { return (Ver / 10000) % 100; }
+constexpr static long getMinor(long Ver) { return (Ver / 100) % 100; }
+constexpr static long getStep(long Ver) { return Ver % 100; }
+
+int printGPUsByKFD() {
+ SmallVector<std::pair<long, long>> Devices;
+ std::error_code EC;
+ for (sys::fs::directory_iterator Begin(KFD_SYSFS_NODE_PATH, EC), End;
+ Begin != End; Begin.increment(EC)) {
+ if (EC)
+ return 1;
+
+ long Node = 0;
+ if (sys::path::stem(Begin->path()).consumeInteger(10, Node))
+ return 1;
+
+ SmallVector<char> Path(Begin->path().begin(), Begin->path().end());
+ sys::path::append(Path, "properties");
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
+ MemoryBuffer::getFileOrSTDIN(Path);
+ if (std::error_code EC = BufferOrErr.getError())
+ return 1;
+
+ long GFXVersion = 0;
+ for (line_iterator Lines(**BufferOrErr, false); !Lines.is_at_end();
+ ++Lines) {
+ if (Lines->starts_with("gfx_target_version")) {
+ if (Lines->drop_front(sizeof("gfx_target_version"))
+ .consumeInteger(10, GFXVersion))
+ return 1;
+ break;
+ }
+ }
+
+ // If this is zero the node is a CPU.
+ if (GFXVersion == 0)
+ continue;
+ Devices.emplace_back(Node, GFXVersion);
+ }
+
+ // Sort the devices by their node to make sure it prints in order.
+ llvm::sort(Devices, [](auto &L, auto &R) { return L.first < R.first; });
+ for (const auto &[Node, GFXVersion] : Devices)
+ std::fprintf(stdout, "gfx%ld%ld%lx\n", getMajor(GFXVersion),
+ getMinor(GFXVersion), getStep(GFXVersion));
+
+ return 0;
+}
diff --git a/clang/tools/amdgpu-arch/CMakeLists.txt b/clang/tools/amdgpu-arch/CMakeLists.txt
index 1657c701251308..c4c8de614565a7 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 AMDGPUArchByHSA.cpp AMDGPUArchByHIP.cpp)
+add_clang_tool(amdgpu-arch AMDGPUArch.cpp AMDGPUArchByKFD.cpp AMDGPUArchByHIP.cpp)
target_link_libraries(amdgpu-arch PRIVATE clangBasic)
>From 8798de263a6d84649241dc23bff9015a8998e975 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 18 Nov 2024 10:55:04 -0600
Subject: [PATCH 2/2] comments
---
clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp
index c7590572de63d4..03ad1ba370e42c 100644
--- a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp
+++ b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp
@@ -20,9 +20,11 @@
using namespace llvm;
-constexpr const char *KFD_SYSFS_NODE_PATH =
+constexpr static const char *KFD_SYSFS_NODE_PATH =
"/sys/devices/virtual/kfd/kfd/topology/nodes";
+// See the ROCm implementation for how this is handled.
+// https://github.com/ROCm/ROCT-Thunk-Interface/blob/master/src/libhsakmt.h#L126
constexpr static long getMajor(long Ver) { return (Ver / 10000) % 100; }
constexpr static long getMinor(long Ver) { return (Ver / 100) % 100; }
constexpr static long getStep(long Ver) { return Ver % 100; }
@@ -50,9 +52,9 @@ int printGPUsByKFD() {
long GFXVersion = 0;
for (line_iterator Lines(**BufferOrErr, false); !Lines.is_at_end();
++Lines) {
- if (Lines->starts_with("gfx_target_version")) {
- if (Lines->drop_front(sizeof("gfx_target_version"))
- .consumeInteger(10, GFXVersion))
+ StringRef Line(*Lines);
+ if (Line.consume_front("gfx_target_version")) {
+ if (Line.consumeInteger(10, GFXVersion))
return 1;
break;
}
More information about the cfe-commits
mailing list