diff options
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp')
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp | 137 |
1 files changed, 81 insertions, 56 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp index 5c9848f3c688..498308e2edbe 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -278,59 +278,20 @@ private: return FD; } - Error createSubProcessAndRunBenchmark( - StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues, - ArrayRef<const char *> ValidationCounters, - SmallVectorImpl<int64_t> &ValidationCounterValues) const { - int PipeFiles[2]; - int PipeSuccessOrErr = socketpair(AF_UNIX, SOCK_DGRAM, 0, PipeFiles); - if (PipeSuccessOrErr != 0) { - return make_error<Failure>( - "Failed to create a pipe for interprocess communication between " - "llvm-exegesis and the benchmarking subprocess: " + - Twine(strerror(errno))); - } - - SubprocessMemory SPMemory; - Error MemoryInitError = SPMemory.initializeSubprocessMemory(getpid()); - if (MemoryInitError) - return MemoryInitError; - - Error AddMemDefError = - SPMemory.addMemoryDefinition(Key.MemoryValues, getpid()); - if (AddMemDefError) - return AddMemDefError; - - pid_t ParentOrChildPID = fork(); - - if (ParentOrChildPID == -1) { - return make_error<Failure>("Failed to create child process: " + - Twine(strerror(errno))); - } - - if (ParentOrChildPID == 0) { - // We are in the child process, close the write end of the pipe. - close(PipeFiles[1]); - // Unregister handlers, signal handling is now handled through ptrace in - // the host process. - sys::unregisterHandlers(); - prepareAndRunBenchmark(PipeFiles[0], Key); - // The child process terminates in the above function, so we should never - // get to this point. - llvm_unreachable("Child process didn't exit when expected."); - } - + Error + runParentProcess(pid_t ChildPID, int WriteFD, StringRef CounterName, + SmallVectorImpl<int64_t> &CounterValues, + ArrayRef<const char *> ValidationCounters, + SmallVectorImpl<int64_t> &ValidationCounterValues) const { const ExegesisTarget &ET = State.getExegesisTarget(); - auto CounterOrError = ET.createCounter( - CounterName, State, ValidationCounters, ParentOrChildPID); + auto CounterOrError = + ET.createCounter(CounterName, State, ValidationCounters, ChildPID); if (!CounterOrError) return CounterOrError.takeError(); pfm::CounterGroup *Counter = CounterOrError.get().get(); - close(PipeFiles[0]); - // Make sure to attach to the process (and wait for the sigstop to be // delivered and for the process to continue) before we write to the counter // file descriptor. Attaching to the process before writing to the socket @@ -338,30 +299,30 @@ private: // attach afterwards, the subprocess might exit before we get to the attach // call due to effects like scheduler contention, introducing transient // failures. - if (ptrace(PTRACE_ATTACH, ParentOrChildPID, NULL, NULL) != 0) + if (ptrace(PTRACE_ATTACH, ChildPID, NULL, NULL) != 0) return make_error<Failure>("Failed to attach to the child process: " + Twine(strerror(errno))); - if (wait(NULL) == -1) { + if (waitpid(ChildPID, NULL, 0) == -1) { return make_error<Failure>( "Failed to wait for child process to stop after attaching: " + Twine(strerror(errno))); } - if (ptrace(PTRACE_CONT, ParentOrChildPID, NULL, NULL) != 0) + if (ptrace(PTRACE_CONT, ChildPID, NULL, NULL) != 0) return make_error<Failure>( "Failed to continue execution of the child process: " + Twine(strerror(errno))); int CounterFileDescriptor = Counter->getFileDescriptor(); Error SendError = - sendFileDescriptorThroughSocket(PipeFiles[1], CounterFileDescriptor); + sendFileDescriptorThroughSocket(WriteFD, CounterFileDescriptor); if (SendError) return SendError; int ChildStatus; - if (wait(&ChildStatus) == -1) { + if (waitpid(ChildPID, &ChildStatus, 0) == -1) { return make_error<Failure>( "Waiting for the child process to complete failed: " + Twine(strerror(errno))); @@ -395,12 +356,25 @@ private: // An error was encountered running the snippet, process it siginfo_t ChildSignalInfo; - if (ptrace(PTRACE_GETSIGINFO, ParentOrChildPID, NULL, &ChildSignalInfo) == - -1) { + if (ptrace(PTRACE_GETSIGINFO, ChildPID, NULL, &ChildSignalInfo) == -1) { return make_error<Failure>("Getting signal info from the child failed: " + Twine(strerror(errno))); } + // Send SIGKILL rather than SIGTERM as the child process has no SIGTERM + // handlers to run, and calling SIGTERM would mean that ptrace will force + // it to block in the signal-delivery-stop for the SIGSEGV/other signals, + // and upon exit. + if (kill(ChildPID, SIGKILL) == -1) + return make_error<Failure>("Failed to kill child benchmarking proces: " + + Twine(strerror(errno))); + + // Wait for the process to exit so that there are no zombie processes left + // around. + if (waitpid(ChildPID, NULL, 0) == -1) + return make_error<Failure>("Failed to wait for process to die: " + + Twine(strerror(errno))); + if (ChildSignalInfo.si_signo == SIGSEGV) return make_error<SnippetSegmentationFault>( reinterpret_cast<intptr_t>(ChildSignalInfo.si_addr)); @@ -408,6 +382,57 @@ private: return make_error<SnippetSignal>(ChildSignalInfo.si_signo); } + Error createSubProcessAndRunBenchmark( + StringRef CounterName, SmallVectorImpl<int64_t> &CounterValues, + ArrayRef<const char *> ValidationCounters, + SmallVectorImpl<int64_t> &ValidationCounterValues) const { + int PipeFiles[2]; + int PipeSuccessOrErr = socketpair(AF_UNIX, SOCK_DGRAM, 0, PipeFiles); + if (PipeSuccessOrErr != 0) { + return make_error<Failure>( + "Failed to create a pipe for interprocess communication between " + "llvm-exegesis and the benchmarking subprocess: " + + Twine(strerror(errno))); + } + + SubprocessMemory SPMemory; + Error MemoryInitError = SPMemory.initializeSubprocessMemory(getpid()); + if (MemoryInitError) + return MemoryInitError; + + Error AddMemDefError = + SPMemory.addMemoryDefinition(Key.MemoryValues, getpid()); + if (AddMemDefError) + return AddMemDefError; + + long ParentTID = SubprocessMemory::getCurrentTID(); + pid_t ParentOrChildPID = fork(); + + if (ParentOrChildPID == -1) { + return make_error<Failure>("Failed to create child process: " + + Twine(strerror(errno))); + } + + if (ParentOrChildPID == 0) { + // We are in the child process, close the write end of the pipe. + close(PipeFiles[1]); + // Unregister handlers, signal handling is now handled through ptrace in + // the host process. + sys::unregisterHandlers(); + runChildSubprocess(PipeFiles[0], Key, ParentTID); + // The child process terminates in the above function, so we should never + // get to this point. + llvm_unreachable("Child process didn't exit when expected."); + } + + // Close the read end of the pipe as we only need to write to the subprocess + // from the parent process. + close(PipeFiles[0]); + return runParentProcess(ParentOrChildPID, PipeFiles[1], CounterName, + CounterValues, ValidationCounters, + ValidationCounterValues); + } + void disableCoreDumps() const { struct rlimit rlim; @@ -415,8 +440,8 @@ private: setrlimit(RLIMIT_CORE, &rlim); } - [[noreturn]] void prepareAndRunBenchmark(int Pipe, - const BenchmarkKey &Key) const { + [[noreturn]] void runChildSubprocess(int Pipe, const BenchmarkKey &Key, + long ParentTID) const { // Disable core dumps in the child process as otherwise everytime we // encounter an execution failure like a segmentation fault, we will create // a core dump. We report the information directly rather than require the @@ -473,7 +498,7 @@ private: Expected<int> AuxMemFDOrError = SubprocessMemory::setupAuxiliaryMemoryInSubprocess( - Key.MemoryValues, ParentPID, CounterFileDescriptor); + Key.MemoryValues, ParentPID, ParentTID, CounterFileDescriptor); if (!AuxMemFDOrError) exit(ChildProcessExitCodeE::AuxiliaryMemorySetupFailed); |
