1 | //===- AMDGPUArchLinux.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 on Linux. This tool is used by AMDGPU OpenMP and HIP driver. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/Basic/Version.h" |
15 | #include "llvm/Support/CommandLine.h" |
16 | #include "llvm/Support/DynamicLibrary.h" |
17 | #include "llvm/Support/Error.h" |
18 | #include "llvm/Support/raw_ostream.h" |
19 | #include <memory> |
20 | #include <string> |
21 | #include <vector> |
22 | |
23 | using namespace llvm; |
24 | |
25 | typedef enum { |
26 | HSA_STATUS_SUCCESS = 0x0, |
27 | } hsa_status_t; |
28 | |
29 | typedef enum { |
30 | HSA_DEVICE_TYPE_CPU = 0, |
31 | HSA_DEVICE_TYPE_GPU = 1, |
32 | } hsa_device_type_t; |
33 | |
34 | typedef enum { |
35 | HSA_AGENT_INFO_NAME = 0, |
36 | HSA_AGENT_INFO_DEVICE = 17, |
37 | } hsa_agent_info_t; |
38 | |
39 | typedef struct hsa_agent_s { |
40 | uint64_t handle; |
41 | } hsa_agent_t; |
42 | |
43 | hsa_status_t (*hsa_init)(); |
44 | hsa_status_t (*hsa_shut_down)(); |
45 | hsa_status_t (*hsa_agent_get_info)(hsa_agent_t, hsa_agent_info_t, void *); |
46 | hsa_status_t (*hsa_iterate_agents)(hsa_status_t (*)(hsa_agent_t, void *), |
47 | void *); |
48 | |
49 | constexpr const char *DynamicHSAPath = "libhsa-runtime64.so" ; |
50 | |
51 | llvm::Error loadHSA() { |
52 | std::string ErrMsg; |
53 | auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>( |
54 | args: llvm::sys::DynamicLibrary::getPermanentLibrary(filename: DynamicHSAPath, errMsg: &ErrMsg)); |
55 | if (!DynlibHandle->isValid()) { |
56 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
57 | Fmt: "Failed to 'dlopen' %s" , Vals: DynamicHSAPath); |
58 | } |
59 | #define DYNAMIC_INIT(SYMBOL) \ |
60 | { \ |
61 | void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL); \ |
62 | if (!SymbolPtr) \ |
63 | return llvm::createStringError(llvm::inconvertibleErrorCode(), \ |
64 | "Failed to 'dlsym' " #SYMBOL); \ |
65 | SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr); \ |
66 | } |
67 | DYNAMIC_INIT(hsa_init); |
68 | DYNAMIC_INIT(hsa_shut_down); |
69 | DYNAMIC_INIT(hsa_agent_get_info); |
70 | DYNAMIC_INIT(hsa_iterate_agents); |
71 | #undef DYNAMIC_INIT |
72 | return llvm::Error::success(); |
73 | } |
74 | |
75 | static hsa_status_t iterateAgentsCallback(hsa_agent_t Agent, void *Data) { |
76 | hsa_device_type_t DeviceType; |
77 | hsa_status_t Status = |
78 | hsa_agent_get_info(Agent, HSA_AGENT_INFO_DEVICE, &DeviceType); |
79 | |
80 | // continue only if device type if GPU |
81 | if (Status != HSA_STATUS_SUCCESS || DeviceType != HSA_DEVICE_TYPE_GPU) { |
82 | return Status; |
83 | } |
84 | |
85 | std::vector<std::string> *GPUs = |
86 | static_cast<std::vector<std::string> *>(Data); |
87 | char GPUName[64]; |
88 | Status = hsa_agent_get_info(Agent, HSA_AGENT_INFO_NAME, GPUName); |
89 | if (Status != HSA_STATUS_SUCCESS) { |
90 | return Status; |
91 | } |
92 | GPUs->push_back(x: GPUName); |
93 | return HSA_STATUS_SUCCESS; |
94 | } |
95 | |
96 | int printGPUsByHSA() { |
97 | // Attempt to load the HSA runtime. |
98 | if (llvm::Error Err = loadHSA()) { |
99 | logAllUnhandledErrors(E: std::move(Err), OS&: llvm::errs()); |
100 | return 1; |
101 | } |
102 | |
103 | hsa_status_t Status = hsa_init(); |
104 | if (Status != HSA_STATUS_SUCCESS) { |
105 | return 1; |
106 | } |
107 | |
108 | std::vector<std::string> GPUs; |
109 | Status = hsa_iterate_agents(iterateAgentsCallback, &GPUs); |
110 | if (Status != HSA_STATUS_SUCCESS) { |
111 | return 1; |
112 | } |
113 | |
114 | for (const auto &GPU : GPUs) |
115 | llvm::outs() << GPU << '\n'; |
116 | |
117 | if (GPUs.size() < 1) |
118 | return 1; |
119 | |
120 | hsa_shut_down(); |
121 | return 0; |
122 | } |
123 | |