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