diff --git a/clang/tools/amdgpu-arch/AMDGPUArch.cpp b/clang/tools/amdgpu-arch/AMDGPUArch.cpp --- 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 -#include -#include using namespace llvm; @@ -30,76 +25,8 @@ 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::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(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 *GPUs = - static_cast *>(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 @@ 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 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 --- /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::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(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/AMDGPUArch.cpp b/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp copy from clang/tools/amdgpu-arch/AMDGPUArch.cpp copy to clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp --- a/clang/tools/amdgpu-arch/AMDGPUArch.cpp +++ b/clang/tools/amdgpu-arch/AMDGPUArchByHSA.cpp @@ -1,4 +1,4 @@ -//===- AMDGPUArch.cpp - list AMDGPU installed ----------*- C++ -*---------===// +//===- 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. @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // // This file implements a tool for detecting name of AMDGPU installed in system -// using HSA. This tool is used by AMDGPU OpenMP driver. +// using HSA on Linux. This tool is used by AMDGPU OpenMP and HIP driver. // //===----------------------------------------------------------------------===// @@ -15,21 +15,13 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" #include #include #include using namespace llvm; -static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); - -// Mark all our options with this category. -static cl::OptionCategory AMDGPUArchCategory("amdgpu-arch options"); - -static void PrintVersion(raw_ostream &OS) { - OS << clang::getClangToolFullVersion("amdgpu-arch") << '\n'; -} - typedef enum { HSA_STATUS_SUCCESS = 0x0, } hsa_status_t; @@ -101,22 +93,7 @@ return HSA_STATUS_SUCCESS; } -int main(int argc, char *argv[]) { - cl::HideUnrelatedOptions(AMDGPUArchCategory); - - cl::SetVersionPrinter(PrintVersion); - cl::ParseCommandLineOptions( - argc, argv, - "A tool to detect the presence of AMDGPU devices on the system. \n\n" - "The tool will output each detected GPU architecture separated by a\n" - "newline character. If multiple GPUs of the same architecture are found\n" - "a string will be printed for each\n"); - - if (Help) { - cl::PrintHelpMessage(); - return 0; - } - +int printGPUsByHSA() { // Attempt to load the HSA runtime. if (llvm::Error Err = loadHSA()) { logAllUnhandledErrors(std::move(Err), llvm::errs()); @@ -135,7 +112,7 @@ } for (const auto &GPU : GPUs) - printf("%s\n", GPU.c_str()); + llvm::outs() << GPU << '\n'; if (GPUs.size() < 1) return 1; diff --git a/clang/tools/amdgpu-arch/CMakeLists.txt b/clang/tools/amdgpu-arch/CMakeLists.txt --- 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)