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 <hube...@outlook.com> Date: Mon, 18 Nov 2024 10:34:23 -0600 Subject: [PATCH 1/5] [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 <hube...@outlook.com> Date: Mon, 18 Nov 2024 10:55:04 -0600 Subject: [PATCH 2/5] 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; } >From c76343f5bece24262267ac464b1a40898ddd685c Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Mon, 18 Nov 2024 11:44:06 -0600 Subject: [PATCH 3/5] Fix whitespace --- clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp index 03ad1ba370e42c..266437d8fa7d39 100644 --- a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp +++ b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp @@ -54,6 +54,7 @@ int printGPUsByKFD() { ++Lines) { StringRef Line(*Lines); if (Line.consume_front("gfx_target_version")) { + Line.drop_while([](char C) { return std::isspace(C); }); if (Line.consumeInteger(10, GFXVersion)) return 1; break; >From e420b8f3f146cae593bee78482dcd3e76c55ecc0 Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Mon, 18 Nov 2024 12:00:24 -0600 Subject: [PATCH 4/5] SmallString --- clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp index 266437d8fa7d39..b09565aee7e752 100644 --- a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp +++ b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp @@ -41,7 +41,7 @@ int printGPUsByKFD() { if (sys::path::stem(Begin->path()).consumeInteger(10, Node)) return 1; - SmallVector<char> Path(Begin->path().begin(), Begin->path().end()); + SmallString<0> Path(Begin->path()); sys::path::append(Path, "properties"); ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = >From 46f459a4e813c3595a61ab273006228d88f58e5b Mon Sep 17 00:00:00 2001 From: Joseph Huber <hube...@outlook.com> Date: Mon, 18 Nov 2024 12:30:21 -0600 Subject: [PATCH 5/5] commnets --- clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp index b09565aee7e752..0e169f654a4cb4 100644 --- a/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp +++ b/clang/tools/amdgpu-arch/AMDGPUArchByKFD.cpp @@ -7,7 +7,8 @@ //===----------------------------------------------------------------------===// // // This file implements a tool for detecting name of AMD GPUs installed in -// system using the Linux sysfs interface for the AMD KFD driver. +// system using the Linux sysfs interface for the AMD KFD driver. This file does +// not respect ROCR_VISIBLE_DEVICES like the ROCm environment would. // //===----------------------------------------------------------------------===// _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits