167d78e3cSJoseph Huber //===-- Main entry into the loader interface ------------------------------===// 267d78e3cSJoseph Huber // 367d78e3cSJoseph Huber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 467d78e3cSJoseph Huber // See https://llvm.org/LICENSE.txt for license information. 567d78e3cSJoseph Huber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 667d78e3cSJoseph Huber // 767d78e3cSJoseph Huber //===----------------------------------------------------------------------===// 867d78e3cSJoseph Huber // 967d78e3cSJoseph Huber // This file opens a device image passed on the command line and passes it to 1067d78e3cSJoseph Huber // one of the loader implementations for launch. 1167d78e3cSJoseph Huber // 1267d78e3cSJoseph Huber //===----------------------------------------------------------------------===// 1367d78e3cSJoseph Huber 1467d78e3cSJoseph Huber #include "Loader.h" 1567d78e3cSJoseph Huber 165e326983SJoseph Huber #include "llvm/BinaryFormat/Magic.h" 175e326983SJoseph Huber #include "llvm/Support/CommandLine.h" 185e326983SJoseph Huber #include "llvm/Support/Error.h" 19*d1b29402SJoseph Huber #include "llvm/Support/FileSystem.h" 205e326983SJoseph Huber #include "llvm/Support/MemoryBuffer.h" 21*d1b29402SJoseph Huber #include "llvm/Support/Path.h" 225e326983SJoseph Huber #include "llvm/Support/Signals.h" 235e326983SJoseph Huber #include "llvm/Support/WithColor.h" 245e326983SJoseph Huber 25*d1b29402SJoseph Huber #include <cerrno> 2667d78e3cSJoseph Huber #include <cstdio> 2767d78e3cSJoseph Huber #include <cstdlib> 28*d1b29402SJoseph Huber #include <cstring> 29bc11bb3eSJoseph Huber #include <string> 30*d1b29402SJoseph Huber #include <sys/file.h> 3167d78e3cSJoseph Huber 325e326983SJoseph Huber using namespace llvm; 335e326983SJoseph Huber 345e326983SJoseph Huber static cl::OptionCategory loader_category("loader options"); 355e326983SJoseph Huber 365e326983SJoseph Huber static cl::opt<bool> help("h", cl::desc("Alias for -help"), cl::Hidden, 375e326983SJoseph Huber cl::cat(loader_category)); 385e326983SJoseph Huber 395e326983SJoseph Huber static cl::opt<unsigned> 405e326983SJoseph Huber threads_x("threads-x", cl::desc("Number of threads in the 'x' dimension"), 415e326983SJoseph Huber cl::init(1), cl::cat(loader_category)); 425e326983SJoseph Huber static cl::opt<unsigned> 435e326983SJoseph Huber threads_y("threads-y", cl::desc("Number of threads in the 'y' dimension"), 445e326983SJoseph Huber cl::init(1), cl::cat(loader_category)); 455e326983SJoseph Huber static cl::opt<unsigned> 465e326983SJoseph Huber threads_z("threads-z", cl::desc("Number of threads in the 'z' dimension"), 475e326983SJoseph Huber cl::init(1), cl::cat(loader_category)); 485e326983SJoseph Huber static cl::alias threads("threads", cl::aliasopt(threads_x), 495e326983SJoseph Huber cl::desc("Alias for --threads-x"), 505e326983SJoseph Huber cl::cat(loader_category)); 515e326983SJoseph Huber 525e326983SJoseph Huber static cl::opt<unsigned> 535e326983SJoseph Huber blocks_x("blocks-x", cl::desc("Number of blocks in the 'x' dimension"), 545e326983SJoseph Huber cl::init(1), cl::cat(loader_category)); 555e326983SJoseph Huber static cl::opt<unsigned> 565e326983SJoseph Huber blocks_y("blocks-y", cl::desc("Number of blocks in the 'y' dimension"), 575e326983SJoseph Huber cl::init(1), cl::cat(loader_category)); 585e326983SJoseph Huber static cl::opt<unsigned> 595e326983SJoseph Huber blocks_z("blocks-z", cl::desc("Number of blocks in the 'z' dimension"), 605e326983SJoseph Huber cl::init(1), cl::cat(loader_category)); 615e326983SJoseph Huber static cl::alias blocks("blocks", cl::aliasopt(blocks_x), 625e326983SJoseph Huber cl::desc("Alias for --blocks-x"), 635e326983SJoseph Huber cl::cat(loader_category)); 645e326983SJoseph Huber 655e326983SJoseph Huber static cl::opt<bool> 665e326983SJoseph Huber print_resource_usage("print-resource-usage", 675e326983SJoseph Huber cl::desc("Output resource usage of launched kernels"), 685e326983SJoseph Huber cl::init(false), cl::cat(loader_category)); 695e326983SJoseph Huber 70*d1b29402SJoseph Huber static cl::opt<bool> 71*d1b29402SJoseph Huber no_parallelism("no-parallelism", 72*d1b29402SJoseph Huber cl::desc("Allows only a single process to use the GPU at a " 73*d1b29402SJoseph Huber "time. Useful to suppress out-of-resource errors"), 74*d1b29402SJoseph Huber cl::init(false), cl::cat(loader_category)); 75*d1b29402SJoseph Huber 765e326983SJoseph Huber static cl::opt<std::string> file(cl::Positional, cl::Required, 775e326983SJoseph Huber cl::desc("<gpu executable>"), 785e326983SJoseph Huber cl::cat(loader_category)); 795e326983SJoseph Huber static cl::list<std::string> args(cl::ConsumeAfter, 805e326983SJoseph Huber cl::desc("<program arguments>..."), 815e326983SJoseph Huber cl::cat(loader_category)); 825e326983SJoseph Huber 835e326983SJoseph Huber [[noreturn]] void report_error(Error E) { 845e326983SJoseph Huber outs().flush(); 855e326983SJoseph Huber logAllUnhandledErrors(std::move(E), WithColor::error(errs(), "loader")); 865e326983SJoseph Huber exit(EXIT_FAILURE); 875e326983SJoseph Huber } 885e326983SJoseph Huber 89*d1b29402SJoseph Huber std::string get_main_executable(const char *name) { 90*d1b29402SJoseph Huber void *ptr = (void *)(intptr_t)&get_main_executable; 91*d1b29402SJoseph Huber auto cow_path = sys::fs::getMainExecutable(name, ptr); 92*d1b29402SJoseph Huber return sys::path::parent_path(cow_path).str(); 93*d1b29402SJoseph Huber } 94*d1b29402SJoseph Huber 955e326983SJoseph Huber int main(int argc, const char **argv, const char **envp) { 965e326983SJoseph Huber sys::PrintStackTraceOnErrorSignal(argv[0]); 975e326983SJoseph Huber cl::HideUnrelatedOptions(loader_category); 985e326983SJoseph Huber cl::ParseCommandLineOptions( 995e326983SJoseph Huber argc, argv, 1005e326983SJoseph Huber "A utility used to launch unit tests built for a GPU target. This is\n" 1015e326983SJoseph Huber "intended to provide an intrface simular to cross-compiling emulators\n"); 1025e326983SJoseph Huber 1035e326983SJoseph Huber if (help) { 1045e326983SJoseph Huber cl::PrintHelpMessage(); 10567d78e3cSJoseph Huber return EXIT_SUCCESS; 10667d78e3cSJoseph Huber } 10767d78e3cSJoseph Huber 1085e326983SJoseph Huber ErrorOr<std::unique_ptr<MemoryBuffer>> image_or_err = 1095e326983SJoseph Huber MemoryBuffer::getFileOrSTDIN(file); 1105e326983SJoseph Huber if (std::error_code ec = image_or_err.getError()) 1115e326983SJoseph Huber report_error(errorCodeToError(ec)); 1125e326983SJoseph Huber MemoryBufferRef image = **image_or_err; 11367d78e3cSJoseph Huber 1145e326983SJoseph Huber SmallVector<const char *> new_argv = {file.c_str()}; 1155e326983SJoseph Huber llvm::transform(args, std::back_inserter(new_argv), 1165e326983SJoseph Huber [](const std::string &arg) { return arg.c_str(); }); 11767d78e3cSJoseph Huber 118*d1b29402SJoseph Huber // Claim a file lock on the executable so only a single process can enter this 119*d1b29402SJoseph Huber // region if requested. This prevents the loader from spurious failures. 120*d1b29402SJoseph Huber int fd = -1; 121*d1b29402SJoseph Huber if (no_parallelism) { 122*d1b29402SJoseph Huber fd = open(get_main_executable(argv[0]).c_str(), O_RDONLY); 123*d1b29402SJoseph Huber if (flock(fd, LOCK_EX) == -1) 124*d1b29402SJoseph Huber report_error(createStringError("Failed to lock '%s': %s", argv[0], 125*d1b29402SJoseph Huber strerror(errno))); 126*d1b29402SJoseph Huber } 127*d1b29402SJoseph Huber 12867d78e3cSJoseph Huber // Drop the loader from the program arguments. 1295e326983SJoseph Huber LaunchParameters params{threads_x, threads_y, threads_z, 1305e326983SJoseph Huber blocks_x, blocks_y, blocks_z}; 1315e326983SJoseph Huber int ret = load(new_argv.size(), new_argv.data(), envp, 1325e326983SJoseph Huber const_cast<char *>(image.getBufferStart()), 1335e326983SJoseph Huber image.getBufferSize(), params, print_resource_usage); 13467d78e3cSJoseph Huber 135*d1b29402SJoseph Huber if (no_parallelism) { 136*d1b29402SJoseph Huber if (flock(fd, LOCK_UN) == -1) 137*d1b29402SJoseph Huber report_error(createStringError("Failed to unlock '%s': %s", argv[0], 138*d1b29402SJoseph Huber strerror(errno))); 139*d1b29402SJoseph Huber } 140*d1b29402SJoseph Huber 14167d78e3cSJoseph Huber return ret; 14267d78e3cSJoseph Huber } 143