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