aboutsummaryrefslogtreecommitdiff
path: root/clang/tools/offload-arch/LevelZeroArch.cpp
blob: 5e543e3231c1117dc0e5d9f777bda5bb6c5f4761 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//===- LevelZeroArch.cpp - list installed Level Zero devices ---*- C++ -*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements a tool for detecting Level Zero devices installed in the
// system
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Error.h"
#include <cstdio>

#define ZE_MAX_DEVICE_NAME 256
#define ZE_MAX_DEVICE_UUID_SIZE 16

using ze_driver_handle_t = void *;
using ze_device_handle_t = void *;

enum ze_result_t {
  ZE_RESULT_SUCCESS = 0,
  ZE_RESULT_ERROR_UNKNOWN = 0x7ffffffe
};

enum ze_structure_type_t {
  ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC = 0x00020021,
  ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES = 0x3,
  ZE_STRUCTURE_TYPE_FORCE_UINT32 = 0x7fffffff
};

enum ze_init_driver_type_flags_t { ZE_INIT_DRIVER_TYPE_FLAG_GPU = 1 };

using ze_device_type_t = uint32_t;
using ze_device_property_flags_t = uint32_t;

struct ze_init_driver_type_desc_t {
  ze_structure_type_t stype;
  const void *pNext;
  ze_init_driver_type_flags_t flags;
};

struct ze_device_uuid_t {
  uint8_t id[ZE_MAX_DEVICE_UUID_SIZE];
};

struct ze_device_properties_t {
  ze_structure_type_t stype;
  void *pNext;
  ze_device_type_t type;
  uint32_t vendorId;
  uint32_t deviceId;
  ze_device_property_flags_t flags;
  uint32_t subdeviceId;
  uint32_t coreClockRate;
  uint64_t maxMemAllocSize;
  uint32_t maxHardwareContexts;
  uint32_t maxCommandQueuePriority;
  uint32_t numThreadsPerEU;
  uint32_t physicalEUSimdWidth;
  uint32_t numEUsPerSubslice;
  uint32_t numSubslicesPerSlice;
  uint32_t numSlices;
  uint64_t timerResolution;
  uint32_t timestampValidBits;
  uint32_t kernelTimestampValidBits;
  ze_device_uuid_t uuid;
  char name[ZE_MAX_DEVICE_NAME];
};

ze_result_t zeInitDrivers(uint32_t *pCount, ze_driver_handle_t *phDrivers,
                          ze_init_driver_type_desc_t *desc);
ze_result_t zeDeviceGet(ze_driver_handle_t hDriver, uint32_t *pCount,
                        void *phDevices);
ze_result_t zeDeviceGetProperties(void *hDevice, void *pProperties);

using namespace llvm;
extern cl::opt<bool> Verbose;

#define DEFINE_WRAPPER(NAME)                                                   \
  using NAME##_ty = decltype(NAME);                                            \
  void *NAME##Ptr = nullptr;                                                   \
  template <class... Ts> ze_result_t NAME##Wrapper(Ts... args) {               \
    if (!NAME##Ptr) {                                                          \
      return ZE_RESULT_ERROR_UNKNOWN;                                          \
    }                                                                          \
    return reinterpret_cast<NAME##_ty *>(NAME##Ptr)(args...);                  \
  }

DEFINE_WRAPPER(zeInitDrivers)
DEFINE_WRAPPER(zeDeviceGet)
DEFINE_WRAPPER(zeDeviceGetProperties)

static bool loadLevelZero() {
  constexpr const char *L0Library = "libze_loader.so";
  std::string ErrMsg;

  auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
      llvm::sys::DynamicLibrary::getPermanentLibrary(L0Library, &ErrMsg));
  if (!DynlibHandle->isValid()) {
    if (ErrMsg.empty())
      ErrMsg = "unknown error";
    if (Verbose)
      llvm::errs() << "Unable to load library '" << L0Library << "': " << ErrMsg
                   << "\n";
    return false;
  }

  constexpr struct {
    const char *Name;
    void **FuncPtr;
  } Wrappers[] = {
      {"zeInitDrivers", &zeInitDriversPtr},
      {"zeDeviceGet", &zeDeviceGetPtr},
      {"zeDeviceGetProperties", &zeDeviceGetPropertiesPtr},
  };

  for (auto Entry : Wrappers) {
    void *P = DynlibHandle->getAddressOfSymbol(Entry.Name);
    if (P == nullptr) {
      if (Verbose)
        llvm::errs() << "Unable to find '" << Entry.Name << "' in '"
                     << L0Library << "'\n";
      return false;
    }
    *(Entry.FuncPtr) = P;
  }

  return true;
}

#define CALL_ZE_AND_CHECK(Fn, ...)                                             \
  do {                                                                         \
    ze_result_t Rc = Fn##Wrapper(__VA_ARGS__);                                 \
    if (Rc != ZE_RESULT_SUCCESS) {                                             \
      if (Verbose)                                                             \
        llvm::errs() << "Error: " << __func__ << ":" << #Fn                    \
                     << " failed with error code " << Rc << "\n";              \
      return 1;                                                                \
    }                                                                          \
  } while (0)

int printGPUsByLevelZero() {
  if (!loadLevelZero())
    return 1;

  ze_init_driver_type_desc_t DriverType = {};
  DriverType.stype = ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC;
  DriverType.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU;
  DriverType.pNext = nullptr;
  uint32_t DriverCount{0};

  // Initialize and find all drivers.
  CALL_ZE_AND_CHECK(zeInitDrivers, &DriverCount, nullptr, &DriverType);

  llvm::SmallVector<ze_driver_handle_t> Drivers(DriverCount);
  CALL_ZE_AND_CHECK(zeInitDrivers, &DriverCount, Drivers.data(), &DriverType);

  for (auto Driver : Drivers) {
    // Discover all the devices for a given driver.
    uint32_t DeviceCount = 0;
    CALL_ZE_AND_CHECK(zeDeviceGet, Driver, &DeviceCount, nullptr);

    llvm::SmallVector<ze_device_handle_t> Devices(DeviceCount);
    CALL_ZE_AND_CHECK(zeDeviceGet, Driver, &DeviceCount, Devices.data());

    for (auto Device : Devices) {
      ze_device_properties_t DeviceProperties = {};
      DeviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES;
      DeviceProperties.pNext = nullptr;
      CALL_ZE_AND_CHECK(zeDeviceGetProperties, Device, &DeviceProperties);
      llvm::outs() << DeviceProperties.name << '\n';
    }
  }

  return 0;
}