|
25 | 25 | #include "llvm/Support/FileSystem.h"
|
26 | 26 | #include "llvm/Support/MemoryBuffer.h"
|
27 | 27 | #include "llvm/Support/Program.h"
|
28 |
| -#include "llvm/Support/Signals.h" |
29 |
| - |
30 |
| -#ifdef __linux__ |
31 |
| -#ifdef HAVE_LIBPFM |
32 |
| -#include <perfmon/perf_event.h> |
33 |
| -#endif |
34 |
| -#include <sys/mman.h> |
35 |
| -#include <sys/ptrace.h> |
36 |
| -#include <sys/syscall.h> |
37 |
| -#include <sys/wait.h> |
38 |
| -#include <unistd.h> |
39 |
| -#endif // __linux__ |
40 | 28 |
|
41 | 29 | namespace llvm {
|
42 | 30 | namespace exegesis {
|
@@ -141,182 +129,6 @@ class InProcessFunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
|
141 | 129 | const ExecutableFunction Function;
|
142 | 130 | BenchmarkRunner::ScratchSpace *const Scratch;
|
143 | 131 | };
|
144 |
| - |
145 |
| -#ifdef __linux__ |
146 |
| -// The following class implements a function executor that executes the |
147 |
| -// benchmark code within a subprocess rather than within the main llvm-exegesis |
148 |
| -// process. This allows for much more control over the execution context of the |
149 |
| -// snippet, particularly with regard to memory. This class performs all the |
150 |
| -// necessary functions to create the subprocess, execute the snippet in the |
151 |
| -// subprocess, and report results/handle errors. |
152 |
| -class SubProcessFunctionExecutorImpl |
153 |
| - : public BenchmarkRunner::FunctionExecutor { |
154 |
| -public: |
155 |
| - SubProcessFunctionExecutorImpl(const LLVMState &State, |
156 |
| - object::OwningBinary<object::ObjectFile> Obj, |
157 |
| - const BenchmarkKey &Key) |
158 |
| - : State(State), Function(State.createTargetMachine(), std::move(Obj)), |
159 |
| - Key(Key) {} |
160 |
| - |
161 |
| -private: |
162 |
| - enum ChildProcessExitCodeE { |
163 |
| - CounterFDReadFailed = 1, |
164 |
| - TranslatingCounterFDFailed |
165 |
| - }; |
166 |
| - |
167 |
| - StringRef childProcessExitCodeToString(int ExitCode) const { |
168 |
| - switch (ExitCode) { |
169 |
| - case ChildProcessExitCodeE::CounterFDReadFailed: |
170 |
| - return "Counter file descriptor read failed"; |
171 |
| - case ChildProcessExitCodeE::TranslatingCounterFDFailed: |
172 |
| - return "Translating counter file descriptor into a file descriptor in " |
173 |
| - "the child process failed. This might be due running an older " |
174 |
| - "Linux kernel that doesn't support the pidfd_getfd system call " |
175 |
| - "(anything before Linux 5.6)."; |
176 |
| - default: |
177 |
| - return "Child process returned with unknown exit code"; |
178 |
| - } |
179 |
| - } |
180 |
| - |
181 |
| - Error createSubProcessAndRunBenchmark( |
182 |
| - StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues) const { |
183 |
| - int PipeFiles[2]; |
184 |
| - int PipeSuccessOrErr = pipe(PipeFiles); |
185 |
| - if (PipeSuccessOrErr != 0) { |
186 |
| - return make_error<Failure>( |
187 |
| - "Failed to create a pipe for interprocess communication between " |
188 |
| - "llvm-exegesis and the benchmarking subprocess"); |
189 |
| - } |
190 |
| - |
191 |
| - pid_t ParentOrChildPID = fork(); |
192 |
| - if (ParentOrChildPID == 0) { |
193 |
| - // We are in the child process, close the write end of the pipe |
194 |
| - close(PipeFiles[1]); |
195 |
| - // Unregister handlers, signal handling is now handled through ptrace in |
196 |
| - // the host process |
197 |
| - llvm::sys::unregisterHandlers(); |
198 |
| - prepareAndRunBenchmark(PipeFiles[0], Key); |
199 |
| - // The child process terminates in the above function, so we should never |
200 |
| - // get to this point. |
201 |
| - llvm_unreachable("Child process didn't exit when expected."); |
202 |
| - } |
203 |
| - |
204 |
| - const ExegesisTarget &ET = State.getExegesisTarget(); |
205 |
| - auto CounterOrError = |
206 |
| - ET.createCounter(CounterName, State, ParentOrChildPID); |
207 |
| - |
208 |
| - if (!CounterOrError) |
209 |
| - return CounterOrError.takeError(); |
210 |
| - |
211 |
| - pfm::Counter *Counter = CounterOrError.get().get(); |
212 |
| - |
213 |
| - close(PipeFiles[0]); |
214 |
| - |
215 |
| - int CounterFileDescriptor = Counter->getFileDescriptor(); |
216 |
| - ssize_t BytesWritten = |
217 |
| - write(PipeFiles[1], &CounterFileDescriptor, sizeof(int)); |
218 |
| - |
219 |
| - if (BytesWritten != sizeof(int)) |
220 |
| - return make_error<Failure>("Writing peformance counter file descriptor " |
221 |
| - "to child process failed: " + |
222 |
| - Twine(strerror(errno))); |
223 |
| - |
224 |
| - if (ptrace(PTRACE_SEIZE, ParentOrChildPID, NULL, NULL) != 0) |
225 |
| - return make_error<Failure>("Failed to seize the child process: " + |
226 |
| - Twine(strerror(errno))); |
227 |
| - |
228 |
| - int ChildStatus; |
229 |
| - if (wait(&ChildStatus) == -1) { |
230 |
| - return make_error<Failure>( |
231 |
| - "Waiting for the child process to complete failed: " + |
232 |
| - Twine(strerror(errno))); |
233 |
| - } |
234 |
| - |
235 |
| - if (WIFEXITED(ChildStatus)) { |
236 |
| - int ChildExitCode = WEXITSTATUS(ChildStatus); |
237 |
| - if (ChildExitCode == 0) { |
238 |
| - // The child exited succesfully, read counter values and return |
239 |
| - // success |
240 |
| - CounterValues[0] = Counter->read(); |
241 |
| - return Error::success(); |
242 |
| - } |
243 |
| - // The child exited, but not successfully |
244 |
| - return make_error<SnippetCrash>( |
245 |
| - "Child benchmarking process exited with non-zero exit code: " + |
246 |
| - childProcessExitCodeToString(ChildExitCode)); |
247 |
| - } |
248 |
| - |
249 |
| - // An error was encountered running the snippet, process it |
250 |
| - siginfo_t ChildSignalInfo; |
251 |
| - if (ptrace(PTRACE_GETSIGINFO, ParentOrChildPID, NULL, &ChildSignalInfo) == |
252 |
| - -1) { |
253 |
| - return make_error<Failure>("Getting signal info from the child failed: " + |
254 |
| - Twine(strerror(errno))); |
255 |
| - } |
256 |
| - |
257 |
| - return make_error<SnippetCrash>( |
258 |
| - "The benchmarking subprocess sent unexpected signal: " + |
259 |
| - Twine(strsignal(ChildSignalInfo.si_signo))); |
260 |
| - } |
261 |
| - |
262 |
| - [[noreturn]] void prepareAndRunBenchmark(int Pipe, |
263 |
| - const BenchmarkKey &Key) const { |
264 |
| - // The following occurs within the benchmarking subprocess |
265 |
| - |
266 |
| - int ParentCounterFileDescriptor = -1; |
267 |
| - ssize_t BytesRead = read(Pipe, &ParentCounterFileDescriptor, sizeof(int)); |
268 |
| - |
269 |
| - if (BytesRead != sizeof(int)) { |
270 |
| - exit(ChildProcessExitCodeE::CounterFDReadFailed); |
271 |
| - } |
272 |
| - |
273 |
| - // Make sure the following two syscalls are defined on the platform that |
274 |
| - // we're building on as they were introduced to the kernel fairly recently |
275 |
| - // (v5.6 for the second one). |
276 |
| -#if defined SYS_pidfd_open && defined SYS_pidfd_getfd |
277 |
| - pid_t ParentPID = getppid(); |
278 |
| - |
279 |
| - int ParentPIDFD = syscall(SYS_pidfd_open, ParentPID, 0); |
280 |
| - int CounterFileDescriptor = |
281 |
| - syscall(SYS_pidfd_getfd, ParentPIDFD, ParentCounterFileDescriptor, 0); |
282 |
| -#else |
283 |
| - int CounterFileDescriptor = 0; |
284 |
| - exit(ChildProcessExitCodeE::TranslatingCounterFDFailed); |
285 |
| -#endif |
286 |
| - |
287 |
| - if (CounterFileDescriptor == -1) { |
288 |
| - exit(ChildProcessExitCodeE::TranslatingCounterFDFailed); |
289 |
| - } |
290 |
| - |
291 |
| -#ifdef HAVE_LIBPFM |
292 |
| - ioctl(CounterFileDescriptor, PERF_EVENT_IOC_RESET); |
293 |
| -#endif |
294 |
| - this->Function(nullptr); |
295 |
| -#ifdef HAVE_LIBPFM |
296 |
| - ioctl(CounterFileDescriptor, PERF_EVENT_IOC_DISABLE); |
297 |
| -#endif |
298 |
| - |
299 |
| - exit(0); |
300 |
| - } |
301 |
| - |
302 |
| - Expected<llvm::SmallVector<int64_t, 4>> |
303 |
| - runWithCounter(StringRef CounterName) const override { |
304 |
| - SmallVector<int64_t, 4> Value(1, 0); |
305 |
| - Error PossibleBenchmarkError = |
306 |
| - createSubProcessAndRunBenchmark(CounterName, Value); |
307 |
| - |
308 |
| - if (PossibleBenchmarkError) { |
309 |
| - return std::move(PossibleBenchmarkError); |
310 |
| - } |
311 |
| - |
312 |
| - return Value; |
313 |
| - } |
314 |
| - |
315 |
| - const LLVMState &State; |
316 |
| - const ExecutableFunction Function; |
317 |
| - const BenchmarkKey &Key; |
318 |
| -}; |
319 |
| -#endif // __linux__ |
320 | 132 | } // namespace
|
321 | 133 |
|
322 | 134 | Expected<SmallString<0>> BenchmarkRunner::assembleSnippet(
|
@@ -389,14 +201,6 @@ BenchmarkRunner::createFunctionExecutor(
|
389 | 201 | case ExecutionModeE::InProcess:
|
390 | 202 | return std::make_unique<InProcessFunctionExecutorImpl>(
|
391 | 203 | State, std::move(ObjectFile), Scratch.get());
|
392 |
| - case ExecutionModeE::SubProcess: |
393 |
| -#ifdef __linux__ |
394 |
| - return std::make_unique<SubProcessFunctionExecutorImpl>( |
395 |
| - State, std::move(ObjectFile), Key); |
396 |
| -#else |
397 |
| - return make_error<Failure>( |
398 |
| - "The subprocess execution mode is only supported on Linux"); |
399 |
| -#endif |
400 | 204 | }
|
401 | 205 | llvm_unreachable("ExecutionMode is outside expected range");
|
402 | 206 | }
|
|
0 commit comments