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 HIP runtime. This tool is used by AMDGPU OpenMP and HIP driver.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/DynamicLibrary.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/raw_ostream.h"
17
18using namespace llvm;
19
20typedef struct {
21  char padding[396];
22  char gcnArchName[256];
23  char padding2[1024];
24} hipDeviceProp_t;
25
26typedef enum {
27  hipSuccess = 0,
28} hipError_t;
29
30typedef hipError_t (*hipGetDeviceCount_t)(int *);
31typedef hipError_t (*hipDeviceGet_t)(int *, int);
32typedef hipError_t (*hipGetDeviceProperties_t)(hipDeviceProp_t *, int);
33
34int printGPUsByHIP() {
35#ifdef _WIN32
36  constexpr const char *DynamicHIPPath = "amdhip64.dll";
37#else
38  constexpr const char *DynamicHIPPath = "libamdhip64.so";
39#endif
40
41  std::string ErrMsg;
42  auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
43      llvm::sys::DynamicLibrary::getPermanentLibrary(DynamicHIPPath, &ErrMsg));
44  if (!DynlibHandle->isValid()) {
45    llvm::errs() << "Failed to load " << DynamicHIPPath << ": " << ErrMsg
46                 << '\n';
47    return 1;
48  }
49
50#define DYNAMIC_INIT_HIP(SYMBOL)                                               \
51  {                                                                            \
52    void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL);               \
53    if (!SymbolPtr) {                                                          \
54      llvm::errs() << "Failed to find symbol " << #SYMBOL << '\n';             \
55      return 1;                                                                \
56    }                                                                          \
57    SYMBOL = reinterpret_cast<decltype(SYMBOL)>(SymbolPtr);                    \
58  }
59
60  hipGetDeviceCount_t hipGetDeviceCount;
61  hipDeviceGet_t hipDeviceGet;
62  hipGetDeviceProperties_t hipGetDeviceProperties;
63
64  DYNAMIC_INIT_HIP(hipGetDeviceCount);
65  DYNAMIC_INIT_HIP(hipDeviceGet);
66  DYNAMIC_INIT_HIP(hipGetDeviceProperties);
67
68#undef DYNAMIC_INIT_HIP
69
70  int deviceCount;
71  hipError_t err = hipGetDeviceCount(&deviceCount);
72  if (err != hipSuccess) {
73    llvm::errs() << "Failed to get device count\n";
74    return 1;
75  }
76
77  for (int i = 0; i < deviceCount; ++i) {
78    int deviceId;
79    err = hipDeviceGet(&deviceId, i);
80    if (err != hipSuccess) {
81      llvm::errs() << "Failed to get device id for ordinal " << i << '\n';
82      return 1;
83    }
84
85    hipDeviceProp_t prop;
86    err = hipGetDeviceProperties(&prop, deviceId);
87    if (err != hipSuccess) {
88      llvm::errs() << "Failed to get device properties for device " << deviceId
89                   << '\n';
90      return 1;
91    }
92    llvm::outs() << prop.gcnArchName << '\n';
93  }
94
95  return 0;
96}
97