acln0 / perf

tentative golang.org/x/sys/unix/linux/perf package
30 stars 6 forks source link

Idea: perf.Command #3

Closed pwaller closed 5 years ago

pwaller commented 5 years ago

One use case I have is to measure another process I want to start from Go. A slight challenge I immediately came up against was how to start the measurement before the process starts doing useful work.

Assumptions:

Illustration of the issue

cmd := exec.Command()
cmd.Start() // required to get the Pid of the subprocess
... := perf.Open(..., cmd.Process.Pid, ...) // by the time we get here, the process may have already done some of the work we want to measure.

Idea

So my idea is to have some sort of user interface which takes the process to run. Either the *exec.Cmd, or arguments that are passed to `exec.Command (though I guess that would be less flexible).

First there is a challenge to solve: How to create a process in Go such that it is in the stopped state, so that you can start measurement before it does work you want to measure? Searching around I'm surprised there is not an immediate solution to this. Ptrace on SysProcAttr might do it - I haven't checked yet.

The next best thing I can think of is to rig up a shell process along the lines of sh -c 'kill -STOP $$; exec "$@"' -- ....

Whatever the solution is, it could be wrapped up in perf.Command or alike.

pwaller commented 5 years ago

ptrace docs:

The request

           ptrace(PTRACE_TRACEME, 0, 0, 0);

       turns the calling thread into a tracee.  The thread continues to run (doesn't enter ptrace-stop). 

However it does say:

       If  the  PTRACE_O_TRACEEXEC  option  is not in effect for the execing tracee, and if the tracee was PTRACE_ATTACHed rather
       that PTRACE_SEIZEd, the kernel delivers an extra SIGTRAP to the tracee after execve(2) returns.  This is an ordinary  sig‐
       nal (similar to one which can be generated by kill -TRAP), not a special kind of ptrace-stop.  Employing PTRACE_GETSIGINFO
       for this signal returns si_code set to 0 (SI_USER).  This signal may be blocked by signal mask, and thus may be  delivered
       (much) later.

I think this is saying that you'll get a SIGTRAP immediately after execve, which can be continued with SIGCONT.

So that seems to be the way to do it. Slightly unfortunate to need to use ptrace because it may require further elevated permissions, but I guess the least invasive thing to do is:

  1. Start process using Ptrace: true
  2. Start measurement.
  3. Do PTRACE_DETACH.

Is such hackery suitable for a perf.Command library function?

acln0 commented 5 years ago

That sounds reasonable to me. One question: where does the PTRACE_ATTACH fit in?

acln0 commented 5 years ago

Ah, I think there is no need for that. Never mind. Sorry for the noise.