16
16
#include " llvm/BinaryFormat/Magic.h"
17
17
#include " llvm/Support/CommandLine.h"
18
18
#include " llvm/Support/Error.h"
19
+ #include " llvm/Support/FileSystem.h"
19
20
#include " llvm/Support/MemoryBuffer.h"
21
+ #include " llvm/Support/Path.h"
20
22
#include " llvm/Support/Signals.h"
21
23
#include " llvm/Support/WithColor.h"
22
24
25
+ #include < cerrno>
23
26
#include < cstdio>
24
27
#include < cstdlib>
28
+ #include < cstring>
25
29
#include < string>
30
+ #include < sys/file.h>
26
31
27
32
using namespace llvm ;
28
33
@@ -62,6 +67,12 @@ static cl::opt<bool>
62
67
cl::desc (" Output resource usage of launched kernels" ),
63
68
cl::init(false ), cl::cat(loader_category));
64
69
70
+ static cl::opt<bool >
71
+ no_parallelism (" no-parallelism" ,
72
+ cl::desc (" Allows only a single process to use the GPU at a "
73
+ " time. Useful to suppress out-of-resource errors" ),
74
+ cl::init(false ), cl::cat(loader_category));
75
+
65
76
static cl::opt<std::string> file (cl::Positional, cl::Required,
66
77
cl::desc (" <gpu executable>" ),
67
78
cl::cat(loader_category));
@@ -75,6 +86,12 @@ static cl::list<std::string> args(cl::ConsumeAfter,
75
86
exit (EXIT_FAILURE);
76
87
}
77
88
89
+ std::string get_main_executable (const char *name) {
90
+ void *ptr = (void *)(intptr_t )&get_main_executable;
91
+ auto cow_path = sys::fs::getMainExecutable (name, ptr);
92
+ return sys::path::parent_path (cow_path).str ();
93
+ }
94
+
78
95
int main (int argc, const char **argv, const char **envp) {
79
96
sys::PrintStackTraceOnErrorSignal (argv[0 ]);
80
97
cl::HideUnrelatedOptions (loader_category);
@@ -98,12 +115,28 @@ int main(int argc, const char **argv, const char **envp) {
98
115
llvm::transform (args, std::back_inserter (new_argv),
99
116
[](const std::string &arg) { return arg.c_str (); });
100
117
118
+ // Claim a file lock on the executable so only a single process can enter this
119
+ // region if requested. This prevents the loader from spurious failures.
120
+ int fd = -1 ;
121
+ if (no_parallelism) {
122
+ fd = open (get_main_executable (argv[0 ]).c_str (), O_RDONLY);
123
+ if (flock (fd, LOCK_EX) == -1 )
124
+ report_error (createStringError (" Failed to lock '%s': %s" , argv[0 ],
125
+ strerror (errno)));
126
+ }
127
+
101
128
// Drop the loader from the program arguments.
102
129
LaunchParameters params{threads_x, threads_y, threads_z,
103
130
blocks_x, blocks_y, blocks_z};
104
131
int ret = load (new_argv.size (), new_argv.data (), envp,
105
132
const_cast <char *>(image.getBufferStart ()),
106
133
image.getBufferSize (), params, print_resource_usage);
107
134
135
+ if (no_parallelism) {
136
+ if (flock (fd, LOCK_UN) == -1 )
137
+ report_error (createStringError (" Failed to unlock '%s': %s" , argv[0 ],
138
+ strerror (errno)));
139
+ }
140
+
108
141
return ret;
109
142
}
0 commit comments