//===- 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 #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 Verbose; #define DEFINE_WRAPPER(NAME) \ using NAME##_ty = decltype(NAME); \ void *NAME##Ptr = nullptr; \ template ze_result_t NAME##Wrapper(Ts... args) { \ if (!NAME##Ptr) { \ return ZE_RESULT_ERROR_UNKNOWN; \ } \ return reinterpret_cast(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::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 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 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; }