1 //===- AMDGPUArchLinux.cpp - list AMDGPU installed ------*- C++ -*---------===//
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
7 //===----------------------------------------------------------------------===//
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.
12 //===----------------------------------------------------------------------===//
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"
26 HSA_STATUS_SUCCESS
= 0x0,
30 HSA_DEVICE_TYPE_CPU
= 0,
31 HSA_DEVICE_TYPE_GPU
= 1,
35 HSA_AGENT_INFO_NAME
= 0,
36 HSA_AGENT_INFO_DEVICE
= 17,
39 typedef struct hsa_agent_s
{
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 *),
49 constexpr const char *DynamicHSAPath
= "libhsa-runtime64.so";
51 llvm::Error
loadHSA() {
53 auto DynlibHandle
= std::make_unique
<llvm::sys::DynamicLibrary
>(
54 llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicHSAPath
, &ErrMsg
));
55 if (!DynlibHandle
->isValid()) {
56 return llvm::createStringError(llvm::inconvertibleErrorCode(),
57 "Failed to 'dlopen' %s", DynamicHSAPath
);
59 #define DYNAMIC_INIT(SYMBOL) \
61 void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL); \
63 return llvm::createStringError(llvm::inconvertibleErrorCode(), \
64 "Failed to 'dlsym' " #SYMBOL); \
65 SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr); \
67 DYNAMIC_INIT(hsa_init
);
68 DYNAMIC_INIT(hsa_shut_down
);
69 DYNAMIC_INIT(hsa_agent_get_info
);
70 DYNAMIC_INIT(hsa_iterate_agents
);
72 return llvm::Error::success();
75 static hsa_status_t
iterateAgentsCallback(hsa_agent_t Agent
, void *Data
) {
76 hsa_device_type_t DeviceType
;
78 hsa_agent_get_info(Agent
, HSA_AGENT_INFO_DEVICE
, &DeviceType
);
80 // continue only if device type if GPU
81 if (Status
!= HSA_STATUS_SUCCESS
|| DeviceType
!= HSA_DEVICE_TYPE_GPU
) {
85 std::vector
<std::string
> *GPUs
=
86 static_cast<std::vector
<std::string
> *>(Data
);
88 Status
= hsa_agent_get_info(Agent
, HSA_AGENT_INFO_NAME
, GPUName
);
89 if (Status
!= HSA_STATUS_SUCCESS
) {
92 GPUs
->push_back(GPUName
);
93 return HSA_STATUS_SUCCESS
;
96 int printGPUsByHSA() {
97 // Attempt to load the HSA runtime.
98 if (llvm::Error Err
= loadHSA()) {
99 logAllUnhandledErrors(std::move(Err
), llvm::errs());
103 hsa_status_t Status
= hsa_init();
104 if (Status
!= HSA_STATUS_SUCCESS
) {
108 std::vector
<std::string
> GPUs
;
109 Status
= hsa_iterate_agents(iterateAgentsCallback
, &GPUs
);
110 if (Status
!= HSA_STATUS_SUCCESS
) {
114 for (const auto &GPU
: GPUs
)
115 llvm::outs() << GPU
<< '\n';