Skip to content

Commit 5e32698

Browse files
authored
[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.
1 parent b6b0a24 commit 5e32698

File tree

5 files changed

+95
-80
lines changed

5 files changed

+95
-80
lines changed

libc/utils/gpu/loader/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ target_include_directories(gpu_loader PUBLIC
77
${LLVM_MAIN_INCLUDE_DIR}
88
${LLVM_BINARY_DIR}/include
99
)
10+
if(NOT LLVM_ENABLE_RTTI)
11+
target_compile_options(gpu_loader PUBLIC -fno-rtti)
12+
endif()
1013

1114
find_package(hsa-runtime64 QUIET 1.2.0 HINTS ${CMAKE_INSTALL_PREFIX} PATHS /opt/rocm)
1215
if(hsa-runtime64_FOUND)

libc/utils/gpu/loader/Loader.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ struct end_args_t {
5353
/// Generic interface to load the \p image and launch execution of the _start
5454
/// kernel on the target device. Copies \p argc and \p argv to the device.
5555
/// Returns the final value of the `main` function on the device.
56-
int load(int argc, char **argv, char **evnp, void *image, size_t size,
57-
const LaunchParameters &params, bool print_resource_usage);
56+
int load(int argc, const char **argv, const char **evnp, void *image,
57+
size_t size, const LaunchParameters &params,
58+
bool print_resource_usage);
5859

5960
/// Return \p V aligned "upwards" according to \p Align.
6061
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) {
6364

6465
/// Copy the system's argument vector to GPU memory allocated using \p alloc.
6566
template <typename Allocator>
66-
void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
67+
void *copy_argument_vector(int argc, const char **argv, Allocator alloc) {
6768
size_t argv_size = sizeof(char *) * (argc + 1);
6869
size_t str_size = 0;
6970
for (int i = 0; i < argc; ++i)
@@ -90,9 +91,9 @@ void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
9091

9192
/// Copy the system's environment to GPU memory allocated using \p alloc.
9293
template <typename Allocator>
93-
void *copy_environment(char **envp, Allocator alloc) {
94+
void *copy_environment(const char **envp, Allocator alloc) {
9495
int envc = 0;
95-
for (char **env = envp; *env != 0; ++env)
96+
for (const char **env = envp; *env != 0; ++env)
9697
++envc;
9798

9899
return copy_argument_vector(envc, envp, alloc);

libc/utils/gpu/loader/Main.cpp

Lines changed: 80 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,88 +13,97 @@
1313

1414
#include "Loader.h"
1515

16+
#include "llvm/BinaryFormat/Magic.h"
17+
#include "llvm/Support/CommandLine.h"
18+
#include "llvm/Support/Error.h"
19+
#include "llvm/Support/MemoryBuffer.h"
20+
#include "llvm/Support/Signals.h"
21+
#include "llvm/Support/WithColor.h"
22+
1623
#include <cstdio>
1724
#include <cstdlib>
1825
#include <string>
19-
#include <vector>
2026

21-
int main(int argc, char **argv, char **envp) {
22-
if (argc < 2) {
23-
printf("USAGE: ./loader [--threads <n>, --blocks <n>, "
24-
"--print-resource-usage] <device_image> "
25-
"<args>, ...\n");
26-
return EXIT_SUCCESS;
27-
}
27+
using namespace llvm;
2828

29-
int offset = 0;
30-
FILE *file = nullptr;
31-
char *ptr;
32-
LaunchParameters params = {1, 1, 1, 1, 1, 1};
33-
bool print_resource_usage = false;
34-
while (!file && ++offset < argc) {
35-
if (argv[offset] == std::string("--threads") ||
36-
argv[offset] == std::string("--threads-x")) {
37-
params.num_threads_x =
38-
offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
39-
offset++;
40-
continue;
41-
} else if (argv[offset] == std::string("--threads-y")) {
42-
params.num_threads_y =
43-
offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
44-
offset++;
45-
continue;
46-
} else if (argv[offset] == std::string("--threads-z")) {
47-
params.num_threads_z =
48-
offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
49-
offset++;
50-
continue;
51-
} else if (argv[offset] == std::string("--blocks") ||
52-
argv[offset] == std::string("--blocks-x")) {
53-
params.num_blocks_x =
54-
offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
55-
offset++;
56-
continue;
57-
} else if (argv[offset] == std::string("--blocks-y")) {
58-
params.num_blocks_y =
59-
offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
60-
offset++;
61-
continue;
62-
} else if (argv[offset] == std::string("--blocks-z")) {
63-
params.num_blocks_z =
64-
offset + 1 < argc ? strtoul(argv[offset + 1], &ptr, 10) : 1;
65-
offset++;
66-
continue;
67-
} else if (argv[offset] == std::string("--print-resource-usage")) {
68-
print_resource_usage = true;
69-
continue;
70-
} else {
71-
file = fopen(argv[offset], "r");
72-
if (!file) {
73-
fprintf(stderr, "Failed to open image file '%s'\n", argv[offset]);
74-
return EXIT_FAILURE;
75-
}
76-
break;
77-
}
78-
}
29+
static cl::OptionCategory loader_category("loader options");
30+
31+
static cl::opt<bool> help("h", cl::desc("Alias for -help"), cl::Hidden,
32+
cl::cat(loader_category));
33+
34+
static cl::opt<unsigned>
35+
threads_x("threads-x", cl::desc("Number of threads in the 'x' dimension"),
36+
cl::init(1), cl::cat(loader_category));
37+
static cl::opt<unsigned>
38+
threads_y("threads-y", cl::desc("Number of threads in the 'y' dimension"),
39+
cl::init(1), cl::cat(loader_category));
40+
static cl::opt<unsigned>
41+
threads_z("threads-z", cl::desc("Number of threads in the 'z' dimension"),
42+
cl::init(1), cl::cat(loader_category));
43+
static cl::alias threads("threads", cl::aliasopt(threads_x),
44+
cl::desc("Alias for --threads-x"),
45+
cl::cat(loader_category));
46+
47+
static cl::opt<unsigned>
48+
blocks_x("blocks-x", cl::desc("Number of blocks in the 'x' dimension"),
49+
cl::init(1), cl::cat(loader_category));
50+
static cl::opt<unsigned>
51+
blocks_y("blocks-y", cl::desc("Number of blocks in the 'y' dimension"),
52+
cl::init(1), cl::cat(loader_category));
53+
static cl::opt<unsigned>
54+
blocks_z("blocks-z", cl::desc("Number of blocks in the 'z' dimension"),
55+
cl::init(1), cl::cat(loader_category));
56+
static cl::alias blocks("blocks", cl::aliasopt(blocks_x),
57+
cl::desc("Alias for --blocks-x"),
58+
cl::cat(loader_category));
7959

80-
if (!file) {
81-
fprintf(stderr, "No image file provided\n");
82-
return EXIT_FAILURE;
60+
static cl::opt<bool>
61+
print_resource_usage("print-resource-usage",
62+
cl::desc("Output resource usage of launched kernels"),
63+
cl::init(false), cl::cat(loader_category));
64+
65+
static cl::opt<std::string> file(cl::Positional, cl::Required,
66+
cl::desc("<gpu executable>"),
67+
cl::cat(loader_category));
68+
static cl::list<std::string> args(cl::ConsumeAfter,
69+
cl::desc("<program arguments>..."),
70+
cl::cat(loader_category));
71+
72+
[[noreturn]] void report_error(Error E) {
73+
outs().flush();
74+
logAllUnhandledErrors(std::move(E), WithColor::error(errs(), "loader"));
75+
exit(EXIT_FAILURE);
76+
}
77+
78+
int main(int argc, const char **argv, const char **envp) {
79+
sys::PrintStackTraceOnErrorSignal(argv[0]);
80+
cl::HideUnrelatedOptions(loader_category);
81+
cl::ParseCommandLineOptions(
82+
argc, argv,
83+
"A utility used to launch unit tests built for a GPU target. This is\n"
84+
"intended to provide an intrface simular to cross-compiling emulators\n");
85+
86+
if (help) {
87+
cl::PrintHelpMessage();
88+
return EXIT_SUCCESS;
8389
}
8490

85-
// TODO: We should perform some validation on the file.
86-
fseek(file, 0, SEEK_END);
87-
const auto size = ftell(file);
88-
fseek(file, 0, SEEK_SET);
91+
ErrorOr<std::unique_ptr<MemoryBuffer>> image_or_err =
92+
MemoryBuffer::getFileOrSTDIN(file);
93+
if (std::error_code ec = image_or_err.getError())
94+
report_error(errorCodeToError(ec));
95+
MemoryBufferRef image = **image_or_err;
8996

90-
void *image = malloc(size * sizeof(char));
91-
fread(image, sizeof(char), size, file);
92-
fclose(file);
97+
SmallVector<const char *> new_argv = {file.c_str()};
98+
llvm::transform(args, std::back_inserter(new_argv),
99+
[](const std::string &arg) { return arg.c_str(); });
93100

94101
// Drop the loader from the program arguments.
95-
int ret = load(argc - offset, &argv[offset], envp, image, size, params,
96-
print_resource_usage);
102+
LaunchParameters params{threads_x, threads_y, threads_z,
103+
blocks_x, blocks_y, blocks_z};
104+
int ret = load(new_argv.size(), new_argv.data(), envp,
105+
const_cast<char *>(image.getBufferStart()),
106+
image.getBufferSize(), params, print_resource_usage);
97107

98-
free(image);
99108
return ret;
100109
}

libc/utils/gpu/loader/amdgpu/amdhsa-loader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,9 @@ static hsa_status_t hsa_memcpy(void *dst, hsa_agent_t dst_agent,
334334
return HSA_STATUS_SUCCESS;
335335
}
336336

337-
int load(int argc, char **argv, char **envp, void *image, size_t size,
338-
const LaunchParameters &params, bool print_resource_usage) {
337+
int load(int argc, const char **argv, const char **envp, void *image,
338+
size_t size, const LaunchParameters &params,
339+
bool print_resource_usage) {
339340
// Initialize the HSA runtime used to communicate with the device.
340341
if (hsa_status_t err = hsa_init())
341342
handle_error(err);

libc/utils/gpu/loader/nvptx/nvptx-loader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,9 @@ CUresult launch_kernel(CUmodule binary, CUstream stream,
245245
return CUDA_SUCCESS;
246246
}
247247

248-
int load(int argc, char **argv, char **envp, void *image, size_t size,
249-
const LaunchParameters &params, bool print_resource_usage) {
248+
int load(int argc, const char **argv, const char **envp, void *image,
249+
size_t size, const LaunchParameters &params,
250+
bool print_resource_usage) {
250251
if (CUresult err = cuInit(0))
251252
handle_error(err);
252253
// Obtain the first device found on the system.

0 commit comments

Comments
 (0)