Skip to content

Commit

Permalink
python: Log PyPerf stdout+stderr after a restart (#634)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jongy authored Dec 20, 2022
1 parent edd2ffd commit 92a57b7
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 4 deletions.
8 changes: 7 additions & 1 deletion gprofiler/profilers/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,13 @@ def snapshot(self) -> ProcessToProfileData:
try:
return self._ebpf_profiler.snapshot()
except PythonEbpfError as e:
logger.warning("Python eBPF profiler failed, restarting PyPerf...", exit_code=e.returncode)
assert not self._ebpf_profiler.is_running()
logger.warning(
"Python eBPF profiler failed, restarting PyPerf...",
pyperf_exit_code=e.returncode,
pyperf_stdout=e.stdout,
pyperf_stderr=e.stderr,
)
self._ebpf_profiler.start()
return {} # empty this round
else:
Expand Down
12 changes: 9 additions & 3 deletions gprofiler/profilers/python_ebpf.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ def start(self) -> None:
self.process = process

def _dump(self) -> Path:
assert self.process is not None, "profiling not started!"
assert self.is_running()
assert self.process is not None # for mypy
self.process.send_signal(self._DUMP_SIGNAL)

try:
Expand All @@ -215,7 +216,6 @@ def _dump(self) -> Path:
# also, makes sure its output pipe doesn't fill up.
# using read1() which performs just a single read() call and doesn't read until EOF
# (unlike Popen.communicate())
assert self.process is not None
logger.debug(f"PyPerf output: {self.process.stderr.read1()}") # type: ignore
return output
except TimeoutError:
Expand Down Expand Up @@ -252,13 +252,19 @@ def snapshot(self) -> ProcessToProfileData:

def _terminate(self) -> Optional[int]:
code = None
if self.process is not None:
if self.is_running():
assert self.process is not None # for mypy
self.process.terminate() # okay to call even if process is already dead
code = self.process.wait()
self.process = None

assert self.process is None # means we're not running
return code

def stop(self) -> None:
code = self._terminate()
if code is not None:
logger.info("Finished profiling Python processes with PyPerf")

def is_running(self) -> bool:
return self.process is not None

0 comments on commit 92a57b7

Please sign in to comment.