182 lines · cpp
1//===- LevelZeroArch.cpp - list installed Level Zero devices ---*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements a tool for detecting Level Zero devices installed in the10// system11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Support/CommandLine.h"15#include "llvm/Support/DynamicLibrary.h"16#include "llvm/Support/Error.h"17#include <cstdio>18 19#define ZE_MAX_DEVICE_NAME 25620#define ZE_MAX_DEVICE_UUID_SIZE 1621 22using ze_driver_handle_t = void *;23using ze_device_handle_t = void *;24 25enum ze_result_t {26 ZE_RESULT_SUCCESS = 0,27 ZE_RESULT_ERROR_UNKNOWN = 0x7ffffffe28};29 30enum ze_structure_type_t {31 ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC = 0x00020021,32 ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES = 0x3,33 ZE_STRUCTURE_TYPE_FORCE_UINT32 = 0x7fffffff34};35 36enum ze_init_driver_type_flags_t { ZE_INIT_DRIVER_TYPE_FLAG_GPU = 1 };37 38using ze_device_type_t = uint32_t;39using ze_device_property_flags_t = uint32_t;40 41struct ze_init_driver_type_desc_t {42 ze_structure_type_t stype;43 const void *pNext;44 ze_init_driver_type_flags_t flags;45};46 47struct ze_device_uuid_t {48 uint8_t id[ZE_MAX_DEVICE_UUID_SIZE];49};50 51struct ze_device_properties_t {52 ze_structure_type_t stype;53 void *pNext;54 ze_device_type_t type;55 uint32_t vendorId;56 uint32_t deviceId;57 ze_device_property_flags_t flags;58 uint32_t subdeviceId;59 uint32_t coreClockRate;60 uint64_t maxMemAllocSize;61 uint32_t maxHardwareContexts;62 uint32_t maxCommandQueuePriority;63 uint32_t numThreadsPerEU;64 uint32_t physicalEUSimdWidth;65 uint32_t numEUsPerSubslice;66 uint32_t numSubslicesPerSlice;67 uint32_t numSlices;68 uint64_t timerResolution;69 uint32_t timestampValidBits;70 uint32_t kernelTimestampValidBits;71 ze_device_uuid_t uuid;72 char name[ZE_MAX_DEVICE_NAME];73};74 75ze_result_t zeInitDrivers(uint32_t *pCount, ze_driver_handle_t *phDrivers,76 ze_init_driver_type_desc_t *desc);77ze_result_t zeDeviceGet(ze_driver_handle_t hDriver, uint32_t *pCount,78 void *phDevices);79ze_result_t zeDeviceGetProperties(void *hDevice, void *pProperties);80 81using namespace llvm;82extern cl::opt<bool> Verbose;83 84#define DEFINE_WRAPPER(NAME) \85 using NAME##_ty = decltype(NAME); \86 void *NAME##Ptr = nullptr; \87 template <class... Ts> ze_result_t NAME##Wrapper(Ts... args) { \88 if (!NAME##Ptr) { \89 return ZE_RESULT_ERROR_UNKNOWN; \90 } \91 return reinterpret_cast<NAME##_ty *>(NAME##Ptr)(args...); \92 }93 94DEFINE_WRAPPER(zeInitDrivers)95DEFINE_WRAPPER(zeDeviceGet)96DEFINE_WRAPPER(zeDeviceGetProperties)97 98static bool loadLevelZero() {99 constexpr const char *L0Library = "libze_loader.so";100 std::string ErrMsg;101 102 auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(103 llvm::sys::DynamicLibrary::getPermanentLibrary(L0Library, &ErrMsg));104 if (!DynlibHandle->isValid()) {105 if (ErrMsg.empty())106 ErrMsg = "unknown error";107 if (Verbose)108 llvm::errs() << "Unable to load library '" << L0Library << "': " << ErrMsg109 << "\n";110 return false;111 }112 113 constexpr struct {114 const char *Name;115 void **FuncPtr;116 } Wrappers[] = {117 {"zeInitDrivers", &zeInitDriversPtr},118 {"zeDeviceGet", &zeDeviceGetPtr},119 {"zeDeviceGetProperties", &zeDeviceGetPropertiesPtr},120 };121 122 for (auto Entry : Wrappers) {123 void *P = DynlibHandle->getAddressOfSymbol(Entry.Name);124 if (P == nullptr) {125 if (Verbose)126 llvm::errs() << "Unable to find '" << Entry.Name << "' in '"127 << L0Library << "'\n";128 return false;129 }130 *(Entry.FuncPtr) = P;131 }132 133 return true;134}135 136#define CALL_ZE_AND_CHECK(Fn, ...) \137 do { \138 ze_result_t Rc = Fn##Wrapper(__VA_ARGS__); \139 if (Rc != ZE_RESULT_SUCCESS) { \140 if (Verbose) \141 llvm::errs() << "Error: " << __func__ << ":" << #Fn \142 << " failed with error code " << Rc << "\n"; \143 return 1; \144 } \145 } while (0)146 147int printGPUsByLevelZero() {148 if (!loadLevelZero())149 return 1;150 151 ze_init_driver_type_desc_t DriverType = {};152 DriverType.stype = ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC;153 DriverType.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU;154 DriverType.pNext = nullptr;155 uint32_t DriverCount{0};156 157 // Initialize and find all drivers.158 CALL_ZE_AND_CHECK(zeInitDrivers, &DriverCount, nullptr, &DriverType);159 160 llvm::SmallVector<ze_driver_handle_t> Drivers(DriverCount);161 CALL_ZE_AND_CHECK(zeInitDrivers, &DriverCount, Drivers.data(), &DriverType);162 163 for (auto Driver : Drivers) {164 // Discover all the devices for a given driver.165 uint32_t DeviceCount = 0;166 CALL_ZE_AND_CHECK(zeDeviceGet, Driver, &DeviceCount, nullptr);167 168 llvm::SmallVector<ze_device_handle_t> Devices(DeviceCount);169 CALL_ZE_AND_CHECK(zeDeviceGet, Driver, &DeviceCount, Devices.data());170 171 for (auto Device : Devices) {172 ze_device_properties_t DeviceProperties = {};173 DeviceProperties.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES;174 DeviceProperties.pNext = nullptr;175 CALL_ZE_AND_CHECK(zeDeviceGetProperties, Device, &DeviceProperties);176 llvm::outs() << DeviceProperties.name << '\n';177 }178 }179 180 return 0;181}182