[libc-commits] [libc] 5e32698 - [libc] Use LLVM CommandLine for loader tool (#101501)

via libc-commits libc-commits at lists.llvm.org
Thu Aug 1 12:07:32 PDT 2024


Author: Joseph Huber
Date: 2024-08-01T14:07:28-05:00
New Revision: 5e326983b620507940816f4c30ab4d80fa6250ad

URL: https://github.com/llvm/llvm-project/commit/5e326983b620507940816f4c30ab4d80fa6250ad
DIFF: https://github.com/llvm/llvm-project/commit/5e326983b620507940816f4c30ab4d80fa6250ad.diff

LOG: [libc] Use LLVM CommandLine for loader tool (#101501)

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.

Added: 
    

Modified: 
    libc/utils/gpu/loader/CMakeLists.txt
    libc/utils/gpu/loader/Loader.h
    libc/utils/gpu/loader/Main.cpp
    libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp
    libc/utils/gpu/loader/nvptx/nvptx-loader.cpp

Removed: 
    


################################################################################
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 &params, bool print_resource_usage);
+int load(int argc, const char **argv, const char **evnp, void *image,
+         size_t size, const LaunchParameters &params,
+         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 &params, bool print_resource_usage) {
+int load(int argc, const char **argv, const char **envp, void *image,
+         size_t size, const LaunchParameters &params,
+         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 &params, bool print_resource_usage) {
+int load(int argc, const char **argv, const char **envp, void *image,
+         size_t size, const LaunchParameters &params,
+         bool print_resource_usage) {
   if (CUresult err = cuInit(0))
     handle_error(err);
   // Obtain the first device found on the system.


        


More information about the libc-commits mailing list