-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang][tools] Add LevelZero support to offload-arch #160570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-clang Author: Alex Duran (adurang) ChangesFull diff: https://github.com/llvm/llvm-project/pull/160570.diff 3 Files Affected:
diff --git a/clang/tools/offload-arch/CMakeLists.txt b/clang/tools/offload-arch/CMakeLists.txt
index cb50b9c1d6dde..187c4d9517551 100644
--- a/clang/tools/offload-arch/CMakeLists.txt
+++ b/clang/tools/offload-arch/CMakeLists.txt
@@ -1,8 +1,16 @@
set(LLVM_LINK_COMPONENTS Support)
-add_clang_tool(offload-arch OffloadArch.cpp NVPTXArch.cpp AMDGPUArchByKFD.cpp AMDGPUArchByHIP.cpp)
+add_clang_tool(offload-arch OffloadArch.cpp NVPTXArch.cpp AMDGPUArchByKFD.cpp
+ AMDGPUArchByHIP.cpp LevelZeroArch.cpp)
+
+find_path(OFFLOAD_ARCH_LEVEL_ZERO_INCLUDE_DIR NAMES level_zero/ze_api.h)
+if (OFFLOAD_ARCH_LEVEL_ZERO_INCLUDE_DIR)
+ target_include_directories(offload-arch PRIVATE ${OFFLOAD_ARCH_LEVEL_ZERO_INCLUDE_DIR})
+ target_compile_definitions(offload-arch PRIVATE HAVE_LEVEL_ZERO_HEADERS)
+endif()
add_clang_symlink(amdgpu-arch offload-arch)
add_clang_symlink(nvptx-arch offload-arch)
+add_clang_symlink(intelgpu-arch offload-arch)
target_link_libraries(offload-arch PRIVATE clangBasic)
diff --git a/clang/tools/offload-arch/LevelZeroArch.cpp b/clang/tools/offload-arch/LevelZeroArch.cpp
new file mode 100644
index 0000000000000..8b6b393f6f9f6
--- /dev/null
+++ b/clang/tools/offload-arch/LevelZeroArch.cpp
@@ -0,0 +1,133 @@
+//===- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HAVE_LEVEL_ZERO_HEADERS
+
+int printGPUsByLevelZero() {
+ return 0;
+}
+
+#else
+
+#include "clang/Basic/Version.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <cstdio>
+#include <memory>
+#include <level_zero/ze_api.h>
+
+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##_wrap(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() {
+ 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 **fptr;
+ } dlwrap[] = {
+ {"zeInitDrivers", &zeInitDriversPtr},
+ {"zeDeviceGet", &zeDeviceGetPtr},
+ {"zeDeviceGetProperties", &zeDeviceGetPropertiesPtr},
+ };
+
+ for (auto entry : dlwrap) {
+ void *P = DynlibHandle->getAddressOfSymbol(entry.name);
+ if (P == nullptr) {
+ if (Verbose)
+ llvm::errs() << "Unable to find '" << entry.name << "' in '" << L0Library
+ << "'!\n";
+ return false;
+ }
+ *(entry.fptr) = P;
+ }
+
+ return true;
+}
+
+#define CALL_ZE_AND_CHECK(Fn, ...) \
+ do { \
+ ze_result_t Rc = Fn##_wrap(__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 driver_type = {};
+ driver_type.stype = ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC;
+ driver_type.flags = ZE_INIT_DRIVER_TYPE_FLAG_GPU;
+ driver_type.pNext = nullptr;
+ uint32_t driverCount{0};
+
+ // Initialize and find all drivers
+ CALL_ZE_AND_CHECK(zeInitDrivers, &driverCount, nullptr, &driver_type);
+
+ llvm::SmallVector<ze_driver_handle_t> drivers(driverCount);
+ CALL_ZE_AND_CHECK(zeInitDrivers, &driverCount, drivers.data(), &driver_type);
+
+ 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) {
+ // Get device properties
+ ze_device_properties_t deviceProperties;
+ CALL_ZE_AND_CHECK(zeDeviceGetProperties, device, &deviceProperties);
+ // Print device name
+ llvm::outs() << deviceProperties.name << '\n';
+ }
+ }
+
+ return 0;
+}
+
+#endif // HAVE_LEVEL_ZERO_HEADERS
diff --git a/clang/tools/offload-arch/OffloadArch.cpp b/clang/tools/offload-arch/OffloadArch.cpp
index 74be40214a0ec..5043c00986a9b 100644
--- a/clang/tools/offload-arch/OffloadArch.cpp
+++ b/clang/tools/offload-arch/OffloadArch.cpp
@@ -21,6 +21,7 @@ enum VendorName {
all,
amdgpu,
nvptx,
+ intel,
};
static cl::opt<VendorName>
@@ -28,7 +29,8 @@ static cl::opt<VendorName>
cl::init(all),
cl::values(clEnumVal(all, "Print all GPUs (default)"),
clEnumVal(amdgpu, "Only print AMD GPUs"),
- clEnumVal(nvptx, "Only print NVIDIA GPUs")));
+ clEnumVal(nvptx, "Only print NVIDIA GPUs"),
+ clEnumVal(intel, "Only print Intel GPUs")));
cl::opt<bool> Verbose("verbose", cl::desc("Enable verbose output"),
cl::init(false), cl::cat(OffloadArchCategory));
@@ -40,6 +42,7 @@ static void PrintVersion(raw_ostream &OS) {
int printGPUsByKFD();
int printGPUsByHIP();
int printGPUsByCUDA();
+int printGPUsByLevelZero();
static int printAMD() {
#ifndef _WIN32
@@ -51,6 +54,7 @@ static int printAMD() {
}
static int printNVIDIA() { return printGPUsByCUDA(); }
+static int printIntel() { return printGPUsByLevelZero(); }
int main(int argc, char *argv[]) {
cl::HideUnrelatedOptions(OffloadArchCategory);
@@ -73,15 +77,22 @@ int main(int argc, char *argv[]) {
sys::path::stem(argv[0]).starts_with("amdgpu-arch");
bool NVIDIAOnly = Only == VendorName::nvptx ||
sys::path::stem(argv[0]).starts_with("nvptx-arch");
+ bool IntelOnly = Only == VendorName::intel ||
+ sys::path::stem(argv[0]).starts_with("intelgpu-arch");
+ bool All = !AMDGPUOnly && !NVIDIAOnly && !IntelOnly;
int NVIDIAResult = 0;
- if (!AMDGPUOnly)
+ if (NVIDIAOnly || All)
NVIDIAResult = printNVIDIA();
int AMDResult = 0;
- if (!NVIDIAOnly)
+ if (AMDGPUOnly || All)
AMDResult = printAMD();
+ int IntelResult = 0;
+ if (IntelOnly || All)
+ IntelResult = printIntel();
+
// We only failed if all cases returned an error.
- return AMDResult && NVIDIAResult;
+ return AMDResult && NVIDIAResult && IntelResult;
}
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
@sarnex @hansangbae @jhuber6 would you mind taking a look at this PR? |
Co-authored-by: Joseph Huber <[email protected]>
| if (!NVIDIAOnly) | ||
| AMDResult = printAMD(); | ||
| llvm::SmallVector<int> results(VendorTable.size()); | ||
| llvm::transform(VendorTable, results.begin(), [&](const auto &entry) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just do return llvm::all_of here now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned llvm::all_of doesn't guarantee all elements will be visited. If one of them returns false the remaining ones won't be executed (as the result is already known to be false).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, then just a manual loop with result &= func() or use std::transform_reduce with logical and. I would assume the former is easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if you do a look remember you can do for (auto [Name, Func] : Table. Also I forgot to nag you about the LLVM naming convention, remember it's CamelCase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did the loop, and I think I changed all the names too :)
|
@jhuber6 @sarnex @hansangbae any further comments? |
jhuber6
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG, one minor nit left.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just nits
|
all done I think :) |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/66/builds/19756 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/51/builds/24168 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/27/builds/16608 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/186/builds/12691 Here is the relevant piece of the build log for the reference |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/72/builds/15222 Here is the relevant piece of the build log for the reference |
|
many thanks @kazutakahirata ! |
Co-authored-by: Joseph Huber <[email protected]>
No description provided.