-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc] Use LLVM CommandLine for loader tool #101501
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
Summary: This patch removes the ad-hoc parsing that I used previously and replaces it with the LLVM CommnadLine interface. This doesn't change any functionality, but makes it easier to maintain.
@llvm/pr-subscribers-libc Author: Joseph Huber (jhuber6) ChangesSummary: Full diff: https://github.com/llvm/llvm-project/pull/101501.diff 5 Files Affected:
diff --git a/libc/utils/gpu/loader/CMakeLists.txt b/libc/utils/gpu/loader/CMakeLists.txt
index fd217a25c8a0e..60597a67ce57a 100644
--- a/libc/utils/gpu/loader/CMakeLists.txt
+++ b/libc/utils/gpu/loader/CMakeLists.txt
@@ -7,6 +7,9 @@ target_include_directories(gpu_loader PUBLIC
${LLVM_MAIN_INCLUDE_DIR}
${LLVM_BINARY_DIR}/include
)
+if(NOT LLVM_ENABLE_RTTI)
+ target_compile_options(gpu_loader PUBLIC -fno-rtti)
+endif()
find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
if(hsa-runtime64_FOUND)
diff --git a/libc/utils/gpu/loader/Loader.h b/libc/utils/gpu/loader/Loader.h
index e029816764427..2151013bae479 100644
--- a/libc/utils/gpu/loader/Loader.h
+++ b/libc/utils/gpu/loader/Loader.h
@@ -53,8 +53,9 @@ struct end_args_t {
/// Generic interface to load the \p image and launch execution of the _start
/// kernel on the target device. Copies \p argc and \p argv to the device.
/// Returns the final value of the `main` function on the device.
-int load(int argc, char **argv, char **evnp, void *image, size_t size,
- const LaunchParameters ¶ms, bool print_resource_usage);
+int load(int argc, const char **argv, const char **evnp, void *image,
+ size_t size, const LaunchParameters ¶ms,
+ bool print_resource_usage);
/// Return \p V aligned "upwards" according to \p Align.
template <typename V, typename A> inline V align_up(V val, A align) {
@@ -63,7 +64,7 @@ template <typename V, typename A> inline V align_up(V val, A align) {
/// Copy the system's argument vector to GPU memory allocated using \p alloc.
template <typename Allocator>
-void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
+void *copy_argument_vector(int argc, const char **argv, Allocator alloc) {
size_t argv_size = sizeof(char *) * (argc + 1);
size_t str_size = 0;
for (int i = 0; i < argc; ++i)
@@ -90,9 +91,9 @@ void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
/// Copy the system's environment to GPU memory allocated using \p alloc.
template <typename Allocator>
-void *copy_environment(char **envp, Allocator alloc) {
+void *copy_environment(const char **envp, Allocator alloc) {
int envc = 0;
- for (char **env = envp; *env != 0; ++env)
+ for (const char **env = envp; *env != 0; ++env)
++envc;
return copy_argument_vector(envc, envp, alloc);
diff --git a/libc/utils/gpu/loader/Main.cpp b/libc/utils/gpu/loader/Main.cpp
index a9c0b868725d0..44ed8bf58ab87 100644
--- a/libc/utils/gpu/loader/Main.cpp
+++ b/libc/utils/gpu/loader/Main.cpp
@@ -13,88 +13,97 @@
#include "Loader.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/WithColor.h"
+
#include <cstdio>
#include <cstdlib>
#include <string>
-#include <vector>
-int main(int argc, char **argv, char **envp) {
- if (argc < 2) {
- printf("USAGE: ./loader [--threads <n>, --blocks <n>, "
- "--print-resource-usage] <device_image> "
- "<args>, ...\n");
- return EXIT_SUCCESS;
- }
+using namespace llvm;
- int offset = 0;
- FILE *file = nullptr;
- char *ptr;
- LaunchParameters params = {1, 1, 1, 1, 1, 1};
- bool print_resource_usage = false;
- while (!file && ++offset < argc) {
- if (argv[offset] == std::string("--threads") ||
- argv[offset] == std::string("--threads-x")) {
- params.num_threads_x =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--threads-y")) {
- params.num_threads_y =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--threads-z")) {
- params.num_threads_z =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--blocks") ||
- argv[offset] == std::string("--blocks-x")) {
- params.num_blocks_x =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--blocks-y")) {
- params.num_blocks_y =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--blocks-z")) {
- params.num_blocks_z =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--print-resource-usage")) {
- print_resource_usage = true;
- continue;
- } else {
- file = fopen(argv[offset], "r");
- if (!file) {
- fprintf(stderr, "Failed to open image file '%s'\n", argv[offset]);
- return EXIT_FAILURE;
- }
- break;
- }
- }
+static cl::OptionCategory loader_category("loader options");
+
+static cl::opt<bool> help("h", cl::desc("Alias for -help"), cl::Hidden,
+ cl::cat(loader_category));
+
+static cl::opt<unsigned>
+ threads_x("threads-x", cl::desc("Number of threads in the 'x' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ threads_y("threads-y", cl::desc("Number of threads in the 'y' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ threads_z("threads-z", cl::desc("Number of threads in the 'z' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::alias threads("threads", cl::aliasopt(threads_x),
+ cl::desc("Alias for --threads-x"),
+ cl::cat(loader_category));
+
+static cl::opt<unsigned>
+ blocks_x("blocks-x", cl::desc("Number of blocks in the 'x' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ blocks_y("blocks-y", cl::desc("Number of blocks in the 'y' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ blocks_z("blocks-z", cl::desc("Number of blocks in the 'z' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::alias blocks("blocks", cl::aliasopt(blocks_x),
+ cl::desc("Alias for --blocks-x"),
+ cl::cat(loader_category));
- if (!file) {
- fprintf(stderr, "No image file provided\n");
- return EXIT_FAILURE;
+static cl::opt<bool>
+ print_resource_usage("print-resource-usage",
+ cl::desc("Output resource usage of launched kernels"),
+ cl::init(false), cl::cat(loader_category));
+
+static cl::opt<std::string> file(cl::Positional, cl::Required,
+ cl::desc("<gpu executable>"),
+ cl::cat(loader_category));
+static cl::list<std::string> args(cl::ConsumeAfter,
+ cl::desc("<program arguments>..."),
+ cl::cat(loader_category));
+
+[[noreturn]] void report_error(Error E) {
+ outs().flush();
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), "loader"));
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, const char **argv, const char **envp) {
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ cl::HideUnrelatedOptions(loader_category);
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A utility used to launch unit tests built for a GPU target. This is\n"
+ "intended to provide an intrface simular to cross-compiling emulators\n");
+
+ if (help) {
+ cl::PrintHelpMessage();
+ return EXIT_SUCCESS;
}
- // TODO: We should perform some validation on the file.
- fseek(file, 0, SEEK_END);
- const auto size = ftell(file);
- fseek(file, 0, SEEK_SET);
+ ErrorOr<std::unique_ptr<MemoryBuffer>> image_or_err =
+ MemoryBuffer::getFileOrSTDIN(file);
+ if (std::error_code ec = image_or_err.getError())
+ report_error(errorCodeToError(ec));
+ MemoryBufferRef image = **image_or_err;
- void *image = malloc(size * sizeof(char));
- fread(image, sizeof(char), size, file);
- fclose(file);
+ SmallVector<const char *> new_argv = {file.c_str()};
+ llvm::transform(args, std::back_inserter(new_argv),
+ [](const std::string &arg) { return arg.c_str(); });
// Drop the loader from the program arguments.
- int ret = load(argc - offset, &argv[offset], envp, image, size, params,
- print_resource_usage);
+ LaunchParameters params{threads_x, threads_y, threads_z,
+ blocks_x, blocks_y, blocks_z};
+ int ret = load(new_argv.size(), new_argv.data(), envp,
+ const_cast<char *>(image.getBufferStart()),
+ image.getBufferSize(), params, print_resource_usage);
- free(image);
return ret;
}
diff --git a/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp b/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
index 8cf6ea5dc9aec..c1dcce84a1c24 100644
--- a/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
+++ b/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
@@ -334,8 +334,9 @@ static hsa_status_t hsa_memcpy(void *dst, hsa_agent_t dst_agent,
return HSA_STATUS_SUCCESS;
}
-int load(int argc, char **argv, char **envp, void *image, size_t size,
- const LaunchParameters ¶ms, bool print_resource_usage) {
+int load(int argc, const char **argv, const char **envp, void *image,
+ size_t size, const LaunchParameters ¶ms,
+ bool print_resource_usage) {
// Initialize the HSA runtime used to communicate with the device.
if (hsa_status_t err = hsa_init())
handle_error(err);
diff --git a/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp b/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp
index 9c3cf3ae19b41..9fd3de2beb723 100644
--- a/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp
+++ b/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp
@@ -245,8 +245,9 @@ CUresult launch_kernel(CUmodule binary, CUstream stream,
return CUDA_SUCCESS;
}
-int load(int argc, char **argv, char **envp, void *image, size_t size,
- const LaunchParameters ¶ms, bool print_resource_usage) {
+int load(int argc, const char **argv, const char **envp, void *image,
+ size_t size, const LaunchParameters ¶ms,
+ bool print_resource_usage) {
if (CUresult err = cuInit(0))
handle_error(err);
// Obtain the first device found on the system.
|
@llvm/pr-subscribers-backend-amdgpu Author: Joseph Huber (jhuber6) ChangesSummary: Full diff: https://github.com/llvm/llvm-project/pull/101501.diff 5 Files Affected:
diff --git a/libc/utils/gpu/loader/CMakeLists.txt b/libc/utils/gpu/loader/CMakeLists.txt
index fd217a25c8a0e..60597a67ce57a 100644
--- a/libc/utils/gpu/loader/CMakeLists.txt
+++ b/libc/utils/gpu/loader/CMakeLists.txt
@@ -7,6 +7,9 @@ target_include_directories(gpu_loader PUBLIC
${LLVM_MAIN_INCLUDE_DIR}
${LLVM_BINARY_DIR}/include
)
+if(NOT LLVM_ENABLE_RTTI)
+ target_compile_options(gpu_loader PUBLIC -fno-rtti)
+endif()
find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
if(hsa-runtime64_FOUND)
diff --git a/libc/utils/gpu/loader/Loader.h b/libc/utils/gpu/loader/Loader.h
index e029816764427..2151013bae479 100644
--- a/libc/utils/gpu/loader/Loader.h
+++ b/libc/utils/gpu/loader/Loader.h
@@ -53,8 +53,9 @@ struct end_args_t {
/// Generic interface to load the \p image and launch execution of the _start
/// kernel on the target device. Copies \p argc and \p argv to the device.
/// Returns the final value of the `main` function on the device.
-int load(int argc, char **argv, char **evnp, void *image, size_t size,
- const LaunchParameters ¶ms, bool print_resource_usage);
+int load(int argc, const char **argv, const char **evnp, void *image,
+ size_t size, const LaunchParameters ¶ms,
+ bool print_resource_usage);
/// Return \p V aligned "upwards" according to \p Align.
template <typename V, typename A> inline V align_up(V val, A align) {
@@ -63,7 +64,7 @@ template <typename V, typename A> inline V align_up(V val, A align) {
/// Copy the system's argument vector to GPU memory allocated using \p alloc.
template <typename Allocator>
-void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
+void *copy_argument_vector(int argc, const char **argv, Allocator alloc) {
size_t argv_size = sizeof(char *) * (argc + 1);
size_t str_size = 0;
for (int i = 0; i < argc; ++i)
@@ -90,9 +91,9 @@ void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
/// Copy the system's environment to GPU memory allocated using \p alloc.
template <typename Allocator>
-void *copy_environment(char **envp, Allocator alloc) {
+void *copy_environment(const char **envp, Allocator alloc) {
int envc = 0;
- for (char **env = envp; *env != 0; ++env)
+ for (const char **env = envp; *env != 0; ++env)
++envc;
return copy_argument_vector(envc, envp, alloc);
diff --git a/libc/utils/gpu/loader/Main.cpp b/libc/utils/gpu/loader/Main.cpp
index a9c0b868725d0..44ed8bf58ab87 100644
--- a/libc/utils/gpu/loader/Main.cpp
+++ b/libc/utils/gpu/loader/Main.cpp
@@ -13,88 +13,97 @@
#include "Loader.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/WithColor.h"
+
#include <cstdio>
#include <cstdlib>
#include <string>
-#include <vector>
-int main(int argc, char **argv, char **envp) {
- if (argc < 2) {
- printf("USAGE: ./loader [--threads <n>, --blocks <n>, "
- "--print-resource-usage] <device_image> "
- "<args>, ...\n");
- return EXIT_SUCCESS;
- }
+using namespace llvm;
- int offset = 0;
- FILE *file = nullptr;
- char *ptr;
- LaunchParameters params = {1, 1, 1, 1, 1, 1};
- bool print_resource_usage = false;
- while (!file && ++offset < argc) {
- if (argv[offset] == std::string("--threads") ||
- argv[offset] == std::string("--threads-x")) {
- params.num_threads_x =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--threads-y")) {
- params.num_threads_y =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--threads-z")) {
- params.num_threads_z =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--blocks") ||
- argv[offset] == std::string("--blocks-x")) {
- params.num_blocks_x =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--blocks-y")) {
- params.num_blocks_y =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--blocks-z")) {
- params.num_blocks_z =
- offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
- offset++;
- continue;
- } else if (argv[offset] == std::string("--print-resource-usage")) {
- print_resource_usage = true;
- continue;
- } else {
- file = fopen(argv[offset], "r");
- if (!file) {
- fprintf(stderr, "Failed to open image file '%s'\n", argv[offset]);
- return EXIT_FAILURE;
- }
- break;
- }
- }
+static cl::OptionCategory loader_category("loader options");
+
+static cl::opt<bool> help("h", cl::desc("Alias for -help"), cl::Hidden,
+ cl::cat(loader_category));
+
+static cl::opt<unsigned>
+ threads_x("threads-x", cl::desc("Number of threads in the 'x' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ threads_y("threads-y", cl::desc("Number of threads in the 'y' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ threads_z("threads-z", cl::desc("Number of threads in the 'z' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::alias threads("threads", cl::aliasopt(threads_x),
+ cl::desc("Alias for --threads-x"),
+ cl::cat(loader_category));
+
+static cl::opt<unsigned>
+ blocks_x("blocks-x", cl::desc("Number of blocks in the 'x' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ blocks_y("blocks-y", cl::desc("Number of blocks in the 'y' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::opt<unsigned>
+ blocks_z("blocks-z", cl::desc("Number of blocks in the 'z' dimension"),
+ cl::init(1), cl::cat(loader_category));
+static cl::alias blocks("blocks", cl::aliasopt(blocks_x),
+ cl::desc("Alias for --blocks-x"),
+ cl::cat(loader_category));
- if (!file) {
- fprintf(stderr, "No image file provided\n");
- return EXIT_FAILURE;
+static cl::opt<bool>
+ print_resource_usage("print-resource-usage",
+ cl::desc("Output resource usage of launched kernels"),
+ cl::init(false), cl::cat(loader_category));
+
+static cl::opt<std::string> file(cl::Positional, cl::Required,
+ cl::desc("<gpu executable>"),
+ cl::cat(loader_category));
+static cl::list<std::string> args(cl::ConsumeAfter,
+ cl::desc("<program arguments>..."),
+ cl::cat(loader_category));
+
+[[noreturn]] void report_error(Error E) {
+ outs().flush();
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), "loader"));
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, const char **argv, const char **envp) {
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ cl::HideUnrelatedOptions(loader_category);
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A utility used to launch unit tests built for a GPU target. This is\n"
+ "intended to provide an intrface simular to cross-compiling emulators\n");
+
+ if (help) {
+ cl::PrintHelpMessage();
+ return EXIT_SUCCESS;
}
- // TODO: We should perform some validation on the file.
- fseek(file, 0, SEEK_END);
- const auto size = ftell(file);
- fseek(file, 0, SEEK_SET);
+ ErrorOr<std::unique_ptr<MemoryBuffer>> image_or_err =
+ MemoryBuffer::getFileOrSTDIN(file);
+ if (std::error_code ec = image_or_err.getError())
+ report_error(errorCodeToError(ec));
+ MemoryBufferRef image = **image_or_err;
- void *image = malloc(size * sizeof(char));
- fread(image, sizeof(char), size, file);
- fclose(file);
+ SmallVector<const char *> new_argv = {file.c_str()};
+ llvm::transform(args, std::back_inserter(new_argv),
+ [](const std::string &arg) { return arg.c_str(); });
// Drop the loader from the program arguments.
- int ret = load(argc - offset, &argv[offset], envp, image, size, params,
- print_resource_usage);
+ LaunchParameters params{threads_x, threads_y, threads_z,
+ blocks_x, blocks_y, blocks_z};
+ int ret = load(new_argv.size(), new_argv.data(), envp,
+ const_cast<char *>(image.getBufferStart()),
+ image.getBufferSize(), params, print_resource_usage);
- free(image);
return ret;
}
diff --git a/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp b/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
index 8cf6ea5dc9aec..c1dcce84a1c24 100644
--- a/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
+++ b/libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
@@ -334,8 +334,9 @@ static hsa_status_t hsa_memcpy(void *dst, hsa_agent_t dst_agent,
return HSA_STATUS_SUCCESS;
}
-int load(int argc, char **argv, char **envp, void *image, size_t size,
- const LaunchParameters ¶ms, bool print_resource_usage) {
+int load(int argc, const char **argv, const char **envp, void *image,
+ size_t size, const LaunchParameters ¶ms,
+ bool print_resource_usage) {
// Initialize the HSA runtime used to communicate with the device.
if (hsa_status_t err = hsa_init())
handle_error(err);
diff --git a/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp b/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp
index 9c3cf3ae19b41..9fd3de2beb723 100644
--- a/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp
+++ b/libc/utils/gpu/loader/nvptx/nvptx-loader.cpp
@@ -245,8 +245,9 @@ CUresult launch_kernel(CUmodule binary, CUstream stream,
return CUDA_SUCCESS;
}
-int load(int argc, char **argv, char **envp, void *image, size_t size,
- const LaunchParameters ¶ms, bool print_resource_usage) {
+int load(int argc, const char **argv, const char **envp, void *image,
+ size_t size, const LaunchParameters ¶ms,
+ bool print_resource_usage) {
if (CUresult err = cuInit(0))
handle_error(err);
// Obtain the first device found on the system.
|
For new tools you should use Opts.td: |
So CommandLine is deprecated now? That should probably be documented then. I've used the options parser in the past and found that |
Deprecated is probably too harsh, but you get most handling for free and don't need those static variables. set(LLVM_TARGET_DEFINITIONS Opts.td) |
Not really sure how to replicate the |
One smallish costumer: |
I don't see where this is doing |
I wanted to make your life easier. If you are happy with this option, then I am fine. |
No problem, the Opt interface definitely has a lot of advantages over |
Summary:
This patch removes the ad-hoc parsing that I used previously and
replaces it with the LLVM CommnadLine interface. This doesn't change any
functionality, but makes it easier to maintain.