THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

786 lines
18KB

  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_sysenv_release();
  108. trace2_enabled = 0;
  109. }
  110. static void tr2main_signal_handler(int signo)
  111. {
  112. struct tr2_tgt *tgt_j;
  113. int j;
  114. uint64_t us_now;
  115. uint64_t us_elapsed_absolute;
  116. us_now = getnanotime() / 1000;
  117. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  118. for_each_wanted_builtin (j, tgt_j)
  119. if (tgt_j->pfn_signal)
  120. tgt_j->pfn_signal(us_elapsed_absolute, signo);
  121. sigchain_pop(signo);
  122. raise(signo);
  123. }
  124. void trace2_initialize_clock(void)
  125. {
  126. tr2tls_start_process_clock();
  127. }
  128. void trace2_initialize_fl(const char *file, int line)
  129. {
  130. struct tr2_tgt *tgt_j;
  131. int j;
  132. if (trace2_enabled)
  133. return;
  134. tr2_sysenv_load();
  135. if (!tr2_tgt_want_builtins())
  136. return;
  137. trace2_enabled = 1;
  138. tr2_sid_get();
  139. atexit(tr2main_atexit_handler);
  140. sigchain_push(SIGPIPE, tr2main_signal_handler);
  141. tr2tls_init();
  142. /*
  143. * Emit 'version' message on each active builtin target.
  144. */
  145. for_each_wanted_builtin (j, tgt_j)
  146. if (tgt_j->pfn_version_fl)
  147. tgt_j->pfn_version_fl(file, line);
  148. }
  149. int trace2_is_enabled(void)
  150. {
  151. return trace2_enabled;
  152. }
  153. void trace2_cmd_start_fl(const char *file, int line, const char **argv)
  154. {
  155. struct tr2_tgt *tgt_j;
  156. int j;
  157. uint64_t us_now;
  158. uint64_t us_elapsed_absolute;
  159. if (!trace2_enabled)
  160. return;
  161. us_now = getnanotime() / 1000;
  162. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  163. for_each_wanted_builtin (j, tgt_j)
  164. if (tgt_j->pfn_start_fl)
  165. tgt_j->pfn_start_fl(file, line, us_elapsed_absolute,
  166. argv);
  167. }
  168. int trace2_cmd_exit_fl(const char *file, int line, int code)
  169. {
  170. struct tr2_tgt *tgt_j;
  171. int j;
  172. uint64_t us_now;
  173. uint64_t us_elapsed_absolute;
  174. code &= 0xff;
  175. if (!trace2_enabled)
  176. return code;
  177. trace2_collect_process_info(TRACE2_PROCESS_INFO_EXIT);
  178. tr2main_exit_code = code;
  179. us_now = getnanotime() / 1000;
  180. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  181. for_each_wanted_builtin (j, tgt_j)
  182. if (tgt_j->pfn_exit_fl)
  183. tgt_j->pfn_exit_fl(file, line, us_elapsed_absolute,
  184. code);
  185. return code;
  186. }
  187. void trace2_cmd_error_va_fl(const char *file, int line, const char *fmt,
  188. va_list ap)
  189. {
  190. struct tr2_tgt *tgt_j;
  191. int j;
  192. if (!trace2_enabled)
  193. return;
  194. /*
  195. * We expect each target function to treat 'ap' as constant
  196. * and use va_copy (because an 'ap' can only be walked once).
  197. */
  198. for_each_wanted_builtin (j, tgt_j)
  199. if (tgt_j->pfn_error_va_fl)
  200. tgt_j->pfn_error_va_fl(file, line, fmt, ap);
  201. }
  202. void trace2_cmd_path_fl(const char *file, int line, const char *pathname)
  203. {
  204. struct tr2_tgt *tgt_j;
  205. int j;
  206. if (!trace2_enabled)
  207. return;
  208. for_each_wanted_builtin (j, tgt_j)
  209. if (tgt_j->pfn_command_path_fl)
  210. tgt_j->pfn_command_path_fl(file, line, pathname);
  211. }
  212. void trace2_cmd_name_fl(const char *file, int line, const char *name)
  213. {
  214. struct tr2_tgt *tgt_j;
  215. const char *hierarchy;
  216. int j;
  217. if (!trace2_enabled)
  218. return;
  219. tr2_cmd_name_append_hierarchy(name);
  220. hierarchy = tr2_cmd_name_get_hierarchy();
  221. for_each_wanted_builtin (j, tgt_j)
  222. if (tgt_j->pfn_command_name_fl)
  223. tgt_j->pfn_command_name_fl(file, line, name, hierarchy);
  224. }
  225. void trace2_cmd_mode_fl(const char *file, int line, const char *mode)
  226. {
  227. struct tr2_tgt *tgt_j;
  228. int j;
  229. if (!trace2_enabled)
  230. return;
  231. for_each_wanted_builtin (j, tgt_j)
  232. if (tgt_j->pfn_command_mode_fl)
  233. tgt_j->pfn_command_mode_fl(file, line, mode);
  234. }
  235. void trace2_cmd_alias_fl(const char *file, int line, const char *alias,
  236. const char **argv)
  237. {
  238. struct tr2_tgt *tgt_j;
  239. int j;
  240. if (!trace2_enabled)
  241. return;
  242. for_each_wanted_builtin (j, tgt_j)
  243. if (tgt_j->pfn_alias_fl)
  244. tgt_j->pfn_alias_fl(file, line, alias, argv);
  245. }
  246. void trace2_cmd_list_config_fl(const char *file, int line)
  247. {
  248. if (!trace2_enabled)
  249. return;
  250. tr2_cfg_list_config_fl(file, line);
  251. }
  252. void trace2_cmd_set_config_fl(const char *file, int line, const char *key,
  253. const char *value)
  254. {
  255. if (!trace2_enabled)
  256. return;
  257. tr2_cfg_set_fl(file, line, key, value);
  258. }
  259. void trace2_child_start_fl(const char *file, int line,
  260. struct child_process *cmd)
  261. {
  262. struct tr2_tgt *tgt_j;
  263. int j;
  264. uint64_t us_now;
  265. uint64_t us_elapsed_absolute;
  266. if (!trace2_enabled)
  267. return;
  268. us_now = getnanotime() / 1000;
  269. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  270. cmd->trace2_child_id = tr2tls_locked_increment(&tr2_next_child_id);
  271. cmd->trace2_child_us_start = us_now;
  272. for_each_wanted_builtin (j, tgt_j)
  273. if (tgt_j->pfn_child_start_fl)
  274. tgt_j->pfn_child_start_fl(file, line,
  275. us_elapsed_absolute, cmd);
  276. }
  277. void trace2_child_exit_fl(const char *file, int line, struct child_process *cmd,
  278. int child_exit_code)
  279. {
  280. struct tr2_tgt *tgt_j;
  281. int j;
  282. uint64_t us_now;
  283. uint64_t us_elapsed_absolute;
  284. uint64_t us_elapsed_child;
  285. if (!trace2_enabled)
  286. return;
  287. us_now = getnanotime() / 1000;
  288. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  289. if (cmd->trace2_child_us_start)
  290. us_elapsed_child = us_now - cmd->trace2_child_us_start;
  291. else
  292. us_elapsed_child = 0;
  293. for_each_wanted_builtin (j, tgt_j)
  294. if (tgt_j->pfn_child_exit_fl)
  295. tgt_j->pfn_child_exit_fl(file, line,
  296. us_elapsed_absolute,
  297. cmd->trace2_child_id, cmd->pid,
  298. child_exit_code,
  299. us_elapsed_child);
  300. }
  301. int trace2_exec_fl(const char *file, int line, const char *exe,
  302. const char **argv)
  303. {
  304. struct tr2_tgt *tgt_j;
  305. int j;
  306. int exec_id;
  307. uint64_t us_now;
  308. uint64_t us_elapsed_absolute;
  309. if (!trace2_enabled)
  310. return -1;
  311. us_now = getnanotime() / 1000;
  312. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  313. exec_id = tr2tls_locked_increment(&tr2_next_exec_id);
  314. for_each_wanted_builtin (j, tgt_j)
  315. if (tgt_j->pfn_exec_fl)
  316. tgt_j->pfn_exec_fl(file, line, us_elapsed_absolute,
  317. exec_id, exe, argv);
  318. return exec_id;
  319. }
  320. void trace2_exec_result_fl(const char *file, int line, int exec_id, int code)
  321. {
  322. struct tr2_tgt *tgt_j;
  323. int j;
  324. uint64_t us_now;
  325. uint64_t us_elapsed_absolute;
  326. if (!trace2_enabled)
  327. return;
  328. us_now = getnanotime() / 1000;
  329. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  330. for_each_wanted_builtin (j, tgt_j)
  331. if (tgt_j->pfn_exec_result_fl)
  332. tgt_j->pfn_exec_result_fl(
  333. file, line, us_elapsed_absolute, exec_id, code);
  334. }
  335. void trace2_thread_start_fl(const char *file, int line, const char *thread_name)
  336. {
  337. struct tr2_tgt *tgt_j;
  338. int j;
  339. uint64_t us_now;
  340. uint64_t us_elapsed_absolute;
  341. if (!trace2_enabled)
  342. return;
  343. if (tr2tls_is_main_thread()) {
  344. /*
  345. * We should only be called from the new thread's thread-proc,
  346. * so this is technically a bug. But in those cases where the
  347. * main thread also runs the thread-proc function (or when we
  348. * are built with threading disabled), we need to allow it.
  349. *
  350. * Convert this call to a region-enter so the nesting looks
  351. * correct.
  352. */
  353. trace2_region_enter_printf_fl(file, line, NULL, NULL, NULL,
  354. "thread-proc on main: %s",
  355. thread_name);
  356. return;
  357. }
  358. us_now = getnanotime() / 1000;
  359. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  360. tr2tls_create_self(thread_name, us_now);
  361. for_each_wanted_builtin (j, tgt_j)
  362. if (tgt_j->pfn_thread_start_fl)
  363. tgt_j->pfn_thread_start_fl(file, line,
  364. us_elapsed_absolute);
  365. }
  366. void trace2_thread_exit_fl(const char *file, int line)
  367. {
  368. struct tr2_tgt *tgt_j;
  369. int j;
  370. uint64_t us_now;
  371. uint64_t us_elapsed_absolute;
  372. uint64_t us_elapsed_thread;
  373. if (!trace2_enabled)
  374. return;
  375. if (tr2tls_is_main_thread()) {
  376. /*
  377. * We should only be called from the exiting thread's
  378. * thread-proc, so this is technically a bug. But in
  379. * those cases where the main thread also runs the
  380. * thread-proc function (or when we are built with
  381. * threading disabled), we need to allow it.
  382. *
  383. * Convert this call to a region-leave so the nesting
  384. * looks correct.
  385. */
  386. trace2_region_leave_printf_fl(file, line, NULL, NULL, NULL,
  387. "thread-proc on main");
  388. return;
  389. }
  390. us_now = getnanotime() / 1000;
  391. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  392. /*
  393. * Clear any unbalanced regions and then get the relative time
  394. * for the outer-most region (which we pushed when the thread
  395. * started). This gives us the run time of the thread.
  396. */
  397. tr2tls_pop_unwind_self();
  398. us_elapsed_thread = tr2tls_region_elasped_self(us_now);
  399. for_each_wanted_builtin (j, tgt_j)
  400. if (tgt_j->pfn_thread_exit_fl)
  401. tgt_j->pfn_thread_exit_fl(file, line,
  402. us_elapsed_absolute,
  403. us_elapsed_thread);
  404. tr2tls_unset_self();
  405. }
  406. void trace2_def_param_fl(const char *file, int line, const char *param,
  407. const char *value)
  408. {
  409. struct tr2_tgt *tgt_j;
  410. int j;
  411. if (!trace2_enabled)
  412. return;
  413. for_each_wanted_builtin (j, tgt_j)
  414. if (tgt_j->pfn_param_fl)
  415. tgt_j->pfn_param_fl(file, line, param, value);
  416. }
  417. void trace2_def_repo_fl(const char *file, int line, struct repository *repo)
  418. {
  419. struct tr2_tgt *tgt_j;
  420. int j;
  421. if (!trace2_enabled)
  422. return;
  423. if (repo->trace2_repo_id)
  424. return;
  425. repo->trace2_repo_id = tr2tls_locked_increment(&tr2_next_repo_id);
  426. for_each_wanted_builtin (j, tgt_j)
  427. if (tgt_j->pfn_repo_fl)
  428. tgt_j->pfn_repo_fl(file, line, repo);
  429. }
  430. void trace2_region_enter_printf_va_fl(const char *file, int line,
  431. const char *category, const char *label,
  432. const struct repository *repo,
  433. const char *fmt, va_list ap)
  434. {
  435. struct tr2_tgt *tgt_j;
  436. int j;
  437. uint64_t us_now;
  438. uint64_t us_elapsed_absolute;
  439. if (!trace2_enabled)
  440. return;
  441. us_now = getnanotime() / 1000;
  442. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  443. /*
  444. * Print the region-enter message at the current nesting
  445. * (indentation) level and then push a new level.
  446. *
  447. * We expect each target function to treat 'ap' as constant
  448. * and use va_copy.
  449. */
  450. for_each_wanted_builtin (j, tgt_j)
  451. if (tgt_j->pfn_region_enter_printf_va_fl)
  452. tgt_j->pfn_region_enter_printf_va_fl(
  453. file, line, us_elapsed_absolute, category,
  454. label, repo, fmt, ap);
  455. tr2tls_push_self(us_now);
  456. }
  457. void trace2_region_enter_fl(const char *file, int line, const char *category,
  458. const char *label, const struct repository *repo, ...)
  459. {
  460. va_list ap;
  461. va_start(ap, repo);
  462. trace2_region_enter_printf_va_fl(file, line, category, label, repo,
  463. NULL, ap);
  464. va_end(ap);
  465. }
  466. void trace2_region_enter_printf_fl(const char *file, int line,
  467. const char *category, const char *label,
  468. const struct repository *repo,
  469. const char *fmt, ...)
  470. {
  471. va_list ap;
  472. va_start(ap, fmt);
  473. trace2_region_enter_printf_va_fl(file, line, category, label, repo, fmt,
  474. ap);
  475. va_end(ap);
  476. }
  477. #ifndef HAVE_VARIADIC_MACROS
  478. void trace2_region_enter_printf(const char *category, const char *label,
  479. const struct repository *repo, const char *fmt,
  480. ...)
  481. {
  482. va_list ap;
  483. va_start(ap, fmt);
  484. trace2_region_enter_printf_va_fl(NULL, 0, category, label, repo, fmt,
  485. ap);
  486. va_end(ap);
  487. }
  488. #endif
  489. void trace2_region_leave_printf_va_fl(const char *file, int line,
  490. const char *category, const char *label,
  491. const struct repository *repo,
  492. const char *fmt, va_list ap)
  493. {
  494. struct tr2_tgt *tgt_j;
  495. int j;
  496. uint64_t us_now;
  497. uint64_t us_elapsed_absolute;
  498. uint64_t us_elapsed_region;
  499. if (!trace2_enabled)
  500. return;
  501. us_now = getnanotime() / 1000;
  502. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  503. /*
  504. * Get the elapsed time in the current region before we
  505. * pop it off the stack. Pop the stack. And then print
  506. * the perf message at the new (shallower) level so that
  507. * it lines up with the corresponding push/enter.
  508. */
  509. us_elapsed_region = tr2tls_region_elasped_self(us_now);
  510. tr2tls_pop_self();
  511. /*
  512. * We expect each target function to treat 'ap' as constant
  513. * and use va_copy.
  514. */
  515. for_each_wanted_builtin (j, tgt_j)
  516. if (tgt_j->pfn_region_leave_printf_va_fl)
  517. tgt_j->pfn_region_leave_printf_va_fl(
  518. file, line, us_elapsed_absolute,
  519. us_elapsed_region, category, label, repo, fmt,
  520. ap);
  521. }
  522. void trace2_region_leave_fl(const char *file, int line, const char *category,
  523. const char *label, const struct repository *repo, ...)
  524. {
  525. va_list ap;
  526. va_start(ap, repo);
  527. trace2_region_leave_printf_va_fl(file, line, category, label, repo,
  528. NULL, ap);
  529. va_end(ap);
  530. }
  531. void trace2_region_leave_printf_fl(const char *file, int line,
  532. const char *category, const char *label,
  533. const struct repository *repo,
  534. const char *fmt, ...)
  535. {
  536. va_list ap;
  537. va_start(ap, fmt);
  538. trace2_region_leave_printf_va_fl(file, line, category, label, repo, fmt,
  539. ap);
  540. va_end(ap);
  541. }
  542. #ifndef HAVE_VARIADIC_MACROS
  543. void trace2_region_leave_printf(const char *category, const char *label,
  544. const struct repository *repo, const char *fmt,
  545. ...)
  546. {
  547. va_list ap;
  548. va_start(ap, fmt);
  549. trace2_region_leave_printf_va_fl(NULL, 0, category, label, repo, fmt,
  550. ap);
  551. va_end(ap);
  552. }
  553. #endif
  554. void trace2_data_string_fl(const char *file, int line, const char *category,
  555. const struct repository *repo, const char *key,
  556. const char *value)
  557. {
  558. struct tr2_tgt *tgt_j;
  559. int j;
  560. uint64_t us_now;
  561. uint64_t us_elapsed_absolute;
  562. uint64_t us_elapsed_region;
  563. if (!trace2_enabled)
  564. return;
  565. us_now = getnanotime() / 1000;
  566. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  567. us_elapsed_region = tr2tls_region_elasped_self(us_now);
  568. for_each_wanted_builtin (j, tgt_j)
  569. if (tgt_j->pfn_data_fl)
  570. tgt_j->pfn_data_fl(file, line, us_elapsed_absolute,
  571. us_elapsed_region, category, repo,
  572. key, value);
  573. }
  574. void trace2_data_intmax_fl(const char *file, int line, const char *category,
  575. const struct repository *repo, const char *key,
  576. intmax_t value)
  577. {
  578. struct strbuf buf_string = STRBUF_INIT;
  579. if (!trace2_enabled)
  580. return;
  581. strbuf_addf(&buf_string, "%" PRIdMAX, value);
  582. trace2_data_string_fl(file, line, category, repo, key, buf_string.buf);
  583. strbuf_release(&buf_string);
  584. }
  585. void trace2_data_json_fl(const char *file, int line, const char *category,
  586. const struct repository *repo, const char *key,
  587. const struct json_writer *value)
  588. {
  589. struct tr2_tgt *tgt_j;
  590. int j;
  591. uint64_t us_now;
  592. uint64_t us_elapsed_absolute;
  593. uint64_t us_elapsed_region;
  594. if (!trace2_enabled)
  595. return;
  596. us_now = getnanotime() / 1000;
  597. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  598. us_elapsed_region = tr2tls_region_elasped_self(us_now);
  599. for_each_wanted_builtin (j, tgt_j)
  600. if (tgt_j->pfn_data_json_fl)
  601. tgt_j->pfn_data_json_fl(file, line, us_elapsed_absolute,
  602. us_elapsed_region, category,
  603. repo, key, value);
  604. }
  605. void trace2_printf_va_fl(const char *file, int line, const char *fmt,
  606. va_list ap)
  607. {
  608. struct tr2_tgt *tgt_j;
  609. int j;
  610. uint64_t us_now;
  611. uint64_t us_elapsed_absolute;
  612. if (!trace2_enabled)
  613. return;
  614. us_now = getnanotime() / 1000;
  615. us_elapsed_absolute = tr2tls_absolute_elapsed(us_now);
  616. /*
  617. * We expect each target function to treat 'ap' as constant
  618. * and use va_copy.
  619. */
  620. for_each_wanted_builtin (j, tgt_j)
  621. if (tgt_j->pfn_printf_va_fl)
  622. tgt_j->pfn_printf_va_fl(file, line, us_elapsed_absolute,
  623. fmt, ap);
  624. }
  625. void trace2_printf_fl(const char *file, int line, const char *fmt, ...)
  626. {
  627. va_list ap;
  628. va_start(ap, fmt);
  629. trace2_printf_va_fl(file, line, fmt, ap);
  630. va_end(ap);
  631. }
  632. #ifndef HAVE_VARIADIC_MACROS
  633. void trace2_printf(const char *fmt, ...)
  634. {
  635. va_list ap;
  636. va_start(ap, fmt);
  637. trace2_printf_va_fl(NULL, 0, fmt, ap);
  638. va_end(ap);
  639. }
  640. #endif