git
/
trace2.c
1042 строки · 23.8 Кб
1#include "git-compat-util.h"2#include "config.h"3#include "repository.h"4#include "run-command.h"5#include "sigchain.h"6#include "thread-utils.h"7#include "trace.h"8#include "trace2.h"9#include "trace2/tr2_cfg.h"10#include "trace2/tr2_cmd_name.h"11#include "trace2/tr2_ctr.h"12#include "trace2/tr2_dst.h"13#include "trace2/tr2_sid.h"14#include "trace2/tr2_sysenv.h"15#include "trace2/tr2_tgt.h"16#include "trace2/tr2_tls.h"17#include "trace2/tr2_tmr.h"18
19static int trace2_enabled;20static int trace2_redact = 1;21
22static int tr2_next_child_id; /* modify under lock */23static int tr2_next_exec_id; /* modify under lock */24static int tr2_next_repo_id = 1; /* modify under lock. zero is reserved */25
26/*
27* A table of the builtin TRACE2 targets. Each of these may be independently
28* enabled or disabled. Each TRACE2 API method will try to write an event to
29* *each* of the enabled targets.
30*/
31/* clang-format off */
32static struct tr2_tgt *tr2_tgt_builtins[] =33{
34&tr2_tgt_normal,35&tr2_tgt_perf,36&tr2_tgt_event,37NULL38};39/* clang-format on */
40
41/* clang-format off */
42#define for_each_builtin(j, tgt_j) \43for (j = 0, tgt_j = tr2_tgt_builtins[j]; \44tgt_j; \45j++, tgt_j = tr2_tgt_builtins[j])46/* clang-format on */
47
48/* clang-format off */
49#define for_each_wanted_builtin(j, tgt_j) \50for_each_builtin(j, tgt_j) \51if (tr2_dst_trace_want(tgt_j->pdst))52/* clang-format on */
53
54/*
55* Force (rather than lazily) initialize any of the requested
56* builtin TRACE2 targets at startup (and before we've seen an
57* actual TRACE2 event call) so we can see if we need to setup
58* private data structures and thread-local storage.
59*
60* Return the number of builtin targets enabled.
61*/
62static int tr2_tgt_want_builtins(void)63{
64struct tr2_tgt *tgt_j;65int j;66int sum = 0;67
68for_each_builtin (j, tgt_j)69if (tgt_j->pfn_init())70sum++;71
72return sum;73}
74
75/*
76* Properly terminate each builtin target. Give each target
77* a chance to write a summary event and/or flush if necessary
78* and then close the fd.
79*/
80static void tr2_tgt_disable_builtins(void)81{
82struct tr2_tgt *tgt_j;83int j;84
85for_each_builtin (j, tgt_j)86tgt_j->pfn_term();87}
88
89/*
90* The signature of this function must match the pfn_timer
91* method in the targets. (Think of this is an apply operation
92* across the set of active targets.)
93*/
94static void tr2_tgt_emit_a_timer(const struct tr2_timer_metadata *meta,95const struct tr2_timer *timer,96int is_final_data)97{
98struct tr2_tgt *tgt_j;99int j;100
101for_each_wanted_builtin (j, tgt_j)102if (tgt_j->pfn_timer)103tgt_j->pfn_timer(meta, timer, is_final_data);104}
105
106/*
107* The signature of this function must match the pfn_counter
108* method in the targets.
109*/
110static void tr2_tgt_emit_a_counter(const struct tr2_counter_metadata *meta,111const struct tr2_counter *counter,112int is_final_data)113{
114struct tr2_tgt *tgt_j;115int j;116
117for_each_wanted_builtin (j, tgt_j)118if (tgt_j->pfn_counter)119tgt_j->pfn_counter(meta, counter, is_final_data);120}
121
122static int tr2main_exit_code;123
124/*
125* Our atexit routine should run after everything has finished.
126*
127* Note that events generated here might not actually appear if
128* we are writing to fd 1 or 2 and our atexit routine runs after
129* the pager's atexit routine (since it closes them to shutdown
130* the pipes).
131*/
132static void tr2main_atexit_handler(void)133{
134struct tr2_tgt *tgt_j;135int j;136uint64_t us_now;137uint64_t us_elapsed_absolute;138
139us_now = getnanotime() / 1000;140us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);141
142/*143* Clear any unbalanced regions so that our atexit message
144* does not appear nested. This improves the appearance of
145* the trace output if someone calls die(), for example.
146*/
147tr2tls_pop_unwind_self();148
149/*150* Some timers want per-thread details. If the main thread
151* used one of those timers, emit the details now (before
152* we emit the aggregate timer values).
153*
154* Likewise for counters.
155*/
156tr2_emit_per_thread_timers(tr2_tgt_emit_a_timer);157tr2_emit_per_thread_counters(tr2_tgt_emit_a_counter);158
159/*160* Add stopwatch timer and counter data for the main thread to
161* the final totals. And then emit the final values.
162*
163* Technically, we shouldn't need to hold the lock to update
164* and output the final_timer_block and final_counter_block
165* (since all other threads should be dead by now), but it
166* doesn't hurt anything.
167*/
168tr2tls_lock();169tr2_update_final_timers();170tr2_update_final_counters();171tr2_emit_final_timers(tr2_tgt_emit_a_timer);172tr2_emit_final_counters(tr2_tgt_emit_a_counter);173tr2tls_unlock();174
175for_each_wanted_builtin (j, tgt_j)176if (tgt_j->pfn_atexit)177tgt_j->pfn_atexit(us_elapsed_absolute,178tr2main_exit_code);179
180tr2_tgt_disable_builtins();181
182tr2tls_release();183tr2_sid_release();184tr2_cmd_name_release();185tr2_cfg_free_patterns();186tr2_cfg_free_env_vars();187tr2_sysenv_release();188
189trace2_enabled = 0;190}
191
192static void tr2main_signal_handler(int signo)193{
194struct tr2_tgt *tgt_j;195int j;196uint64_t us_now;197uint64_t us_elapsed_absolute;198
199us_now = getnanotime() / 1000;200us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);201
202for_each_wanted_builtin (j, tgt_j)203if (tgt_j->pfn_signal)204tgt_j->pfn_signal(us_elapsed_absolute, signo);205
206sigchain_pop(signo);207raise(signo);208}
209
210void trace2_initialize_clock(void)211{
212tr2tls_start_process_clock();213}
214
215void trace2_initialize_fl(const char *file, int line)216{
217struct tr2_tgt *tgt_j;218int j;219
220if (trace2_enabled)221return;222
223tr2_sysenv_load();224
225if (!tr2_tgt_want_builtins())226return;227trace2_enabled = 1;228if (!git_env_bool("GIT_TRACE2_REDACT", 1))229trace2_redact = 0;230
231tr2_sid_get();232
233atexit(tr2main_atexit_handler);234sigchain_push(SIGPIPE, tr2main_signal_handler);235tr2tls_init();236
237/*238* Emit 'version' message on each active builtin target.
239*/
240for_each_wanted_builtin (j, tgt_j)241if (tgt_j->pfn_version_fl)242tgt_j->pfn_version_fl(file, line);243}
244
245int trace2_is_enabled(void)246{
247return trace2_enabled;248}
249
250/*
251* Redacts an argument, i.e. ensures that no password in
252* https://user:password@host/-style URLs is logged.
253*
254* Returns the original if nothing needed to be redacted.
255* Returns a pointer that needs to be `free()`d otherwise.
256*/
257static const char *redact_arg(const char *arg)258{
259const char *p, *colon;260size_t at;261
262if (!trace2_redact ||263(!skip_prefix(arg, "https://", &p) &&264!skip_prefix(arg, "http://", &p)))265return arg;266
267at = strcspn(p, "@/");268if (p[at] != '@')269return arg;270
271colon = memchr(p, ':', at);272if (!colon)273return arg;274
275return xstrfmt("%.*s:<REDACTED>%s", (int)(colon - arg), arg, p + at);276}
277
278/*
279* Redacts arguments in an argument list.
280*
281* Returns the original if nothing needed to be redacted.
282* Otherwise, returns a new array that needs to be released
283* via `free_redacted_argv()`.
284*/
285static const char **redact_argv(const char **argv)286{
287int i, j;288const char *redacted = NULL;289const char **ret;290
291if (!trace2_redact)292return argv;293
294for (i = 0; argv[i]; i++)295if ((redacted = redact_arg(argv[i])) != argv[i])296break;297
298if (!argv[i])299return argv;300
301for (j = 0; argv[j]; j++)302; /* keep counting */303
304ALLOC_ARRAY(ret, j + 1);305ret[j] = NULL;306
307for (j = 0; j < i; j++)308ret[j] = argv[j];309ret[i] = redacted;310for (++i; argv[i]; i++) {311redacted = redact_arg(argv[i]);312ret[i] = redacted ? redacted : argv[i];313}314
315return ret;316}
317
318static void free_redacted_argv(const char **redacted, const char **argv)319{
320int i;321
322if (redacted != argv) {323for (i = 0; argv[i]; i++)324if (redacted[i] != argv[i])325free((void *)redacted[i]);326free((void *)redacted);327}328}
329
330void trace2_cmd_start_fl(const char *file, int line, const char **argv)331{
332struct tr2_tgt *tgt_j;333int j;334uint64_t us_now;335uint64_t us_elapsed_absolute;336const char **redacted;337
338if (!trace2_enabled)339return;340
341us_now = getnanotime() / 1000;342us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);343
344redacted = redact_argv(argv);345
346for_each_wanted_builtin (j, tgt_j)347if (tgt_j->pfn_start_fl)348tgt_j->pfn_start_fl(file, line, us_elapsed_absolute,349redacted);350
351free_redacted_argv(redacted, argv);352}
353
354void trace2_cmd_exit_fl(const char *file, int line, int code)355{
356struct tr2_tgt *tgt_j;357int j;358uint64_t us_now;359uint64_t us_elapsed_absolute;360
361if (!trace2_enabled)362return;363
364trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT);365
366tr2main_exit_code = code;367
368us_now = getnanotime() / 1000;369us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);370
371for_each_wanted_builtin (j, tgt_j)372if (tgt_j->pfn_exit_fl)373tgt_j->pfn_exit_fl(file, line, us_elapsed_absolute,374code);375}
376
377void trace2_cmd_error_va_fl(const char *file, int line, const char *fmt,378va_list ap)379{
380struct tr2_tgt *tgt_j;381int j;382
383if (!trace2_enabled)384return;385
386/*387* We expect each target function to treat 'ap' as constant
388* and use va_copy (because an 'ap' can only be walked once).
389*/
390for_each_wanted_builtin (j, tgt_j)391if (tgt_j->pfn_error_va_fl)392tgt_j->pfn_error_va_fl(file, line, fmt, ap);393}
394
395void trace2_cmd_path_fl(const char *file, int line, const char *pathname)396{
397struct tr2_tgt *tgt_j;398int j;399
400if (!trace2_enabled)401return;402
403for_each_wanted_builtin (j, tgt_j)404if (tgt_j->pfn_command_path_fl)405tgt_j->pfn_command_path_fl(file, line, pathname);406}
407
408void trace2_cmd_ancestry_fl(const char *file, int line, const char **parent_names)409{
410struct tr2_tgt *tgt_j;411int j;412
413if (!trace2_enabled)414return;415
416for_each_wanted_builtin (j, tgt_j)417if (tgt_j->pfn_command_ancestry_fl)418tgt_j->pfn_command_ancestry_fl(file, line, parent_names);419}
420
421void trace2_cmd_name_fl(const char *file, int line, const char *name)422{
423struct tr2_tgt *tgt_j;424const char *hierarchy;425int j;426
427if (!trace2_enabled)428return;429
430tr2_cmd_name_append_hierarchy(name);431hierarchy = tr2_cmd_name_get_hierarchy();432
433for_each_wanted_builtin (j, tgt_j)434if (tgt_j->pfn_command_name_fl)435tgt_j->pfn_command_name_fl(file, line, name, hierarchy);436
437trace2_cmd_list_config();438trace2_cmd_list_env_vars();439}
440
441void trace2_cmd_mode_fl(const char *file, int line, const char *mode)442{
443struct tr2_tgt *tgt_j;444int j;445
446if (!trace2_enabled)447return;448
449for_each_wanted_builtin (j, tgt_j)450if (tgt_j->pfn_command_mode_fl)451tgt_j->pfn_command_mode_fl(file, line, mode);452}
453
454void trace2_cmd_alias_fl(const char *file, int line, const char *alias,455const char **argv)456{
457struct tr2_tgt *tgt_j;458int j;459
460if (!trace2_enabled)461return;462
463for_each_wanted_builtin (j, tgt_j)464if (tgt_j->pfn_alias_fl)465tgt_j->pfn_alias_fl(file, line, alias, argv);466}
467
468void trace2_cmd_list_config_fl(const char *file, int line)469{
470static int emitted = 0;471
472if (!trace2_enabled)473return;474
475if (emitted)476return;477emitted = 1;478
479tr2_cfg_list_config_fl(file, line);480}
481
482void trace2_cmd_list_env_vars_fl(const char *file, int line)483{
484static int emitted = 0;485
486if (!trace2_enabled)487return;488
489if (emitted)490return;491emitted = 1;492
493tr2_list_env_vars_fl(file, line);494}
495
496void trace2_cmd_set_config_fl(const char *file, int line, const char *key,497const char *value)498{
499if (!trace2_enabled)500return;501
502tr2_cfg_set_fl(file, line, key, value);503}
504
505void trace2_child_start_fl(const char *file, int line,506struct child_process *cmd)507{
508struct tr2_tgt *tgt_j;509int j;510uint64_t us_now;511uint64_t us_elapsed_absolute;512const char **orig_argv = cmd->args.v;513
514if (!trace2_enabled)515return;516
517us_now = getnanotime() / 1000;518us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);519
520cmd->trace2_child_id = tr2tls_locked_increment(&tr2_next_child_id);521cmd->trace2_child_us_start = us_now;522
523/*524* The `pfn_child_start_fl` API takes a `struct child_process`
525* rather than a simple `argv` for the child because some
526* targets make use of the additional context bits/values. So
527* temporarily replace the original argv (inside the `strvec`)
528* with a possibly redacted version.
529*/
530cmd->args.v = redact_argv(orig_argv);531
532for_each_wanted_builtin (j, tgt_j)533if (tgt_j->pfn_child_start_fl)534tgt_j->pfn_child_start_fl(file, line,535us_elapsed_absolute, cmd);536
537if (cmd->args.v != orig_argv) {538free_redacted_argv(cmd->args.v, orig_argv);539cmd->args.v = orig_argv;540}541}
542
543void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,544int child_exit_code)545{
546struct tr2_tgt *tgt_j;547int j;548uint64_t us_now;549uint64_t us_elapsed_absolute;550uint64_t us_elapsed_child;551
552if (!trace2_enabled)553return;554
555us_now = getnanotime() / 1000;556us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);557
558if (cmd->trace2_child_us_start)559us_elapsed_child = us_now - cmd->trace2_child_us_start;560else561us_elapsed_child = 0;562
563for_each_wanted_builtin (j, tgt_j)564if (tgt_j->pfn_child_exit_fl)565tgt_j->pfn_child_exit_fl(file, line,566us_elapsed_absolute,567cmd->trace2_child_id, cmd->pid,568child_exit_code,569us_elapsed_child);570}
571
572void trace2_child_ready_fl(const char *file, int line,573struct child_process *cmd,574const char *ready)575{
576struct tr2_tgt *tgt_j;577int j;578uint64_t us_now;579uint64_t us_elapsed_absolute;580uint64_t us_elapsed_child;581
582if (!trace2_enabled)583return;584
585us_now = getnanotime() / 1000;586us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);587
588if (cmd->trace2_child_us_start)589us_elapsed_child = us_now - cmd->trace2_child_us_start;590else591us_elapsed_child = 0;592
593for_each_wanted_builtin (j, tgt_j)594if (tgt_j->pfn_child_ready_fl)595tgt_j->pfn_child_ready_fl(file, line,596us_elapsed_absolute,597cmd->trace2_child_id,598cmd->pid,599ready,600us_elapsed_child);601}
602
603int trace2_exec_fl(const char *file, int line, const char *exe,604const char **argv)605{
606struct tr2_tgt *tgt_j;607int j;608int exec_id;609uint64_t us_now;610uint64_t us_elapsed_absolute;611const char **redacted;612
613if (!trace2_enabled)614return -1;615
616us_now = getnanotime() / 1000;617us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);618
619exec_id = tr2tls_locked_increment(&tr2_next_exec_id);620
621redacted = redact_argv(argv);622
623for_each_wanted_builtin (j, tgt_j)624if (tgt_j->pfn_exec_fl)625tgt_j->pfn_exec_fl(file, line, us_elapsed_absolute,626exec_id, exe, redacted);627
628free_redacted_argv(redacted, argv);629
630return exec_id;631}
632
633void trace2_exec_result_fl(const char *file, int line, int exec_id, int code)634{
635struct tr2_tgt *tgt_j;636int j;637uint64_t us_now;638uint64_t us_elapsed_absolute;639
640if (!trace2_enabled)641return;642
643us_now = getnanotime() / 1000;644us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);645
646for_each_wanted_builtin (j, tgt_j)647if (tgt_j->pfn_exec_result_fl)648tgt_j->pfn_exec_result_fl(649file, line, us_elapsed_absolute, exec_id, code);650}
651
652void trace2_thread_start_fl(const char *file, int line, const char *thread_base_name)653{
654struct tr2_tgt *tgt_j;655int j;656uint64_t us_now;657uint64_t us_elapsed_absolute;658
659if (!trace2_enabled)660return;661
662if (tr2tls_is_main_thread()) {663/*664* We should only be called from the new thread's thread-proc,
665* so this is technically a bug. But in those cases where the
666* main thread also runs the thread-proc function (or when we
667* are built with threading disabled), we need to allow it.
668*
669* Convert this call to a region-enter so the nesting looks
670* correct.
671*/
672trace2_region_enter_printf_fl(file, line, NULL, NULL, NULL,673"thread-proc on main: %s",674thread_base_name);675return;676}677
678us_now = getnanotime() / 1000;679us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);680
681tr2tls_create_self(thread_base_name, us_now);682
683for_each_wanted_builtin (j, tgt_j)684if (tgt_j->pfn_thread_start_fl)685tgt_j->pfn_thread_start_fl(file, line,686us_elapsed_absolute);687}
688
689void trace2_thread_exit_fl(const char *file, int line)690{
691struct tr2_tgt *tgt_j;692int j;693uint64_t us_now;694uint64_t us_elapsed_absolute;695uint64_t us_elapsed_thread;696
697if (!trace2_enabled)698return;699
700if (tr2tls_is_main_thread()) {701/*702* We should only be called from the exiting thread's
703* thread-proc, so this is technically a bug. But in
704* those cases where the main thread also runs the
705* thread-proc function (or when we are built with
706* threading disabled), we need to allow it.
707*
708* Convert this call to a region-leave so the nesting
709* looks correct.
710*/
711trace2_region_leave_printf_fl(file, line, NULL, NULL, NULL,712"thread-proc on main");713return;714}715
716us_now = getnanotime() / 1000;717us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);718
719/*720* Clear any unbalanced regions and then get the relative time
721* for the outer-most region (which we pushed when the thread
722* started). This gives us the run time of the thread.
723*/
724tr2tls_pop_unwind_self();725us_elapsed_thread = tr2tls_region_elasped_self(us_now);726
727/*728* Some timers want per-thread details. If this thread used
729* one of those timers, emit the details now.
730*
731* Likewise for counters.
732*/
733tr2_emit_per_thread_timers(tr2_tgt_emit_a_timer);734tr2_emit_per_thread_counters(tr2_tgt_emit_a_counter);735
736/*737* Add stopwatch timer and counter data from the current
738* (non-main) thread to the final totals. (We'll accumulate
739* data for the main thread later during "atexit".)
740*/
741tr2tls_lock();742tr2_update_final_timers();743tr2_update_final_counters();744tr2tls_unlock();745
746for_each_wanted_builtin (j, tgt_j)747if (tgt_j->pfn_thread_exit_fl)748tgt_j->pfn_thread_exit_fl(file, line,749us_elapsed_absolute,750us_elapsed_thread);751
752tr2tls_unset_self();753}
754
755void trace2_def_param_fl(const char *file, int line, const char *param,756const char *value, const struct key_value_info *kvi)757{
758struct tr2_tgt *tgt_j;759int j;760const char *redacted;761
762if (!trace2_enabled)763return;764
765redacted = redact_arg(value);766
767for_each_wanted_builtin (j, tgt_j)768if (tgt_j->pfn_param_fl)769tgt_j->pfn_param_fl(file, line, param, redacted, kvi);770
771if (redacted != value)772free((void *)redacted);773}
774
775void trace2_def_repo_fl(const char *file, int line, struct repository *repo)776{
777struct tr2_tgt *tgt_j;778int j;779
780if (!trace2_enabled)781return;782
783if (repo->trace2_repo_id)784return;785
786repo->trace2_repo_id = tr2tls_locked_increment(&tr2_next_repo_id);787
788for_each_wanted_builtin (j, tgt_j)789if (tgt_j->pfn_repo_fl)790tgt_j->pfn_repo_fl(file, line, repo);791}
792
793void trace2_region_enter_printf_va_fl(const char *file, int line,794const char *category, const char *label,795const struct repository *repo,796const char *fmt, va_list ap)797{
798struct tr2_tgt *tgt_j;799int j;800uint64_t us_now;801uint64_t us_elapsed_absolute;802
803if (!trace2_enabled)804return;805
806us_now = getnanotime() / 1000;807us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);808
809/*810* Print the region-enter message at the current nesting
811* (indentation) level and then push a new level.
812*
813* We expect each target function to treat 'ap' as constant
814* and use va_copy.
815*/
816for_each_wanted_builtin (j, tgt_j)817if (tgt_j->pfn_region_enter_printf_va_fl)818tgt_j->pfn_region_enter_printf_va_fl(819file, line, us_elapsed_absolute, category,820label, repo, fmt, ap);821
822tr2tls_push_self(us_now);823}
824
825void trace2_region_enter_fl(const char *file, int line, const char *category,826const char *label, const struct repository *repo, ...)827{
828va_list ap;829va_start(ap, repo);830trace2_region_enter_printf_va_fl(file, line, category, label, repo,831NULL, ap);832va_end(ap);833
834}
835
836void trace2_region_enter_printf_fl(const char *file, int line,837const char *category, const char *label,838const struct repository *repo,839const char *fmt, ...)840{
841va_list ap;842
843va_start(ap, fmt);844trace2_region_enter_printf_va_fl(file, line, category, label, repo, fmt,845ap);846va_end(ap);847}
848
849void trace2_region_leave_printf_va_fl(const char *file, int line,850const char *category, const char *label,851const struct repository *repo,852const char *fmt, va_list ap)853{
854struct tr2_tgt *tgt_j;855int j;856uint64_t us_now;857uint64_t us_elapsed_absolute;858uint64_t us_elapsed_region;859
860if (!trace2_enabled)861return;862
863us_now = getnanotime() / 1000;864us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);865
866/*867* Get the elapsed time in the current region before we
868* pop it off the stack. Pop the stack. And then print
869* the perf message at the new (shallower) level so that
870* it lines up with the corresponding push/enter.
871*/
872us_elapsed_region = tr2tls_region_elasped_self(us_now);873
874tr2tls_pop_self();875
876/*877* We expect each target function to treat 'ap' as constant
878* and use va_copy.
879*/
880for_each_wanted_builtin (j, tgt_j)881if (tgt_j->pfn_region_leave_printf_va_fl)882tgt_j->pfn_region_leave_printf_va_fl(883file, line, us_elapsed_absolute,884us_elapsed_region, category, label, repo, fmt,885ap);886}
887
888void trace2_region_leave_fl(const char *file, int line, const char *category,889const char *label, const struct repository *repo, ...)890{
891va_list ap;892va_start(ap, repo);893trace2_region_leave_printf_va_fl(file, line, category, label, repo,894NULL, ap);895va_end(ap);896}
897
898void trace2_region_leave_printf_fl(const char *file, int line,899const char *category, const char *label,900const struct repository *repo,901const char *fmt, ...)902{
903va_list ap;904
905va_start(ap, fmt);906trace2_region_leave_printf_va_fl(file, line, category, label, repo, fmt,907ap);908va_end(ap);909}
910
911void trace2_data_string_fl(const char *file, int line, const char *category,912const struct repository *repo, const char *key,913const char *value)914{
915struct tr2_tgt *tgt_j;916int j;917uint64_t us_now;918uint64_t us_elapsed_absolute;919uint64_t us_elapsed_region;920
921if (!trace2_enabled)922return;923
924us_now = getnanotime() / 1000;925us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);926us_elapsed_region = tr2tls_region_elasped_self(us_now);927
928for_each_wanted_builtin (j, tgt_j)929if (tgt_j->pfn_data_fl)930tgt_j->pfn_data_fl(file, line, us_elapsed_absolute,931us_elapsed_region, category, repo,932key, value);933}
934
935void trace2_data_intmax_fl(const char *file, int line, const char *category,936const struct repository *repo, const char *key,937intmax_t value)938{
939struct strbuf buf_string = STRBUF_INIT;940
941if (!trace2_enabled)942return;943
944strbuf_addf(&buf_string, "%" PRIdMAX, value);945trace2_data_string_fl(file, line, category, repo, key, buf_string.buf);946strbuf_release(&buf_string);947}
948
949void trace2_data_json_fl(const char *file, int line, const char *category,950const struct repository *repo, const char *key,951const struct json_writer *value)952{
953struct tr2_tgt *tgt_j;954int j;955uint64_t us_now;956uint64_t us_elapsed_absolute;957uint64_t us_elapsed_region;958
959if (!trace2_enabled)960return;961
962us_now = getnanotime() / 1000;963us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);964us_elapsed_region = tr2tls_region_elasped_self(us_now);965
966for_each_wanted_builtin (j, tgt_j)967if (tgt_j->pfn_data_json_fl)968tgt_j->pfn_data_json_fl(file, line, us_elapsed_absolute,969us_elapsed_region, category,970repo, key, value);971}
972
973void trace2_printf_va_fl(const char *file, int line, const char *fmt,974va_list ap)975{
976struct tr2_tgt *tgt_j;977int j;978uint64_t us_now;979uint64_t us_elapsed_absolute;980
981if (!trace2_enabled)982return;983
984us_now = getnanotime() / 1000;985us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);986
987/*988* We expect each target function to treat 'ap' as constant
989* and use va_copy.
990*/
991for_each_wanted_builtin (j, tgt_j)992if (tgt_j->pfn_printf_va_fl)993tgt_j->pfn_printf_va_fl(file, line, us_elapsed_absolute,994fmt, ap);995}
996
997void trace2_printf_fl(const char *file, int line, const char *fmt, ...)998{
999va_list ap;1000
1001va_start(ap, fmt);1002trace2_printf_va_fl(file, line, fmt, ap);1003va_end(ap);1004}
1005
1006void trace2_timer_start(enum trace2_timer_id tid)1007{
1008if (!trace2_enabled)1009return;1010
1011if (tid < 0 || tid >= TRACE2_NUMBER_OF_TIMERS)1012BUG("trace2_timer_start: invalid timer id: %d", tid);1013
1014tr2_start_timer(tid);1015}
1016
1017void trace2_timer_stop(enum trace2_timer_id tid)1018{
1019if (!trace2_enabled)1020return;1021
1022if (tid < 0 || tid >= TRACE2_NUMBER_OF_TIMERS)1023BUG("trace2_timer_stop: invalid timer id: %d", tid);1024
1025tr2_stop_timer(tid);1026}
1027
1028void trace2_counter_add(enum trace2_counter_id cid, uint64_t value)1029{
1030if (!trace2_enabled)1031return;1032
1033if (cid < 0 || cid >= TRACE2_NUMBER_OF_COUNTERS)1034BUG("trace2_counter_add: invalid counter id: %d", cid);1035
1036tr2_counter_increment(cid, value);1037}
1038
1039const char *trace2_session_id(void)1040{
1041return tr2_sid_get();1042}
1043