blob: 5e543e3231c1117dc0e5d9f777bda5bb6c5f4761 [file] [log] [blame]
//===- 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;
}