Skip to content

Commit 1ff0cbe

Browse files
jeffhostetlerdscho
authored andcommitted
trace2: add trace2_child_ready() to report on background children
Create "child_ready" event to capture the state of a child process created in the background. When a child command is started a "child_start" event is generated in the Trace2 log. For normal synchronous children, a "child_exit" event is later generated when the child exits or is terminated. The two events include information, such as the "child_id" and "pid", to allow post analysis to match-up the command line and exit status. When a child is started in the background (and may outlive the parent process), it is not possible for the parent to emit a "child_exit" event. Create a new "child_ready" event to indicate whether the child was successfully started. Also include the "child_id" and "pid" to allow similar post processing. This will be used in a later commit with the new "start_bg_command()". Signed-off-by: Jeff Hostetler <[email protected]>
1 parent 2d9a659 commit 1ff0cbe

File tree

7 files changed

+152
-0
lines changed

7 files changed

+152
-0
lines changed

Documentation/technical/api-trace2.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,46 @@ stopping after the waitpid() and includes OS process creation overhead).
599599
So this time will be slightly larger than the atexit time reported by
600600
the child process itself.
601601

602+
`"child_ready"`::
603+
This event is generated after the current process has started
604+
a background process and released all handles to it.
605+
+
606+
------------
607+
{
608+
"event":"child_ready",
609+
...
610+
"child_id":2,
611+
"pid":14708, # child PID
612+
"ready":"ready", # child ready state
613+
"t_rel":0.110605 # observed run-time of child process
614+
}
615+
------------
616+
+
617+
Note that the session-id of the child process is not available to
618+
the current/spawning process, so the child's PID is reported here as
619+
a hint for post-processing. (But it is only a hint because the child
620+
process may be a shell script which doesn't have a session-id.)
621+
+
622+
This event is generated after the child is started in the background
623+
and given a little time to boot up and start working. If the child
624+
startups normally and while the parent is still waiting, the "ready"
625+
field will have the value "ready".
626+
If the child is too slow to start and the parent times out, the field
627+
will have the value "timeout".
628+
If the child starts but the parent is unable to probe it, the field
629+
will have the value "error".
630+
+
631+
After the parent process emits this event, it will release all of its
632+
handles to the child process and treat the child as a background
633+
daemon. So even if the child does eventually finish booting up,
634+
the parent will not emit an updated event.
635+
+
636+
Note that the `t_rel` field contains the observed run time in seconds
637+
when the parent released the child process into the background.
638+
The child is assumed to be a long-running daemon process and may
639+
outlive the parent process. So the parent's child event times should
640+
not be compared to the child's atexit times.
641+
602642
`"exec"`::
603643
This event is generated before git attempts to `exec()`
604644
another command rather than starting a child process.

trace2.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,37 @@ void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
381381
us_elapsed_child);
382382
}
383383

