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.

552 lines
15KB

  1. #include "cache.h"
  2. #include "config.h"
  3. #include "run-command.h"
  4. #include "quote.h"
  5. #include "version.h"
  6. #include "json-writer.h"
  7. #include "trace2/tr2_dst.h"
  8. #include "trace2/tr2_sid.h"
  9. #include "trace2/tr2_sysenv.h"
  10. #include "trace2/tr2_tbuf.h"
  11. #include "trace2/tr2_tgt.h"
  12. #include "trace2/tr2_tls.h"
  13. static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0, 0 };
  14. /*
  15. * Use TR2_SYSENV_PERF_BRIEF to omit the "<time> <file>:<line>"
  16. * fields from each line written to the builtin performance target.
  17. *
  18. * Unit tests may want to use this to help with testing.
  19. */
  20. static int tr2env_perf_be_brief;
  21. #define TR2FMT_PERF_FL_WIDTH (28)
  22. #define TR2FMT_PERF_MAX_EVENT_NAME (12)
  23. #define TR2FMT_PERF_REPO_WIDTH (3)
  24. #define TR2FMT_PERF_CATEGORY_WIDTH (12)
  25. #define TR2_INDENT (2)
  26. #define TR2_INDENT_LENGTH(ctx) (((ctx)->nr_open_regions - 1) * TR2_INDENT)
  27. static int fn_init(void)
  28. {
  29. int want = tr2_dst_trace_want(&tr2dst_perf);
  30. int want_brief;
  31. const char *brief;
  32. if (!want)
  33. return want;
  34. brief = tr2_sysenv_get(TR2_SYSENV_PERF_BRIEF);
  35. if (brief && *brief &&
  36. ((want_brief = git_parse_maybe_bool(brief)) != -1))
  37. tr2env_perf_be_brief = want_brief;
  38. return want;
  39. }
  40. static void fn_term(void)
  41. {
  42. tr2_dst_trace_disable(&tr2dst_perf);
  43. }
  44. /*
  45. * Format trace line prefix in human-readable classic format for
  46. * the performance target:
  47. * "[<time> [<file>:<line>] <bar>] <nr_parents> <bar>
  48. * <thread_name> <bar> <event_name> <bar> [<repo>] <bar>
  49. * [<elapsed_absolute>] [<elapsed_relative>] <bar>
  50. * [<category>] <bar> [<dots>] "
  51. */
  52. static void perf_fmt_prepare(const char *event_name,
  53. struct tr2tls_thread_ctx *ctx, const char *file,
  54. int line, const struct repository *repo,
  55. uint64_t *p_us_elapsed_absolute,
  56. uint64_t *p_us_elapsed_relative,
  57. const char *category, struct strbuf *buf)
  58. {
  59. int len;
  60. strbuf_setlen(buf, 0);
  61. if (!tr2env_perf_be_brief) {
  62. struct tr2_tbuf tb_now;
  63. size_t fl_end_col;
  64. tr2_tbuf_local_time(&tb_now);
  65. strbuf_addstr(buf, tb_now.buf);
  66. strbuf_addch(buf, ' ');
  67. fl_end_col = buf->len + TR2FMT_PERF_FL_WIDTH;
  68. if (file && *file) {
  69. struct strbuf buf_fl = STRBUF_INIT;
  70. strbuf_addf(&buf_fl, "%s:%d", file, line);
  71. if (buf_fl.len <= TR2FMT_PERF_FL_WIDTH)
  72. strbuf_addbuf(buf, &buf_fl);
  73. else {
  74. size_t avail = TR2FMT_PERF_FL_WIDTH - 3;
  75. strbuf_addstr(buf, "...");
  76. strbuf_add(buf,
  77. &buf_fl.buf[buf_fl.len - avail],
  78. avail);
  79. }
  80. strbuf_release(&buf_fl);
  81. }
  82. while (buf->len < fl_end_col)
  83. strbuf_addch(buf, ' ');
  84. strbuf_addstr(buf, " | ");
  85. }
  86. strbuf_addf(buf, "d%d | ", tr2_sid_depth());
  87. strbuf_addf(buf, "%-*s | %-*s | ", TR2_MAX_THREAD_NAME,
  88. ctx->thread_name.buf, TR2FMT_PERF_MAX_EVENT_NAME,
  89. event_name);
  90. len = buf->len + TR2FMT_PERF_REPO_WIDTH;
  91. if (repo)
  92. strbuf_addf(buf, "r%d ", repo->trace2_repo_id);
  93. while (buf->len < len)
  94. strbuf_addch(buf, ' ');
  95. strbuf_addstr(buf, " | ");
  96. if (p_us_elapsed_absolute)
  97. strbuf_addf(buf, "%9.6f | ",
  98. ((double)(*p_us_elapsed_absolute)) / 1000000.0);
  99. else
  100. strbuf_addf(buf, "%9s | ", " ");
  101. if (p_us_elapsed_relative)
  102. strbuf_addf(buf, "%9.6f | ",
  103. ((double)(*p_us_elapsed_relative)) / 1000000.0);
  104. else
  105. strbuf_addf(buf, "%9s | ", " ");
  106. strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
  107. TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : ""));
  108. if (ctx->nr_open_regions > 0)
  109. strbuf_addchars(buf, '.', TR2_INDENT_LENGTH(ctx));
  110. }
  111. static void perf_io_write_fl(const char *file, int line, const char *event_name,
  112. const struct repository *repo,
  113. uint64_t *p_us_elapsed_absolute,
  114. uint64_t *p_us_elapsed_relative,
  115. const char *category,
  116. const struct strbuf *buf_payload)
  117. {
  118. struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
  119. struct strbuf buf_line = STRBUF_INIT;
  120. perf_fmt_prepare(event_name, ctx, file, line, repo,
  121. p_us_elapsed_absolute, p_us_elapsed_relative, category,
  122. &buf_line);
  123. strbuf_addbuf(&buf_line, buf_payload);
  124. tr2_dst_write_line(&tr2dst_perf, &buf_line);
  125. strbuf_release(&buf_line);
  126. }
  127. static void fn_version_fl(const char *file, int line)
  128. {
  129. const char *event_name = "version";
  130. struct strbuf buf_payload = STRBUF_INIT;
  131. strbuf_addstr(&buf_payload, git_version_string);
  132. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  133. &buf_payload);
  134. strbuf_release(&buf_payload);
  135. }
  136. static void fn_start_fl(const char *file, int line,
  137. uint64_t us_elapsed_absolute, const char **argv)
  138. {
  139. const char *event_name = "start";
  140. struct strbuf buf_payload = STRBUF_INIT;
  141. sq_append_quote_argv_pretty(&buf_payload, argv);
  142. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  143. NULL, NULL, &buf_payload);
  144. strbuf_release(&buf_payload);
  145. }
  146. static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute,
  147. int code)
  148. {
  149. const char *event_name = "exit";
  150. struct strbuf buf_payload = STRBUF_INIT;
  151. strbuf_addf(&buf_payload, "code:%d", code);
  152. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  153. NULL, NULL, &buf_payload);
  154. strbuf_release(&buf_payload);
  155. }
  156. static void fn_signal(uint64_t us_elapsed_absolute, int signo)
  157. {
  158. const char *event_name = "signal";
  159. struct strbuf buf_payload = STRBUF_INIT;
  160. strbuf_addf(&buf_payload, "signo:%d", signo);
  161. perf_io_write_fl(__FILE__, __LINE__, event_name, NULL,
  162. &us_elapsed_absolute, NULL, NULL, &buf_payload);
  163. strbuf_release(&buf_payload);
  164. }
  165. static void fn_atexit(uint64_t us_elapsed_absolute, int code)
  166. {
  167. const char *event_name = "atexit";
  168. struct strbuf buf_payload = STRBUF_INIT;
  169. strbuf_addf(&buf_payload, "code:%d", code);
  170. perf_io_write_fl(__FILE__, __LINE__, event_name, NULL,
  171. &us_elapsed_absolute, NULL, NULL, &buf_payload);
  172. strbuf_release(&buf_payload);
  173. }
  174. static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
  175. va_list ap)
  176. {
  177. if (fmt && *fmt) {
  178. va_list copy_ap;
  179. va_copy(copy_ap, ap);
  180. strbuf_vaddf(buf, fmt, copy_ap);
  181. va_end(copy_ap);
  182. return;
  183. }
  184. }
  185. static void fn_error_va_fl(const char *file, int line, const char *fmt,
  186. va_list ap)
  187. {
  188. const char *event_name = "error";
  189. struct strbuf buf_payload = STRBUF_INIT;
  190. maybe_append_string_va(&buf_payload, fmt, ap);
  191. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  192. &buf_payload);
  193. strbuf_release(&buf_payload);
  194. }
  195. static void fn_command_path_fl(const char *file, int line, const char *pathname)
  196. {
  197. const char *event_name = "cmd_path";
  198. struct strbuf buf_payload = STRBUF_INIT;
  199. strbuf_addstr(&buf_payload, pathname);
  200. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  201. &buf_payload);
  202. strbuf_release(&buf_payload);
  203. }
  204. static void fn_command_name_fl(const char *file, int line, const char *name,
  205. const char *hierarchy)
  206. {
  207. const char *event_name = "cmd_name";
  208. struct strbuf buf_payload = STRBUF_INIT;
  209. strbuf_addstr(&buf_payload, name);
  210. if (hierarchy && *hierarchy)
  211. strbuf_addf(&buf_payload, " (%s)", hierarchy);
  212. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  213. &buf_payload);
  214. strbuf_release(&buf_payload);
  215. }
  216. static void fn_command_mode_fl(const char *file, int line, const char *mode)
  217. {
  218. const char *event_name = "cmd_mode";
  219. struct strbuf buf_payload = STRBUF_INIT;
  220. strbuf_addstr(&buf_payload, mode);
  221. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  222. &buf_payload);
  223. strbuf_release(&buf_payload);
  224. }
  225. static void fn_alias_fl(const char *file, int line, const char *alias,
  226. const char **argv)
  227. {
  228. const char *event_name = "alias";
  229. struct strbuf buf_payload = STRBUF_INIT;
  230. strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
  231. sq_append_quote_argv_pretty(&buf_payload, argv);
  232. strbuf_addch(&buf_payload, ']');
  233. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  234. &buf_payload);
  235. strbuf_release(&buf_payload);
  236. }
  237. static void fn_child_start_fl(const char *file, int line,
  238. uint64_t us_elapsed_absolute,
  239. const struct child_process *cmd)
  240. {
  241. const char *event_name = "child_start";
  242. struct strbuf buf_payload = STRBUF_INIT;
  243. if (cmd->trace2_hook_name) {
  244. strbuf_addf(&buf_payload, "[ch%d] class:hook hook:%s",
  245. cmd->trace2_child_id, cmd->trace2_hook_name);
  246. } else {
  247. const char *child_class =
  248. cmd->trace2_child_class ? cmd->trace2_child_class : "?";
  249. strbuf_addf(&buf_payload, "[ch%d] class:%s",
  250. cmd->trace2_child_id, child_class);
  251. }
  252. if (cmd->dir) {
  253. strbuf_addstr(&buf_payload, " cd:");
  254. sq_quote_buf_pretty(&buf_payload, cmd->dir);
  255. }
  256. strbuf_addstr(&buf_payload, " argv:[");
  257. if (cmd->git_cmd) {
  258. strbuf_addstr(&buf_payload, "git");
  259. if (cmd->argv[0])
  260. strbuf_addch(&buf_payload, ' ');
  261. }
  262. sq_append_quote_argv_pretty(&buf_payload, cmd->argv);
  263. strbuf_addch(&buf_payload, ']');
  264. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  265. NULL, NULL, &buf_payload);
  266. strbuf_release(&buf_payload);
  267. }
  268. static void fn_child_exit_fl(const char *file, int line,
  269. uint64_t us_elapsed_absolute, int cid, int pid,
  270. int code, uint64_t us_elapsed_child)
  271. {
  272. const char *event_name = "child_exit";
  273. struct strbuf buf_payload = STRBUF_INIT;
  274. strbuf_addf(&buf_payload, "[ch%d] pid:%d code:%d", cid, pid, code);
  275. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  276. &us_elapsed_child, NULL, &buf_payload);
  277. strbuf_release(&buf_payload);
  278. }
  279. static void fn_thread_start_fl(const char *file, int line,
  280. uint64_t us_elapsed_absolute)
  281. {
  282. const char *event_name = "thread_start";
  283. struct strbuf buf_payload = STRBUF_INIT;
  284. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  285. NULL, NULL, &buf_payload);
  286. strbuf_release(&buf_payload);
  287. }
  288. static void fn_thread_exit_fl(const char *file, int line,
  289. uint64_t us_elapsed_absolute,
  290. uint64_t us_elapsed_thread)
  291. {
  292. const char *event_name = "thread_exit";
  293. struct strbuf buf_payload = STRBUF_INIT;
  294. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  295. &us_elapsed_thread, NULL, &buf_payload);
  296. strbuf_release(&buf_payload);
  297. }
  298. static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
  299. int exec_id, const char *exe, const char **argv)
  300. {
  301. const char *event_name = "exec";
  302. struct strbuf buf_payload = STRBUF_INIT;
  303. strbuf_addf(&buf_payload, "id:%d ", exec_id);
  304. strbuf_addstr(&buf_payload, "argv:[");
  305. if (exe) {
  306. strbuf_addstr(&buf_payload, exe);
  307. if (argv[0])
  308. strbuf_addch(&buf_payload, ' ');
  309. }
  310. sq_append_quote_argv_pretty(&buf_payload, argv);
  311. strbuf_addch(&buf_payload, ']');
  312. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  313. NULL, NULL, &buf_payload);
  314. strbuf_release(&buf_payload);
  315. }
  316. static void fn_exec_result_fl(const char *file, int line,
  317. uint64_t us_elapsed_absolute, int exec_id,
  318. int code)
  319. {
  320. const char *event_name = "exec_result";
  321. struct strbuf buf_payload = STRBUF_INIT;
  322. strbuf_addf(&buf_payload, "id:%d code:%d", exec_id, code);
  323. if (code > 0)
  324. strbuf_addf(&buf_payload, " err:%s", strerror(code));
  325. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  326. NULL, NULL, &buf_payload);
  327. strbuf_release(&buf_payload);
  328. }
  329. static void fn_param_fl(const char *file, int line, const char *param,
  330. const char *value)
  331. {
  332. const char *event_name = "def_param";
  333. struct strbuf buf_payload = STRBUF_INIT;
  334. strbuf_addf(&buf_payload, "%s:%s", param, value);
  335. perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
  336. &buf_payload);
  337. strbuf_release(&buf_payload);
  338. }
  339. static void fn_repo_fl(const char *file, int line,
  340. const struct repository *repo)
  341. {
  342. const char *event_name = "def_repo";
  343. struct strbuf buf_payload = STRBUF_INIT;
  344. strbuf_addstr(&buf_payload, "worktree:");
  345. sq_quote_buf_pretty(&buf_payload, repo->worktree);
  346. perf_io_write_fl(file, line, event_name, repo, NULL, NULL, NULL,
  347. &buf_payload);
  348. strbuf_release(&buf_payload);
  349. }
  350. static void fn_region_enter_printf_va_fl(const char *file, int line,
  351. uint64_t us_elapsed_absolute,
  352. const char *category,
  353. const char *label,
  354. const struct repository *repo,
  355. const char *fmt, va_list ap)
  356. {
  357. const char *event_name = "region_enter";
  358. struct strbuf buf_payload = STRBUF_INIT;
  359. if (label)
  360. strbuf_addf(&buf_payload, "label:%s", label);
  361. if (fmt && *fmt) {
  362. strbuf_addch(&buf_payload, ' ');
  363. maybe_append_string_va(&buf_payload, fmt, ap);
  364. }
  365. perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
  366. NULL, category, &buf_payload);
  367. strbuf_release(&buf_payload);
  368. }
  369. static void fn_region_leave_printf_va_fl(
  370. const char *file, int line, uint64_t us_elapsed_absolute,
  371. uint64_t us_elapsed_region, const char *category, const char *label,
  372. const struct repository *repo, const char *fmt, va_list ap)
  373. {
  374. const char *event_name = "region_leave";
  375. struct strbuf buf_payload = STRBUF_INIT;
  376. if (label)
  377. strbuf_addf(&buf_payload, "label:%s", label);
  378. if (fmt && *fmt) {
  379. strbuf_addch(&buf_payload, ' ' );
  380. maybe_append_string_va(&buf_payload, fmt, ap);
  381. }
  382. perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
  383. &us_elapsed_region, category, &buf_payload);
  384. strbuf_release(&buf_payload);
  385. }
  386. static void fn_data_fl(const char *file, int line, uint64_t us_elapsed_absolute,
  387. uint64_t us_elapsed_region, const char *category,
  388. const struct repository *repo, const char *key,
  389. const char *value)
  390. {
  391. const char *event_name = "data";
  392. struct strbuf buf_payload = STRBUF_INIT;
  393. strbuf_addf(&buf_payload, "%s:%s", key, value);
  394. perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
  395. &us_elapsed_region, category, &buf_payload);
  396. strbuf_release(&buf_payload);
  397. }
  398. static void fn_data_json_fl(const char *file, int line,
  399. uint64_t us_elapsed_absolute,
  400. uint64_t us_elapsed_region, const char *category,
  401. const struct repository *repo, const char *key,
  402. const struct json_writer *value)
  403. {
  404. const char *event_name = "data_json";
  405. struct strbuf buf_payload = STRBUF_INIT;
  406. strbuf_addf(&buf_payload, "%s:%s", key, value->json.buf);
  407. perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
  408. &us_elapsed_region, category, &buf_payload);
  409. strbuf_release(&buf_payload);
  410. }
  411. static void fn_printf_va_fl(const char *file, int line,
  412. uint64_t us_elapsed_absolute, const char *fmt,
  413. va_list ap)
  414. {
  415. const char *event_name = "printf";
  416. struct strbuf buf_payload = STRBUF_INIT;
  417. maybe_append_string_va(&buf_payload, fmt, ap);
  418. perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
  419. NULL, NULL, &buf_payload);
  420. strbuf_release(&buf_payload);
  421. }
  422. struct tr2_tgt tr2_tgt_perf = {
  423. &tr2dst_perf,
  424. fn_init,
  425. fn_term,
  426. fn_version_fl,
  427. fn_start_fl,
  428. fn_exit_fl,
  429. fn_signal,
  430. fn_atexit,
  431. fn_error_va_fl,
  432. fn_command_path_fl,
  433. fn_command_name_fl,
  434. fn_command_mode_fl,
  435. fn_alias_fl,
  436. fn_child_start_fl,
  437. fn_child_exit_fl,
  438. fn_thread_start_fl,
  439. fn_thread_exit_fl,
  440. fn_exec_fl,
  441. fn_exec_result_fl,
  442. fn_param_fl,
  443. fn_repo_fl,
  444. fn_region_enter_printf_va_fl,
  445. fn_region_leave_printf_va_fl,
  446. fn_data_fl,
  447. fn_data_json_fl,
  448. fn_printf_va_fl,
  449. };