| //===- llvm-offload-device-info.cpp - Print liboffload properties ---------===// |
| // |
| // 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 is a command line utility that, by using the new liboffload API, prints |
| // all devices and properties |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <OffloadAPI.h> |
| #include <iostream> |
| #include <vector> |
| |
| #define OFFLOAD_ERR(X) \ |
| if (auto Err = X) { \ |
| return Err; \ |
| } |
| |
| enum class PrintKind { |
| NORMAL, |
| FP_FLAGS, |
| }; |
| |
| template <typename T, PrintKind PK = PrintKind::NORMAL> |
| void doWrite(std::ostream &S, T &&Val) { |
| S << Val; |
| } |
| |
| template <> |
| void doWrite<ol_platform_backend_t>(std::ostream &S, |
| ol_platform_backend_t &&Val) { |
| switch (Val) { |
| case OL_PLATFORM_BACKEND_UNKNOWN: |
| S << "UNKNOWN"; |
| break; |
| case OL_PLATFORM_BACKEND_CUDA: |
| S << "CUDA"; |
| break; |
| case OL_PLATFORM_BACKEND_AMDGPU: |
| S << "AMDGPU"; |
| break; |
| case OL_PLATFORM_BACKEND_HOST: |
| S << "HOST"; |
| break; |
| default: |
| S << "<< INVALID >>"; |
| break; |
| } |
| } |
| template <> |
| void doWrite<ol_device_type_t>(std::ostream &S, ol_device_type_t &&Val) { |
| switch (Val) { |
| case OL_DEVICE_TYPE_GPU: |
| S << "GPU"; |
| break; |
| case OL_DEVICE_TYPE_CPU: |
| S << "CPU"; |
| break; |
| case OL_DEVICE_TYPE_HOST: |
| S << "HOST"; |
| break; |
| default: |
| S << "<< INVALID >>"; |
| break; |
| } |
| } |
| template <> |
| void doWrite<ol_dimensions_t>(std::ostream &S, ol_dimensions_t &&Val) { |
| S << "{x: " << Val.x << ", y: " << Val.y << ", z: " << Val.z << "}"; |
| } |
| template <> |
| void doWrite<ol_device_fp_capability_flags_t, PrintKind::FP_FLAGS>( |
| std::ostream &S, ol_device_fp_capability_flags_t &&Val) { |
| S << Val << " {"; |
| |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_CORRECTLY_ROUNDED_DIVIDE_SQRT) { |
| S << " CORRECTLY_ROUNDED_DIVIDE_SQRT"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_NEAREST) { |
| S << " ROUND_TO_NEAREST"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_ZERO) { |
| S << " ROUND_TO_ZERO"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_ROUND_TO_INF) { |
| S << " ROUND_TO_INF"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_INF_NAN) { |
| S << " INF_NAN"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_DENORM) { |
| S << " DENORM"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_FMA) { |
| S << " FMA"; |
| } |
| if (Val & OL_DEVICE_FP_CAPABILITY_FLAG_SOFT_FLOAT) { |
| S << " SOFT_FLOAT"; |
| } |
| |
| S << " }"; |
| } |
| |
| template <typename T> |
| ol_result_t printPlatformValue(std::ostream &S, ol_platform_handle_t Plat, |
| ol_platform_info_t Info, const char *Desc) { |
| S << Desc << ": "; |
| |
| if constexpr (std::is_pointer_v<T>) { |
| std::vector<uint8_t> Val; |
| size_t Size; |
| OFFLOAD_ERR(olGetPlatformInfoSize(Plat, Info, &Size)); |
| Val.resize(Size); |
| OFFLOAD_ERR(olGetPlatformInfo(Plat, Info, sizeof(Val), Val.data())); |
| doWrite(S, reinterpret_cast<T>(Val.data())); |
| } else { |
| T Val; |
| OFFLOAD_ERR(olGetPlatformInfo(Plat, Info, sizeof(Val), &Val)); |
| doWrite(S, std::move(Val)); |
| } |
| S << "\n"; |
| return OL_SUCCESS; |
| } |
| |
| template <typename T, PrintKind PK = PrintKind::NORMAL> |
| ol_result_t printDeviceValue(std::ostream &S, ol_device_handle_t Dev, |
| ol_device_info_t Info, const char *Desc, |
| const char *Units = nullptr) { |
| S << Desc << ": "; |
| |
| if constexpr (std::is_pointer_v<T>) { |
| std::vector<uint8_t> Val; |
| size_t Size; |
| OFFLOAD_ERR(olGetDeviceInfoSize(Dev, Info, &Size)); |
| Val.resize(Size); |
| OFFLOAD_ERR(olGetDeviceInfo(Dev, Info, Size, Val.data())); |
| doWrite<T, PK>(S, reinterpret_cast<T>(Val.data())); |
| } else { |
| T Val; |
| OFFLOAD_ERR(olGetDeviceInfo(Dev, Info, sizeof(Val), &Val)); |
| doWrite<T, PK>(S, std::move(Val)); |
| } |
| if (Units) |
| S << " " << Units; |
| S << "\n"; |
| return OL_SUCCESS; |
| } |
| |
| ol_result_t printDevice(std::ostream &S, ol_device_handle_t D) { |
| ol_platform_handle_t Platform; |
| OFFLOAD_ERR( |
| olGetDeviceInfo(D, OL_DEVICE_INFO_PLATFORM, sizeof(Platform), &Platform)); |
| |
| std::vector<char> Name; |
| size_t NameSize; |
| OFFLOAD_ERR(olGetDeviceInfoSize(D, OL_DEVICE_INFO_PRODUCT_NAME, &NameSize)) |
| Name.resize(NameSize); |
| OFFLOAD_ERR( |
| olGetDeviceInfo(D, OL_DEVICE_INFO_PRODUCT_NAME, NameSize, Name.data())); |
| S << "[" << Name.data() << "]\n"; |
| |
| OFFLOAD_ERR(printPlatformValue<const char *>( |
| S, Platform, OL_PLATFORM_INFO_NAME, "Platform Name")); |
| OFFLOAD_ERR(printPlatformValue<const char *>( |
| S, Platform, OL_PLATFORM_INFO_VENDOR_NAME, "Platform Vendor Name")); |
| OFFLOAD_ERR(printPlatformValue<const char *>( |
| S, Platform, OL_PLATFORM_INFO_VERSION, "Platform Version")); |
| OFFLOAD_ERR(printPlatformValue<ol_platform_backend_t>( |
| S, Platform, OL_PLATFORM_INFO_BACKEND, "Platform Backend")); |
| |
| OFFLOAD_ERR( |
| printDeviceValue<const char *>(S, D, OL_DEVICE_INFO_NAME, "Name")); |
| OFFLOAD_ERR(printDeviceValue<const char *>(S, D, OL_DEVICE_INFO_PRODUCT_NAME, |
| "Product Name")); |
| OFFLOAD_ERR(printDeviceValue<const char *>(S, D, OL_DEVICE_INFO_UID, "UID")); |
| OFFLOAD_ERR( |
| printDeviceValue<ol_device_type_t>(S, D, OL_DEVICE_INFO_TYPE, "Type")); |
| OFFLOAD_ERR(printDeviceValue<const char *>( |
| S, D, OL_DEVICE_INFO_DRIVER_VERSION, "Driver Version")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>( |
| S, D, OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE, "Max Work Group Size")); |
| OFFLOAD_ERR(printDeviceValue<ol_dimensions_t>( |
| S, D, OL_DEVICE_INFO_MAX_WORK_GROUP_SIZE_PER_DIMENSION, |
| "Max Work Group Size Per Dimension")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_MAX_WORK_SIZE, |
| "Max Work Size")); |
| OFFLOAD_ERR(printDeviceValue<ol_dimensions_t>( |
| S, D, OL_DEVICE_INFO_MAX_WORK_SIZE_PER_DIMENSION, |
| "Max Work Size Per Dimension")); |
| OFFLOAD_ERR( |
| printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_VENDOR_ID, "Vendor ID")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_NUM_COMPUTE_UNITS, |
| "Num Compute Units")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>( |
| S, D, OL_DEVICE_INFO_MAX_CLOCK_FREQUENCY, "Max Clock Frequency", "MHz")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_MEMORY_CLOCK_RATE, |
| "Memory Clock Rate", "MHz")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_ADDRESS_BITS, |
| "Address Bits")); |
| OFFLOAD_ERR(printDeviceValue<uint64_t>( |
| S, D, OL_DEVICE_INFO_MAX_MEM_ALLOC_SIZE, "Max Mem Allocation Size", "B")); |
| OFFLOAD_ERR(printDeviceValue<uint64_t>(S, D, OL_DEVICE_INFO_GLOBAL_MEM_SIZE, |
| "Global Mem Size", "B")); |
| OFFLOAD_ERR( |
| printDeviceValue<uint64_t>(S, D, OL_DEVICE_INFO_WORK_GROUP_LOCAL_MEM_SIZE, |
| "Work Group Shared Mem Size", "B")); |
| OFFLOAD_ERR( |
| (printDeviceValue<ol_device_fp_capability_flags_t, PrintKind::FP_FLAGS>( |
| S, D, OL_DEVICE_INFO_SINGLE_FP_CONFIG, |
| "Single Precision Floating Point Capability"))); |
| OFFLOAD_ERR( |
| (printDeviceValue<ol_device_fp_capability_flags_t, PrintKind::FP_FLAGS>( |
| S, D, OL_DEVICE_INFO_DOUBLE_FP_CONFIG, |
| "Double Precision Floating Point Capability"))); |
| OFFLOAD_ERR( |
| (printDeviceValue<ol_device_fp_capability_flags_t, PrintKind::FP_FLAGS>( |
| S, D, OL_DEVICE_INFO_HALF_FP_CONFIG, |
| "Half Precision Floating Point Capability"))); |
| OFFLOAD_ERR( |
| printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_CHAR, |
| "Native Vector Width For Char")); |
| OFFLOAD_ERR( |
| printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_SHORT, |
| "Native Vector Width For Short")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>(S, D, |
| OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_INT, |
| "Native Vector Width For Int")); |
| OFFLOAD_ERR( |
| printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_LONG, |
| "Native Vector Width For Long")); |
| OFFLOAD_ERR( |
| printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_FLOAT, |
| "Native Vector Width For Float")); |
| OFFLOAD_ERR(printDeviceValue<uint32_t>( |
| S, D, OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_DOUBLE, |
| "Native Vector Width For Double")); |
| OFFLOAD_ERR( |
| printDeviceValue<uint32_t>(S, D, OL_DEVICE_INFO_NATIVE_VECTOR_WIDTH_HALF, |
| "Native Vector Width For Half")); |
| |
| return OL_SUCCESS; |
| } |
| |
| ol_result_t printRoot(std::ostream &S) { |
| OFFLOAD_ERR(olInit()); |
| S << "Liboffload Version: " << OL_VERSION_MAJOR << "." << OL_VERSION_MINOR |
| << "." << OL_VERSION_PATCH << "\n"; |
| |
| std::vector<ol_device_handle_t> Devices; |
| OFFLOAD_ERR(olIterateDevices( |
| [](ol_device_handle_t Device, void *UserData) { |
| reinterpret_cast<decltype(Devices) *>(UserData)->push_back(Device); |
| return true; |
| }, |
| &Devices)); |
| |
| S << "Num Devices: " << Devices.size() << "\n"; |
| |
| for (auto &D : Devices) { |
| S << "\n"; |
| OFFLOAD_ERR(printDevice(S, D)); |
| } |
| |
| OFFLOAD_ERR(olShutDown()); |
| return OL_SUCCESS; |
| } |
| |
| int main(int argc, char **argv) { |
| auto Err = printRoot(std::cout); |
| |
| if (Err) { |
| std::cerr << "[Liboffload error " << Err->Code << "]: " << Err->Details |
| << "\n"; |
| return 1; |
| } |
| return 0; |
| } |