384+
void trace2_child_ready_fl(const char *file, int line,
385+
struct child_process *cmd,
386+
const char *ready)
387+
{
388+
struct tr2_tgt *tgt_j;
389+
int j;
390+
uint64_t us_now;
391+
uint64_t us_elapsed_absolute;
392+
uint64_t us_elapsed_child;
393+
394+
if (!trace2_enabled)
395+
return;
396+
397+
us_now = getnanotime() / 1000;
398+
us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
399+
400+
if (cmd->trace2_child_us_start)
401+
us_elapsed_child = us_now - cmd->trace2_child_us_start;
402+
else
403+
us_elapsed_child = 0;
404+
405+
for_each_wanted_builtin (j, tgt_j)
406+
if (tgt_j->pfn_child_ready_fl)
407+
tgt_j->pfn_child_ready_fl(file, line,
408+
us_elapsed_absolute,
409+
cmd->trace2_child_id,
410+
cmd->pid,
411+
ready,
412+
us_elapsed_child);
413+
}
414+
384415
int trace2_exec_fl(const char *file, int line, const char *exe,
385416
const char **argv)
386417
{

trace2.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,31 @@ void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
243243
#define trace2_child_exit(cmd, code) \
244244
trace2_child_exit_fl(__FILE__, __LINE__, (cmd), (code))
245245

246+
/**
247+
* Emits a "child_ready" message containing the "child-id" and a flag
248+
* indicating whether the child was considered "ready" when we
249+
* released it.
250+
*
251+
* This function should be called after starting a daemon process in
252+
* the background (and after giving it sufficient time to boot
253+
* up) to indicate that we no longer control or own it.
254+
*
255+
* The "ready" argument should contain one of { "ready", "timeout",
256+
* "error" } to indicate the state of the running daemon when we
257+
* released it.
258+
*
259+
* If the daemon process fails to start or it exits or is terminated
260+
* while we are still waiting for it, the caller should emit a
261+
* regular "child_exit" to report the normal process exit information.
262+
*
263+
*/
264+
void trace2_child_ready_fl(const char *file, int line,
265+
struct child_process *cmd,
266+
const char *ready);
267+
268+
#define trace2_child_ready(cmd, ready) \
269+
trace2_child_ready_fl(__FILE__, __LINE__, (cmd), (ready))
270+
246271
/**
247272
* Emit an 'exec' event prior to calling one of exec(), execv(),
248273
* execvp(), and etc. On Unix-derived systems, this will be the

trace2/tr2_tgt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ typedef void(tr2_tgt_evt_child_exit_fl_t)(const char *file, int line,
4343
uint64_t us_elapsed_absolute, int cid,
4444
int pid, int code,
4545
uint64_t us_elapsed_child);
46+
typedef void(tr2_tgt_evt_child_ready_fl_t)(const char *file, int line,
47+
uint64_t us_elapsed_absolute,
48+
int cid, int pid, const char *ready,
49+
uint64_t us_elapsed_child);
4650

4751
typedef void(tr2_tgt_evt_thread_start_fl_t)(const char *file, int line,
4852
uint64_t us_elapsed_absolute);
@@ -113,6 +117,7 @@ struct tr2_tgt {
113117
tr2_tgt_evt_alias_fl_t *pfn_alias_fl;
114118
tr2_tgt_evt_child_start_fl_t *pfn_child_start_fl;
115119
tr2_tgt_evt_child_exit_fl_t *pfn_child_exit_fl;
120+
tr2_tgt_evt_child_ready_fl_t *pfn_child_ready_fl;
116121
tr2_tgt_evt_thread_start_fl_t *pfn_thread_start_fl;
117122
tr2_tgt_evt_thread_exit_fl_t *pfn_thread_exit_fl;
118123
tr2_tgt_evt_exec_fl_t *pfn_exec_fl;

trace2/tr2_tgt_event.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,27 @@ static void fn_child_exit_fl(const char *file, int line,
363363
jw_release(&jw);
364364
}
365365

366+
static void fn_child_ready_fl(const char *file, int line,
367+
uint64_t us_elapsed_absolute, int cid, int pid,
368+
const char *ready, uint64_t us_elapsed_child)
369+
{
370+
const char *event_name = "child_ready";
371+
struct json_writer jw = JSON_WRITER_INIT;
372+
double t_rel = (double)us_elapsed_child / 1000000.0;
373+
374+
jw_object_begin(&jw, 0);
375+
event_fmt_prepare(event_name, file, line, NULL, &jw);
376+
jw_object_intmax(&jw, "child_id", cid);
377+
jw_object_intmax(&jw, "pid", pid);
378+
jw_object_string(&jw, "ready", ready);
379+
jw_object_double(&jw, "t_rel", 6, t_rel);
380+
jw_end(&jw);
381+
382+
tr2_dst_write_line(&tr2dst_event, &jw.json);
383+
384+
jw_release(&jw);
385+
}
386+
366387
static void fn_thread_start_fl(const char *file, int line,
367388
uint64_t us_elapsed_absolute)
368389
{
@@ -589,6 +610,7 @@ struct tr2_tgt tr2_tgt_event = {
589610
fn_alias_fl,
590611
fn_child_start_fl,
591612
fn_child_exit_fl,
613+
fn_child_ready_fl,
592614
fn_thread_start_fl,
593615
fn_thread_exit_fl,
594616
fn_exec_fl,

trace2/tr2_tgt_normal.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,19 @@ static void fn_child_exit_fl(const char *file, int line,
233233
strbuf_release(&buf_payload);
234234
}
235235

236+
static void fn_child_ready_fl(const char *file, int line,
237+
uint64_t us_elapsed_absolute, int cid, int pid,
238+
const char *ready, uint64_t us_elapsed_child)
239+
{
240+
struct strbuf buf_payload = STRBUF_INIT;
241+
double elapsed = (double)us_elapsed_child / 1000000.0;
242+
243+
strbuf_addf(&buf_payload, "child_ready[%d] pid:%d ready:%s elapsed:%.6f",
244+
cid, pid, ready, elapsed);
245+
normal_io_write_fl(file, line, &buf_payload);
246+
strbuf_release(&buf_payload);
247+
}
248+
236249
static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
237250
int exec_id, const char *exe, const char **argv)
238251
{
@@ -311,6 +324,7 @@ struct tr2_tgt tr2_tgt_normal = {
311324
fn_alias_fl,
312325
fn_child_start_fl,
313326
fn_child_exit_fl,
327+
fn_child_ready_fl,
314328
NULL, /* thread_start */
315329
NULL, /* thread_exit */
316330
fn_exec_fl,

trace2/tr2_tgt_perf.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,20 @@ static void fn_child_exit_fl(const char *file, int line,
345345
strbuf_release(&buf_payload);
346346
}
347347

348+
static void fn_child_ready_fl(const char *file, int line,
349+
uint64_t us_elapsed_absolute, int cid, int pid,
350+
const char *ready, uint64_t us_elapsed_child)
351+
{
352+
const char *event_name = "child_ready";
353+
struct strbuf buf_payload = STRBUF_INIT;
354+
355+
strbuf_addf(&buf_payload, "[ch%d] pid:%d ready:%s", cid, pid, ready);
356+
357+
perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
358+
&us_elapsed_child, NULL, &buf_payload);
359+
strbuf_release(&buf_payload);
360+
}
361+
348362
static void fn_thread_start_fl(const char *file, int line,
349363
uint64_t us_elapsed_absolute)
350364
{
@@ -537,6 +551,7 @@ struct tr2_tgt tr2_tgt_perf = {
537551
fn_alias_fl,
538552
fn_child_start_fl,
539553
fn_child_exit_fl,
554+
fn_child_ready_fl,
540555
fn_thread_start_fl,
541556
fn_thread_exit_fl,
542557
fn_exec_fl,

0 commit comments

Comments
 (0)