trace2.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. #include "cache.h"
  2. #include "config.h"
  3. #include "json-writer.h"
  4. #include "quote.h"
  5. #include "run-command.h"
  6. #include "sigchain.h"
  7. #include "thread-utils.h"
  8. #include "version.h"
  9. #include "trace2/tr2_cfg.h"
  10. #include "trace2/tr2_cmd_name.h"
  11. #include "trace2/tr2_dst.h"
  12. #include "trace2/tr2_sid.h"
  13. #include "trace2/tr2_sysenv.h"
  14. #include "trace2/tr2_tgt.h"
  15. #include "trace2/tr2_tls.h"
  16. static int trace2_enabled;
  17. static int tr2_next_child_id; /* modify under lock */
  18. static int tr2_next_exec_id; /* modify under lock */
  19. static int tr2_next_repo_id = 1; /* modify under lock. zero is reserved */
  20. /*
  21. * A table of the builtin TRACE2 targets. Each of these may be independently
  22. * enabled or disabled. Each TRACE2 API method will try to write an event to
  23. * *each* of the enabled targets.
  24. */
  25. /* clang-format off */
  26. static struct tr2_tgt *tr2_tgt_builtins[] =
  27. {
  28. &tr2_tgt_normal,
  29. &tr2_tgt_perf,
  30. &tr2_tgt_event,
  31. NULL
  32. };
  33. /* clang-format on */
  34. /* clang-format off */
  35. #define for_each_builtin(j, tgt_j) \
  36. for (j = 0, tgt_j = tr2_tgt_builtins[j]; \
  37. tgt_j; \
  38. j++, tgt_j = tr2_tgt_builtins[j])
  39. /* clang-format on */
  40. /* clang-format off */
  41. #define for_each_wanted_builtin(j, tgt_j) \
  42. for_each_builtin(j, tgt_j) \
  43. if (tr2_dst_trace_want(tgt_j->pdst))
  44. /* clang-format on */
  45. /*
  46. * Force (rather than lazily) initialize any of the requested
  47. * builtin TRACE2 targets at startup (and before we've seen an
  48. * actual TRACE2 event call) so we can see if we need to setup
  49. * the TR2 and TLS machinery.
  50. *
  51. * Return the number of builtin targets enabled.
  52. */
  53. static int tr2_tgt_want_builtins(void)
  54. {
  55. struct tr2_tgt *tgt_j;
  56. int j;
  57. int sum = 0;
  58. for_each_builtin (j, tgt_j)
  59. if (tgt_j->pfn_init())
  60. sum++;
  61. return sum;
  62. }
  63. /*
  64. * Properly terminate each builtin target. Give each target
  65. * a chance to write a summary event and/or flush if necessary
  66. * and then close the fd.
  67. */
  68. static void tr2_tgt_disable_builtins(void)
  69. {
  70. struct tr2_tgt *tgt_j;
  71. int j;
  72. for_each_builtin (j, tgt_j)
  73. tgt_j->pfn_term();
  74. }
  75. static int tr2main_exit_code;
  76. /*
  77. * Our atexit routine should run after everything has finished.
  78. *
  79. * Note that events generated here might not actually appear if
  80. * we are writing to fd 1 or 2 and our atexit routine runs after
  81. * the pager's atexit routine (since it closes them to shutdown
  82. * the pipes).
  83. */
  84. static void tr2main_atexit_handler(void)
  85. {
  86. struct tr2_tgt *tgt_j;
  87. int j;
  88. uint64_t us_now;
  89. uint64_t us_elapsed_absolute;
  90. us_now = getnanotime() / 1000;
  91. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  92. /*
  93. * Clear any unbalanced regions so that our atexit message
  94. * does not appear nested. This improves the appearance of
  95. * the trace output if someone calls die(), for example.
  96. */
  97. tr2tls_pop_unwind_self();
  98. for_each_wanted_builtin (j, tgt_j)
  99. if (tgt_j->pfn_atexit)
  100. tgt_j->pfn_atexit(us_elapsed_absolute,
  101. tr2main_exit_code);
  102. tr2_tgt_disable_builtins();
  103. tr2tls_release();
  104. tr2_sid_release();
  105. tr2_cmd_name_release();
  106. tr2_cfg_free_patterns();
  107. tr2_cfg_free_env_vars();
  108. tr2_sysenv_release();
  109. trace2_enabled = 0;
  110. }
  111. static void tr2main_signal_handler(int signo)
  112. {
  113. struct tr2_tgt *tgt_j;
  114. int j;
  115. uint64_t us_now;
  116. uint64_t us_elapsed_absolute;
  117. us_now = getnanotime() / 1000;
  118. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  119. for_each_wanted_builtin (j, tgt_j)
  120. if (tgt_j->pfn_signal)
  121. tgt_j->pfn_signal(us_elapsed_absolute, signo);
  122. sigchain_pop(signo);
  123. raise(signo);
  124. }
  125. void trace2_initialize_clock(void)
  126. {
  127. tr2tls_start_process_clock();
  128. }
  129. void trace2_initialize_fl(const char *file, int line)
  130. {
  131. struct tr2_tgt *tgt_j;
  132. int j;
  133. if (trace2_enabled)
  134. return;
  135. tr2_sysenv_load();
  136. if (!tr2_tgt_want_builtins())
  137. return;
  138. trace2_enabled = 1;
  139. tr2_sid_get();
  140. atexit(tr2main_atexit_handler);
  141. sigchain_push(SIGPIPE, tr2main_signal_handler);
  142. tr2tls_init();
  143. /*
  144. * Emit 'version' message on each active builtin target.
  145. */
  146. for_each_wanted_builtin (j, tgt_j)
  147. if (tgt_j->pfn_version_fl)
  148. tgt_j->pfn_version_fl(file, line);
  149. }
  150. int trace2_is_enabled(void)
  151. {
  152. return trace2_enabled;
  153. }
  154. void trace2_cmd_start_fl(const char *file, int line, const char **argv)
  155. {
  156. struct tr2_tgt *tgt_j;
  157. int j;
  158. uint64_t us_now;
  159. uint64_t us_elapsed_absolute;
  160. if (!trace2_enabled)
  161. return;
  162. us_now = getnanotime() / 1000;
  163. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  164. for_each_wanted_builtin (j, tgt_j)
  165. if (tgt_j->pfn_start_fl)
  166. tgt_j->pfn_start_fl(file, line, us_elapsed_absolute,
  167. argv);
  168. }
  169. int trace2_cmd_exit_fl(const char *file, int line, int code)
  170. {
  171. struct tr2_tgt *tgt_j;
  172. int j;
  173. uint64_t us_now;
  174. uint64_t us_elapsed_absolute;
  175. code &= 0xff;
  176. if (!trace2_enabled)
  177. return code;
  178. trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT);
  179. tr2main_exit_code = code;
  180. us_now = getnanotime() / 1000;
  181. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  182. for_each_wanted_builtin (j, tgt_j)
  183. if (tgt_j->pfn_exit_fl)
  184. tgt_j->pfn_exit_fl(file, line, us_elapsed_absolute,
  185. code);
  186. return code;
  187. }
  188. void trace2_cmd_error_va_fl(const char *file, int line, const char *fmt,
  189. va_list ap)
  190. {
  191. struct tr2_tgt *tgt_j;
  192. int j;
  193. if (!trace2_enabled)
  194. return;
  195. /*
  196. * We expect each target function to treat 'ap' as constant
  197. * and use va_copy (because an 'ap' can only be walked once).
  198. */
  199. for_each_wanted_builtin (j, tgt_j)
  200. if (tgt_j->pfn_error_va_fl)
  201. tgt_j->pfn_error_va_fl(file, line, fmt, ap);
  202. }
  203. void trace2_cmd_path_fl(const char *file, int line, const char *pathname)
  204. {
  205. struct tr2_tgt *tgt_j;
  206. int j;
  207. if (!trace2_enabled)
  208. return;
  209. for_each_wanted_builtin (j, tgt_j)
  210. if (tgt_j->pfn_command_path_fl)
  211. tgt_j->pfn_command_path_fl(file, line, pathname);
  212. }
  213. void trace2_cmd_name_fl(const char *file, int line, const char *name)
  214. {
  215. struct tr2_tgt *tgt_j;
  216. const char *hierarchy;
  217. int j;
  218. if (!trace2_enabled)
  219. return;
  220. tr2_cmd_name_append_hierarchy(name);
  221. hierarchy = tr2_cmd_name_get_hierarchy();
  222. for_each_wanted_builtin (j, tgt_j)
  223. if (tgt_j->pfn_command_name_fl)
  224. tgt_j->pfn_command_name_fl(file, line, name, hierarchy);
  225. }
  226. void trace2_cmd_mode_fl(const char *file, int line, const char *mode)
  227. {
  228. struct tr2_tgt *tgt_j;
  229. int j;
  230. if (!trace2_enabled)
  231. return;
  232. for_each_wanted_builtin (j, tgt_j)
  233. if (tgt_j->pfn_command_mode_fl)
  234. tgt_j->pfn_command_mode_fl(file, line, mode);
  235. }
  236. void trace2_cmd_alias_fl(const char *file, int line, const char *alias,
  237. const char **argv)
  238. {
  239. struct tr2_tgt *tgt_j;
  240. int j;
  241. if (!trace2_enabled)
  242. return;
  243. for_each_wanted_builtin (j, tgt_j)
  244. if (tgt_j->pfn_alias_fl)
  245. tgt_j->pfn_alias_fl(file, line, alias, argv);
  246. }
  247. void trace2_cmd_list_config_fl(const char *file, int line)
  248. {
  249. if (!trace2_enabled)
  250. return;
  251. tr2_cfg_list_config_fl(file, line);
  252. }
  253. void trace2_cmd_list_env_vars_fl(const char *file, int line)
  254. {
  255. if (!trace2_enabled)
  256. return;
  257. tr2_list_env_vars_fl(file, line);
  258. }
  259. void trace2_cmd_set_config_fl(const char *file, int line, const char *key,
  260. const char *value)
  261. {
  262. if (!trace2_enabled)
  263. return;
  264. tr2_cfg_set_fl(file, line, key, value);
  265. }
  266. void trace2_child_start_fl(const char *file, int line,
  267. struct child_process *cmd)
  268. {
  269. struct tr2_tgt *tgt_j;
  270. int j;
  271. uint64_t us_now;
  272. uint64_t us_elapsed_absolute;
  273. if (!trace2_enabled)
  274. return;
  275. us_now = getnanotime() / 1000;
  276. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  277. cmd->trace2_child_id = tr2tls_locked_increment(&tr2_next_child_id);
  278. cmd->trace2_child_us_start = us_now;
  279. for_each_wanted_builtin (j, tgt_j)
  280. if (tgt_j->pfn_child_start_fl)
  281. tgt_j->pfn_child_start_fl(file, line,
  282. us_elapsed_absolute, cmd);
  283. }
  284. void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
  285. int child_exit_code)
  286. {
  287. struct tr2_tgt *tgt_j;
  288. int j;
  289. uint64_t us_now;
  290. uint64_t us_elapsed_absolute;
  291. uint64_t us_elapsed_child;
  292. if (!trace2_enabled)
  293. return;
  294. us_now = getnanotime() / 1000;
  295. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  296. if (cmd->trace2_child_us_start)
  297. us_elapsed_child = us_now - cmd->trace2_child_us_start;
  298. else
  299. us_elapsed_child = 0;
  300. for_each_wanted_builtin (j, tgt_j)
  301. if (tgt_j->pfn_child_exit_fl)
  302. tgt_j->pfn_child_exit_fl(file, line,
  303. us_elapsed_absolute,
  304. cmd->trace2_child_id, cmd->pid,
  305. child_exit_code,
  306. us_elapsed_child);
  307. }
  308. int trace2_exec_fl(const char *file, int line, const char *exe,
  309. const char **argv)
  310. {
  311. struct tr2_tgt *tgt_j;
  312. int j;
  313. int exec_id;
  314. uint64_t us_now;
  315. uint64_t us_elapsed_absolute;
  316. if (!trace2_enabled)
  317. return -1;
  318. us_now = getnanotime() / 1000;
  319. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  320. exec_id = tr2tls_locked_increment(&tr2_next_exec_id);
  321. for_each_wanted_builtin (j, tgt_j)
  322. if (tgt_j->pfn_exec_fl)
  323. tgt_j->pfn_exec_fl(file, line, us_elapsed_absolute,
  324. exec_id, exe, argv);
  325. return exec_id;
  326. }
  327. void trace2_exec_result_fl(const char *file, int line, int exec_id, int code)
  328. {
  329. struct tr2_tgt *tgt_j;
  330. int j;
  331. uint64_t us_now;
  332. uint64_t us_elapsed_absolute;
  333. if (!trace2_enabled)
  334. return;
  335. us_now = getnanotime() / 1000;
  336. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  337. for_each_wanted_builtin (j, tgt_j)
  338. if (tgt_j->pfn_exec_result_fl)
  339. tgt_j->pfn_exec_result_fl(
  340. file, line, us_elapsed_absolute, exec_id, code);
  341. }
  342. void trace2_thread_start_fl(const char *file, int line, const char *thread_name)
  343. {
  344. struct tr2_tgt *tgt_j;
  345. int j;
  346. uint64_t us_now;
  347. uint64_t us_elapsed_absolute;
  348. if (!trace2_enabled)
  349. return;
  350. if (tr2tls_is_main_thread()) {
  351. /*
  352. * We should only be called from the new thread's thread-proc,
  353. * so this is technically a bug. But in those cases where the
  354. * main thread also runs the thread-proc function (or when we
  355. * are built with threading disabled), we need to allow it.
  356. *
  357. * Convert this call to a region-enter so the nesting looks
  358. * correct.
  359. */
  360. trace2_region_enter_printf_fl(file, line, NULL, NULL, NULL,
  361. "thread-proc on main: %s",
  362. thread_name);
  363. return;
  364. }
  365. us_now = getnanotime() / 1000;
  366. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  367. tr2tls_create_self(thread_name, us_now);
  368. for_each_wanted_builtin (j, tgt_j)
  369. if (tgt_j->pfn_thread_start_fl)
  370. tgt_j->pfn_thread_start_fl(file, line,
  371. us_elapsed_absolute);
  372. }
  373. void trace2_thread_exit_fl(const char *file, int line)
  374. {
  375. struct tr2_tgt *tgt_j;
  376. int j;
  377. uint64_t us_now;
  378. uint64_t us_elapsed_absolute;
  379. uint64_t us_elapsed_thread;
  380. if (!trace2_enabled)
  381. return;
  382. if (tr2tls_is_main_thread()) {
  383. /*
  384. * We should only be called from the exiting thread's
  385. * thread-proc, so this is technically a bug. But in
  386. * those cases where the main thread also runs the
  387. * thread-proc function (or when we are built with
  388. * threading disabled), we need to allow it.
  389. *
  390. * Convert this call to a region-leave so the nesting
  391. * looks correct.
  392. */
  393. trace2_region_leave_printf_fl(file, line, NULL, NULL, NULL,
  394. "thread-proc on main");
  395. return;
  396. }
  397. us_now = getnanotime() / 1000;
  398. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  399. /*
  400. * Clear any unbalanced regions and then get the relative time
  401. * for the outer-most region (which we pushed when the thread
  402. * started). This gives us the run time of the thread.
  403. */
  404. tr2tls_pop_unwind_self();
  405. us_elapsed_thread = tr2tls_region_elasped_self(us_now);
  406. for_each_wanted_builtin (j, tgt_j)
  407. if (tgt_j->pfn_thread_exit_fl)
  408. tgt_j->pfn_thread_exit_fl(file, line,
  409. us_elapsed_absolute,
  410. us_elapsed_thread);
  411. tr2tls_unset_self();
  412. }
  413. void trace2_def_param_fl(const char *file, int line, const char *param,
  414. const char *value)
  415. {
  416. struct tr2_tgt *tgt_j;
  417. int j;
  418. if (!trace2_enabled)
  419. return;
  420. for_each_wanted_builtin (j, tgt_j)
  421. if (tgt_j->pfn_param_fl)
  422. tgt_j->pfn_param_fl(file, line, param, value);
  423. }
  424. void trace2_def_repo_fl(const char *file, int line, struct repository *repo)
  425. {
  426. struct tr2_tgt *tgt_j;
  427. int j;
  428. if (!trace2_enabled)
  429. return;
  430. if (repo->trace2_repo_id)
  431. return;
  432. repo->trace2_repo_id = tr2tls_locked_increment(&tr2_next_repo_id);
  433. for_each_wanted_builtin (j, tgt_j)
  434. if (tgt_j->pfn_repo_fl)
  435. tgt_j->pfn_repo_fl(file, line, repo);
  436. }
  437. void trace2_region_enter_printf_va_fl(const char *file, int line,
  438. const char *category, const char *label,
  439. const struct repository *repo,
  440. const char *fmt, va_list ap)
  441. {
  442. struct tr2_tgt *tgt_j;
  443. int j;
  444. uint64_t us_now;
  445. uint64_t us_elapsed_absolute;
  446. if (!trace2_enabled)
  447. return;
  448. us_now = getnanotime() / 1000;
  449. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  450. /*
  451. * Print the region-enter message at the current nesting
  452. * (indentation) level and then push a new level.
  453. *
  454. * We expect each target function to treat 'ap' as constant
  455. * and use va_copy.
  456. */
  457. for_each_wanted_builtin (j, tgt_j)
  458. if (tgt_j->pfn_region_enter_printf_va_fl)
  459. tgt_j->pfn_region_enter_printf_va_fl(
  460. file, line, us_elapsed_absolute, category,
  461. label, repo, fmt, ap);
  462. tr2tls_push_self(us_now);
  463. }
  464. void trace2_region_enter_fl(const char *file, int line, const char *category,
  465. const char *label, const struct repository *repo, ...)
  466. {
  467. va_list ap;
  468. va_start(ap, repo);
  469. trace2_region_enter_printf_va_fl(file, line, category, label, repo,
  470. NULL, ap);
  471. va_end(ap);
  472. }
  473. void trace2_region_enter_printf_fl(const char *file, int line,
  474. const char *category, const char *label,
  475. const struct repository *repo,
  476. const char *fmt, ...)
  477. {
  478. va_list ap;
  479. va_start(ap, fmt);
  480. trace2_region_enter_printf_va_fl(file, line, category, label, repo, fmt,
  481. ap);
  482. va_end(ap);
  483. }
  484. #ifndef HAVE_VARIADIC_MACROS
  485. void trace2_region_enter_printf(const char *category, const char *label,
  486. const struct repository *repo, const char *fmt,
  487. ...)
  488. {
  489. va_list ap;
  490. va_start(ap, fmt);
  491. trace2_region_enter_printf_va_fl(NULL, 0, category, label, repo, fmt,
  492. ap);
  493. va_end(ap);
  494. }
  495. #endif
  496. void trace2_region_leave_printf_va_fl(const char *file, int line,
  497. const char *category, const char *label,
  498. const struct repository *repo,
  499. const char *fmt, va_list ap)
  500. {
  501. struct tr2_tgt *tgt_j;
  502. int j;
  503. uint64_t us_now;
  504. uint64_t us_elapsed_absolute;
  505. uint64_t us_elapsed_region;
  506. if (!trace2_enabled)
  507. return;
  508. us_now = getnanotime() / 1000;
  509. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  510. /*
  511. * Get the elapsed time in the current region before we
  512. * pop it off the stack. Pop the stack. And then print
  513. * the perf message at the new (shallower) level so that
  514. * it lines up with the corresponding push/enter.
  515. */
  516. us_elapsed_region = tr2tls_region_elasped_self(us_now);
  517. tr2tls_pop_self();
  518. /*
  519. * We expect each target function to treat 'ap' as constant
  520. * and use va_copy.
  521. */
  522. for_each_wanted_builtin (j, tgt_j)
  523. if (tgt_j->pfn_region_leave_printf_va_fl)
  524. tgt_j->pfn_region_leave_printf_va_fl(
  525. file, line, us_elapsed_absolute,
  526. us_elapsed_region, category, label, repo, fmt,
  527. ap);
  528. }
  529. void trace2_region_leave_fl(const char *file, int line, const char *category,
  530. const char *label, const struct repository *repo, ...)
  531. {
  532. va_list ap;
  533. va_start(ap, repo);
  534. trace2_region_leave_printf_va_fl(file, line, category, label, repo,
  535. NULL, ap);
  536. va_end(ap);
  537. }
  538. void trace2_region_leave_printf_fl(const char *file, int line,
  539. const char *category, const char *label,
  540. const struct repository *repo,
  541. const char *fmt, ...)
  542. {
  543. va_list ap;
  544. va_start(ap, fmt);
  545. trace2_region_leave_printf_va_fl(file, line, category, label, repo, fmt,
  546. ap);
  547. va_end(ap);
  548. }
  549. #ifndef HAVE_VARIADIC_MACROS
  550. void trace2_region_leave_printf(const char *category, const char *label,
  551. const struct repository *repo, const char *fmt,
  552. ...)
  553. {
  554. va_list ap;
  555. va_start(ap, fmt);
  556. trace2_region_leave_printf_va_fl(NULL, 0, category, label, repo, fmt,
  557. ap);
  558. va_end(ap);
  559. }
  560. #endif
  561. void trace2_data_string_fl(const char *file, int line, const char *category,
  562. const struct repository *repo, const char *key,
  563. const char *value)
  564. {
  565. struct tr2_tgt *tgt_j;
  566. int j;
  567. uint64_t us_now;
  568. uint64_t us_elapsed_absolute;
  569. uint64_t us_elapsed_region;
  570. if (!trace2_enabled)
  571. return;
  572. us_now = getnanotime() / 1000;
  573. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  574. us_elapsed_region = tr2tls_region_elasped_self(us_now);
  575. for_each_wanted_builtin (j, tgt_j)
  576. if (tgt_j->pfn_data_fl)
  577. tgt_j->pfn_data_fl(file, line, us_elapsed_absolute,
  578. us_elapsed_region, category, repo,
  579. key, value);
  580. }
  581. void trace2_data_intmax_fl(const char *file, int line, const char *category,
  582. const struct repository *repo, const char *key,
  583. intmax_t value)
  584. {
  585. struct strbuf buf_string = STRBUF_INIT;
  586. if (!trace2_enabled)
  587. return;
  588. strbuf_addf(&buf_string, "%" PRIdMAX, value);
  589. trace2_data_string_fl(file, line, category, repo, key, buf_string.buf);
  590. strbuf_release(&buf_string);
  591. }
  592. void trace2_data_json_fl(const char *file, int line, const char *category,
  593. const struct repository *repo, const char *key,
  594. const struct json_writer *value)
  595. {
  596. struct tr2_tgt *tgt_j;
  597. int j;
  598. uint64_t us_now;
  599. uint64_t us_elapsed_absolute;
  600. uint64_t us_elapsed_region;
  601. if (!trace2_enabled)
  602. return;
  603. us_now = getnanotime() / 1000;
  604. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  605. us_elapsed_region = tr2tls_region_elasped_self(us_now);
  606. for_each_wanted_builtin (j, tgt_j)
  607. if (tgt_j->pfn_data_json_fl)
  608. tgt_j->pfn_data_json_fl(file, line, us_elapsed_absolute,
  609. us_elapsed_region, category,
  610. repo, key, value);
  611. }
  612. void trace2_printf_va_fl(const char *file, int line, const char *fmt,
  613. va_list ap)
  614. {
  615. struct tr2_tgt *tgt_j;
  616. int j;
  617. uint64_t us_now;
  618. uint64_t us_elapsed_absolute;
  619. if (!trace2_enabled)
  620. return;
  621. us_now = getnanotime() / 1000;
  622. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  623. /*
  624. * We expect each target function to treat 'ap' as constant
  625. * and use va_copy.
  626. */
  627. for_each_wanted_builtin (j, tgt_j)
  628. if (tgt_j->pfn_printf_va_fl)
  629. tgt_j->pfn_printf_va_fl(file, line, us_elapsed_absolute,
  630. fmt, ap);
  631. }
  632. void trace2_printf_fl(const char *file, int line, const char *fmt, ...)
  633. {
  634. va_list ap;
  635. va_start(ap, fmt);
  636. trace2_printf_va_fl(file, line, fmt, ap);
  637. va_end(ap);
  638. }
  639. #ifndef HAVE_VARIADIC_MACROS
  640. void trace2_printf(const char *fmt, ...)
  641. {
  642. va_list ap;
  643. va_start(ap, fmt);
  644. trace2_printf_va_fl(NULL, 0, fmt, ap);
  645. va_end(ap);
  646. }
  647. #endif