1 //===- AMDGPUArch.cpp - list AMDGPU installed ----------*- C++ -*---------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements a tool for detecting name of AMDGPU installed in system 10 // using HSA. This tool is used by AMDGPU OpenMP driver. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Support/DynamicLibrary.h" 15 #include "llvm/Support/Error.h" 16 #include <memory> 17 #include <string> 18 #include <vector> 19 20 #if defined(__has_include) 21 #if __has_include("hsa/hsa.h") 22 #define HSA_HEADER_FOUND 1 23 #include "hsa/hsa.h" 24 #elif __has_include("hsa.h") 25 #define HSA_HEADER_FOUND 1 26 #include "hsa.h" 27 #else 28 #define HSA_HEADER_FOUND 0 29 #endif 30 #else 31 #define HSA_HEADER_FOUND 0 32 #endif 33 34 #if !HSA_HEADER_FOUND 35 // Forward declaration of the status enumeration used by HSA. 36 typedef enum { 37 HSA_STATUS_SUCCESS = 0x0, 38 } hsa_status_t; 39 40 // Forward declaration of the device types used by HSA. 41 typedef enum { 42 HSA_DEVICE_TYPE_CPU = 0, 43 HSA_DEVICE_TYPE_GPU = 1, 44 } hsa_device_type_t; 45 46 // Forward declaration of the agent information types we use. 47 typedef enum { 48 HSA_AGENT_INFO_NAME = 0, 49 HSA_AGENT_INFO_DEVICE = 17, 50 } hsa_agent_info_t; 51 52 typedef struct hsa_agent_s { 53 uint64_t handle; 54 } hsa_agent_t; 55 56 hsa_status_t (*hsa_init)(); 57 hsa_status_t (*hsa_shut_down)(); 58 hsa_status_t (*hsa_agent_get_info)(hsa_agent_t, hsa_agent_info_t, void *); 59 hsa_status_t (*hsa_iterate_agents)(hsa_status_t (*callback)(hsa_agent_t, 60 void *), 61 void *); 62 63 constexpr const char *DynamicHSAPath = "libhsa-runtime64.so"; 64 65 llvm::Error loadHSA() { 66 std::string ErrMsg; 67 auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>( 68 llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicHSAPath, &ErrMsg)); 69 if (!DynlibHandle->isValid()) { 70 return llvm::createStringError(llvm::inconvertibleErrorCode(), 71 "Failed to 'dlopen' %s\n", DynamicHSAPath); 72 } 73 #define DYNAMIC_INIT(SYMBOL) \ 74 { \ 75 void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL); \ 76 if (!SymbolPtr) \ 77 return llvm::createStringError(llvm::inconvertibleErrorCode(), \ 78 "Failed to 'dlsym' " #SYMBOL); \ 79 SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr); \ 80 } 81 DYNAMIC_INIT(hsa_init); 82 DYNAMIC_INIT(hsa_shut_down); 83 DYNAMIC_INIT(hsa_agent_get_info); 84 DYNAMIC_INIT(hsa_iterate_agents); 85 #undef DYNAMIC_INIT 86 return llvm::Error::success(); 87 } 88 #else 89 llvm::Error loadHSA() { return llvm::Error::success(); } 90 #endif 91 92 static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) { 93 hsa_device_type_t DeviceType; 94 hsa_status_t Status = 95 hsa_agent_get_info(Agent, HSA_AGENT_INFO_DEVICE, &DeviceType); 96 97 // continue only if device type if GPU 98 if (Status != HSA_STATUS_SUCCESS || DeviceType != HSA_DEVICE_TYPE_GPU) { 99 return Status; 100 } 101 102 std::vector<std::string> *GPUs = 103 static_cast<std::vector<std::string> *>(Data); 104 char GPUName[64]; 105 Status = hsa_agent_get_info(Agent, HSA_AGENT_INFO_NAME, GPUName); 106 if (Status != HSA_STATUS_SUCCESS) { 107 return Status; 108 } 109 GPUs->push_back(GPUName); 110 return HSA_STATUS_SUCCESS; 111 } 112 113 int main(int argc, char *argv[]) { 114 // Attempt to load the HSA runtime. 115 if (llvm::Error Err = loadHSA()) { 116 logAllUnhandledErrors(std::move(Err), llvm::errs()); 117 return 1; 118 } 119 120 hsa_status_t Status = hsa_init(); 121 if (Status != HSA_STATUS_SUCCESS) { 122 return 1; 123 } 124 125 std::vector<std::string> GPUs; 126 Status = hsa_iterate_agents(iterateAgentsCallback, &GPUs); 127 if (Status != HSA_STATUS_SUCCESS) { 128 return 1; 129 } 130 131 for (const auto &GPU : GPUs) 132 printf("%s\n", GPU.c_str()); 133 134 if (GPUs.size() < 1) 135 return 1; 136 137 hsa_shut_down(); 138 return 0; 139 } 140