Coverage Report

Created: 2025-12-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/trace2/tr2_tgt_perf.c
Line
Count
Source
1
#define DISABLE_SIGN_COMPARE_WARNINGS
2
3
#include "git-compat-util.h"
4
#include "config.h"
5
#include "repository.h"
6
#include "run-command.h"
7
#include "quote.h"
8
#include "version.h"
9
#include "json-writer.h"
10
#include "trace2/tr2_dst.h"
11
#include "trace2/tr2_sid.h"
12
#include "trace2/tr2_sysenv.h"
13
#include "trace2/tr2_tbuf.h"
14
#include "trace2/tr2_tgt.h"
15
#include "trace2/tr2_tls.h"
16
#include "trace2/tr2_tmr.h"
17
18
static struct tr2_dst tr2dst_perf = {
19
  .sysenv_var = TR2_SYSENV_PERF,
20
};
21
22
/*
23
 * Use TR2_SYSENV_PERF_BRIEF to omit the "<time> <file>:<line>"
24
 * fields from each line written to the builtin performance target.
25
 *
26
 * Unit tests may want to use this to help with testing.
27
 */
28
static int tr2env_perf_be_brief;
29
30
0
#define TR2FMT_PERF_FL_WIDTH (28)
31
0
#define TR2FMT_PERF_MAX_EVENT_NAME (12)
32
0
#define TR2FMT_PERF_REPO_WIDTH (3)
33
0
#define TR2FMT_PERF_CATEGORY_WIDTH (12)
34
35
0
#define TR2_INDENT (2)
36
0
#define TR2_INDENT_LENGTH(ctx) (((ctx)->nr_open_regions - 1) * TR2_INDENT)
37
38
static int fn_init(void)
39
0
{
40
0
  int want = tr2_dst_trace_want(&tr2dst_perf);
41
0
  int want_brief;
42
0
  const char *brief;
43
44
0
  if (!want)
45
0
    return want;
46
47
0
  brief = tr2_sysenv_get(TR2_SYSENV_PERF_BRIEF);
48
0
  if (brief && *brief &&
49
0
      ((want_brief = git_parse_maybe_bool(brief)) != -1))
50
0
    tr2env_perf_be_brief = want_brief;
51
52
0
  return want;
53
0
}
54
55
static void fn_term(void)
56
0
{
57
0
  tr2_dst_trace_disable(&tr2dst_perf);
58
0
}
59
60
/*
61
 * Format trace line prefix in human-readable classic format for
62
 * the performance target:
63
 *     "[<time> [<file>:<line>] <bar>] <nr_parents> <bar>
64
 *         <thread_name> <bar> <event_name> <bar> [<repo>] <bar>
65
 *         [<elapsed_absolute>] [<elapsed_relative>] <bar>
66
 *         [<category>] <bar> [<dots>] "
67
 */
68
static void perf_fmt_prepare(const char *event_name,
69
           struct tr2tls_thread_ctx *ctx, const char *file,
70
           int line, const struct repository *repo,
71
           uint64_t *p_us_elapsed_absolute,
72
           uint64_t *p_us_elapsed_relative,
73
           const char *category, struct strbuf *buf)
74
0
{
75
0
  int len;
76
77
0
  strbuf_setlen(buf, 0);
78
79
0
  if (!tr2env_perf_be_brief) {
80
0
    struct tr2_tbuf tb_now;
81
0
    size_t fl_end_col;
82
83
0
    tr2_tbuf_local_time(&tb_now);
84
0
    strbuf_addstr(buf, tb_now.buf);
85
0
    strbuf_addch(buf, ' ');
86
87
0
    fl_end_col = buf->len + TR2FMT_PERF_FL_WIDTH;
88
89
0
    if (file && *file) {
90
0
      struct strbuf buf_fl = STRBUF_INIT;
91
92
0
      strbuf_addf(&buf_fl, "%s:%d", file, line);
93
94
0
      if (buf_fl.len <= TR2FMT_PERF_FL_WIDTH)
95
0
        strbuf_addbuf(buf, &buf_fl);
96
0
      else {
97
0
        size_t avail = TR2FMT_PERF_FL_WIDTH - 3;
98
0
        strbuf_addstr(buf, "...");
99
0
        strbuf_add(buf,
100
0
             &buf_fl.buf[buf_fl.len - avail],
101
0
             avail);
102
0
      }
103
104
0
      strbuf_release(&buf_fl);
105
0
    }
106
107
0
    while (buf->len < fl_end_col)
108
0
      strbuf_addch(buf, ' ');
109
110
0
    strbuf_addstr(buf, " | ");
111
0
  }
112
113
0
  strbuf_addf(buf, "d%d | ", tr2_sid_depth());
114
0
  strbuf_addf(buf, "%-*s | %-*s | ", TR2_MAX_THREAD_NAME,
115
0
        ctx->thread_name, TR2FMT_PERF_MAX_EVENT_NAME,
116
0
        event_name);
117
118
0
  len = buf->len + TR2FMT_PERF_REPO_WIDTH;
119
0
  if (repo)
120
0
    strbuf_addf(buf, "r%d ", repo->trace2_repo_id);
121
0
  while (buf->len < len)
122
0
    strbuf_addch(buf, ' ');
123
0
  strbuf_addstr(buf, " | ");
124
125
0
  if (p_us_elapsed_absolute)
126
0
    strbuf_addf(buf, "%9.6f | ",
127
0
          ((double)(*p_us_elapsed_absolute)) / 1000000.0);
128
0
  else
129
0
    strbuf_addf(buf, "%9s | ", " ");
130
131
0
  if (p_us_elapsed_relative)
132
0
    strbuf_addf(buf, "%9.6f | ",
133
0
          ((double)(*p_us_elapsed_relative)) / 1000000.0);
134
0
  else
135
0
    strbuf_addf(buf, "%9s | ", " ");
136
137
0
  strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH,
138
0
        TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : ""));
139
140
0
  if (ctx->nr_open_regions > 0)
141
0
    strbuf_addchars(buf, '.', TR2_INDENT_LENGTH(ctx));
142
0
}
143
144
static void perf_io_write_fl(const char *file, int line, const char *event_name,
145
           const struct repository *repo,
146
           uint64_t *p_us_elapsed_absolute,
147
           uint64_t *p_us_elapsed_relative,
148
           const char *category,
149
           const struct strbuf *buf_payload)
150
0
{
151
0
  struct tr2tls_thread_ctx *ctx = tr2tls_get_self();
152
0
  struct strbuf buf_line = STRBUF_INIT;
153
154
0
  perf_fmt_prepare(event_name, ctx, file, line, repo,
155
0
       p_us_elapsed_absolute, p_us_elapsed_relative, category,
156
0
       &buf_line);
157
0
  strbuf_addbuf(&buf_line, buf_payload);
158
0
  tr2_dst_write_line(&tr2dst_perf, &buf_line);
159
0
  strbuf_release(&buf_line);
160
0
}
161
162
static void fn_version_fl(const char *file, int line)
163
0
{
164
0
  const char *event_name = "version";
165
0
  struct strbuf buf_payload = STRBUF_INIT;
166
167
0
  strbuf_addstr(&buf_payload, git_version_string);
168
169
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
170
0
       &buf_payload);
171
0
  strbuf_release(&buf_payload);
172
0
}
173
174
static void fn_start_fl(const char *file, int line,
175
      uint64_t us_elapsed_absolute, const char **argv)
176
0
{
177
0
  const char *event_name = "start";
178
0
  struct strbuf buf_payload = STRBUF_INIT;
179
180
0
  sq_append_quote_argv_pretty(&buf_payload, argv);
181
182
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
183
0
       NULL, NULL, &buf_payload);
184
0
  strbuf_release(&buf_payload);
185
0
}
186
187
static void fn_exit_fl(const char *file, int line, uint64_t us_elapsed_absolute,
188
           int code)
189
0
{
190
0
  const char *event_name = "exit";
191
0
  struct strbuf buf_payload = STRBUF_INIT;
192
193
0
  strbuf_addf(&buf_payload, "code:%d", code);
194
195
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
196
0
       NULL, NULL, &buf_payload);
197
0
  strbuf_release(&buf_payload);
198
0
}
199
200
static void fn_signal(uint64_t us_elapsed_absolute, int signo)
201
0
{
202
0
  const char *event_name = "signal";
203
0
  struct strbuf buf_payload = STRBUF_INIT;
204
205
0
  strbuf_addf(&buf_payload, "signo:%d", signo);
206
207
0
  perf_io_write_fl(__FILE__, __LINE__, event_name, NULL,
208
0
       &us_elapsed_absolute, NULL, NULL, &buf_payload);
209
0
  strbuf_release(&buf_payload);
210
0
}
211
212
static void fn_atexit(uint64_t us_elapsed_absolute, int code)
213
0
{
214
0
  const char *event_name = "atexit";
215
0
  struct strbuf buf_payload = STRBUF_INIT;
216
217
0
  strbuf_addf(&buf_payload, "code:%d", code);
218
219
0
  perf_io_write_fl(__FILE__, __LINE__, event_name, NULL,
220
0
       &us_elapsed_absolute, NULL, NULL, &buf_payload);
221
0
  strbuf_release(&buf_payload);
222
0
}
223
224
static void maybe_append_string_va(struct strbuf *buf, const char *fmt,
225
           va_list ap)
226
0
{
227
0
  if (fmt && *fmt) {
228
0
    va_list copy_ap;
229
230
0
    va_copy(copy_ap, ap);
231
0
    strbuf_vaddf(buf, fmt, copy_ap);
232
0
    va_end(copy_ap);
233
0
    return;
234
0
  }
235
0
}
236
237
static void fn_error_va_fl(const char *file, int line, const char *fmt,
238
         va_list ap)
239
0
{
240
0
  const char *event_name = "error";
241
0
  struct strbuf buf_payload = STRBUF_INIT;
242
243
0
  maybe_append_string_va(&buf_payload, fmt, ap);
244
245
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
246
0
       &buf_payload);
247
0
  strbuf_release(&buf_payload);
248
0
}
249
250
static void fn_command_path_fl(const char *file, int line, const char *pathname)
251
0
{
252
0
  const char *event_name = "cmd_path";
253
0
  struct strbuf buf_payload = STRBUF_INIT;
254
255
0
  strbuf_addstr(&buf_payload, pathname);
256
257
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
258
0
       &buf_payload);
259
0
  strbuf_release(&buf_payload);
260
0
}
261
262
static void fn_command_ancestry_fl(const char *file, int line, const char **parent_names)
263
0
{
264
0
  const char *event_name = "cmd_ancestry";
265
0
  struct strbuf buf_payload = STRBUF_INIT;
266
267
0
  strbuf_addstr(&buf_payload, "ancestry:[");
268
  /* It's not an argv but the rules are basically the same. */
269
0
  sq_append_quote_argv_pretty(&buf_payload, parent_names);
270
0
  strbuf_addch(&buf_payload, ']');
271
272
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
273
0
       &buf_payload);
274
0
  strbuf_release(&buf_payload);
275
0
}
276
277
static void fn_command_name_fl(const char *file, int line, const char *name,
278
             const char *hierarchy)
279
0
{
280
0
  const char *event_name = "cmd_name";
281
0
  struct strbuf buf_payload = STRBUF_INIT;
282
283
0
  strbuf_addstr(&buf_payload, name);
284
0
  if (hierarchy && *hierarchy)
285
0
    strbuf_addf(&buf_payload, " (%s)", hierarchy);
286
287
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
288
0
       &buf_payload);
289
0
  strbuf_release(&buf_payload);
290
0
}
291
292
static void fn_command_mode_fl(const char *file, int line, const char *mode)
293
0
{
294
0
  const char *event_name = "cmd_mode";
295
0
  struct strbuf buf_payload = STRBUF_INIT;
296
297
0
  strbuf_addstr(&buf_payload, mode);
298
299
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
300
0
       &buf_payload);
301
0
  strbuf_release(&buf_payload);
302
0
}
303
304
static void fn_alias_fl(const char *file, int line, const char *alias,
305
      const char **argv)
306
0
{
307
0
  const char *event_name = "alias";
308
0
  struct strbuf buf_payload = STRBUF_INIT;
309
310
0
  strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
311
0
  sq_append_quote_argv_pretty(&buf_payload, argv);
312
0
  strbuf_addch(&buf_payload, ']');
313
314
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL, NULL,
315
0
       &buf_payload);
316
0
  strbuf_release(&buf_payload);
317
0
}
318
319
static void fn_child_start_fl(const char *file, int line,
320
            uint64_t us_elapsed_absolute,
321
            const struct child_process *cmd)
322
0
{
323
0
  const char *event_name = "child_start";
324
0
  struct strbuf buf_payload = STRBUF_INIT;
325
326
0
  if (cmd->trace2_hook_name) {
327
0
    strbuf_addf(&buf_payload, "[ch%d] class:hook hook:%s",
328
0
          cmd->trace2_child_id, cmd->trace2_hook_name);
329
0
  } else {
330
0
    const char *child_class =
331
0
      cmd->trace2_child_class ? cmd->trace2_child_class : "?";
332
0
    strbuf_addf(&buf_payload, "[ch%d] class:%s",
333
0
          cmd->trace2_child_id, child_class);
334
0
  }
335
336
0
  if (cmd->dir) {
337
0
    strbuf_addstr(&buf_payload, " cd:");
338
0
    sq_quote_buf_pretty(&buf_payload, cmd->dir);
339
0
  }
340
341
0
  strbuf_addstr(&buf_payload, " argv:[");
342
0
  if (cmd->git_cmd) {
343
0
    strbuf_addstr(&buf_payload, "git");
344
0
    if (cmd->args.nr)
345
0
      strbuf_addch(&buf_payload, ' ');
346
0
  }
347
0
  sq_append_quote_argv_pretty(&buf_payload, cmd->args.v);
348
0
  strbuf_addch(&buf_payload, ']');
349
350
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
351
0
       NULL, NULL, &buf_payload);
352
0
  strbuf_release(&buf_payload);
353
0
}
354
355
static void fn_child_exit_fl(const char *file, int line,
356
           uint64_t us_elapsed_absolute, int cid, int pid,
357
           int code, uint64_t us_elapsed_child)
358
0
{
359
0
  const char *event_name = "child_exit";
360
0
  struct strbuf buf_payload = STRBUF_INIT;
361
362
0
  strbuf_addf(&buf_payload, "[ch%d] pid:%d code:%d", cid, pid, code);
363
364
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
365
0
       &us_elapsed_child, NULL, &buf_payload);
366
0
  strbuf_release(&buf_payload);
367
0
}
368
369
static void fn_child_ready_fl(const char *file, int line,
370
            uint64_t us_elapsed_absolute, int cid, int pid,
371
            const char *ready, uint64_t us_elapsed_child)
372
0
{
373
0
  const char *event_name = "child_ready";
374
0
  struct strbuf buf_payload = STRBUF_INIT;
375
376
0
  strbuf_addf(&buf_payload, "[ch%d] pid:%d ready:%s", cid, pid, ready);
377
378
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
379
0
       &us_elapsed_child, NULL, &buf_payload);
380
0
  strbuf_release(&buf_payload);
381
0
}
382
383
static void fn_thread_start_fl(const char *file, int line,
384
             uint64_t us_elapsed_absolute)
385
0
{
386
0
  const char *event_name = "thread_start";
387
0
  struct strbuf buf_payload = STRBUF_INIT;
388
389
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
390
0
       NULL, NULL, &buf_payload);
391
0
  strbuf_release(&buf_payload);
392
0
}
393
394
static void fn_thread_exit_fl(const char *file, int line,
395
            uint64_t us_elapsed_absolute,
396
            uint64_t us_elapsed_thread)
397
0
{
398
0
  const char *event_name = "thread_exit";
399
0
  struct strbuf buf_payload = STRBUF_INIT;
400
401
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
402
0
       &us_elapsed_thread, NULL, &buf_payload);
403
0
  strbuf_release(&buf_payload);
404
0
}
405
406
static void fn_exec_fl(const char *file, int line, uint64_t us_elapsed_absolute,
407
           int exec_id, const char *exe, const char **argv)
408
0
{
409
0
  const char *event_name = "exec";
410
0
  struct strbuf buf_payload = STRBUF_INIT;
411
412
0
  strbuf_addf(&buf_payload, "id:%d ", exec_id);
413
0
  strbuf_addstr(&buf_payload, "argv:[");
414
0
  if (exe) {
415
0
    strbuf_addstr(&buf_payload, exe);
416
0
    if (argv[0])
417
0
      strbuf_addch(&buf_payload, ' ');
418
0
  }
419
0
  sq_append_quote_argv_pretty(&buf_payload, argv);
420
0
  strbuf_addch(&buf_payload, ']');
421
422
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
423
0
       NULL, NULL, &buf_payload);
424
0
  strbuf_release(&buf_payload);
425
0
}
426
427
static void fn_exec_result_fl(const char *file, int line,
428
            uint64_t us_elapsed_absolute, int exec_id,
429
            int code)
430
0
{
431
0
  const char *event_name = "exec_result";
432
0
  struct strbuf buf_payload = STRBUF_INIT;
433
434
0
  strbuf_addf(&buf_payload, "id:%d code:%d", exec_id, code);
435
0
  if (code > 0)
436
0
    strbuf_addf(&buf_payload, " err:%s", strerror(code));
437
438
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
439
0
       NULL, NULL, &buf_payload);
440
0
  strbuf_release(&buf_payload);
441
0
}
442
443
static void fn_param_fl(const char *file, int line, const char *param,
444
      const char *value, const struct key_value_info *kvi)
445
0
{
446
0
  const char *event_name = "def_param";
447
0
  struct strbuf buf_payload = STRBUF_INIT;
448
0
  struct strbuf scope_payload = STRBUF_INIT;
449
0
  enum config_scope scope = kvi->scope;
450
0
  const char *scope_name = config_scope_name(scope);
451
0
  strbuf_addstr(&buf_payload, param);
452
0
  if (value)
453
0
    strbuf_addf(&buf_payload, ":%s", value);
454
0
  strbuf_addf(&scope_payload, "%s:%s", "scope", scope_name);
455
456
0
  perf_io_write_fl(file, line, event_name, NULL, NULL, NULL,
457
0
       scope_payload.buf, &buf_payload);
458
0
  strbuf_release(&buf_payload);
459
0
  strbuf_release(&scope_payload);
460
0
}
461
462
static void fn_repo_fl(const char *file, int line,
463
           const struct repository *repo)
464
0
{
465
0
  const char *event_name = "def_repo";
466
0
  struct strbuf buf_payload = STRBUF_INIT;
467
468
0
  strbuf_addstr(&buf_payload, "worktree:");
469
0
  sq_quote_buf_pretty(&buf_payload, repo->worktree);
470
471
0
  perf_io_write_fl(file, line, event_name, repo, NULL, NULL, NULL,
472
0
       &buf_payload);
473
0
  strbuf_release(&buf_payload);
474
0
}
475
476
static void fn_region_enter_printf_va_fl(const char *file, int line,
477
           uint64_t us_elapsed_absolute,
478
           const char *category,
479
           const char *label,
480
           const struct repository *repo,
481
           const char *fmt, va_list ap)
482
0
{
483
0
  const char *event_name = "region_enter";
484
0
  struct strbuf buf_payload = STRBUF_INIT;
485
486
0
  if (label)
487
0
    strbuf_addf(&buf_payload, "label:%s", label);
488
0
  if (fmt && *fmt) {
489
0
    strbuf_addch(&buf_payload, ' ');
490
0
    maybe_append_string_va(&buf_payload, fmt, ap);
491
0
  }
492
493
0
  perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
494
0
       NULL, category, &buf_payload);
495
0
  strbuf_release(&buf_payload);
496
0
}
497
498
static void fn_region_leave_printf_va_fl(
499
  const char *file, int line, uint64_t us_elapsed_absolute,
500
  uint64_t us_elapsed_region, const char *category, const char *label,
501
  const struct repository *repo, const char *fmt, va_list ap)
502
0
{
503
0
  const char *event_name = "region_leave";
504
0
  struct strbuf buf_payload = STRBUF_INIT;
505
506
0
  if (label)
507
0
    strbuf_addf(&buf_payload, "label:%s", label);
508
0
  if (fmt && *fmt) {
509
0
    strbuf_addch(&buf_payload, ' ' );
510
0
    maybe_append_string_va(&buf_payload, fmt, ap);
511
0
  }
512
513
0
  perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
514
0
       &us_elapsed_region, category, &buf_payload);
515
0
  strbuf_release(&buf_payload);
516
0
}
517
518
static void fn_data_fl(const char *file, int line, uint64_t us_elapsed_absolute,
519
           uint64_t us_elapsed_region, const char *category,
520
           const struct repository *repo, const char *key,
521
           const char *value)
522
0
{
523
0
  const char *event_name = "data";
524
0
  struct strbuf buf_payload = STRBUF_INIT;
525
526
0
  strbuf_addf(&buf_payload, "%s:%s", key, value);
527
528
0
  perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
529
0
       &us_elapsed_region, category, &buf_payload);
530
0
  strbuf_release(&buf_payload);
531
0
}
532
533
static void fn_data_json_fl(const char *file, int line,
534
          uint64_t us_elapsed_absolute,
535
          uint64_t us_elapsed_region, const char *category,
536
          const struct repository *repo, const char *key,
537
          const struct json_writer *value)
538
0
{
539
0
  const char *event_name = "data_json";
540
0
  struct strbuf buf_payload = STRBUF_INIT;
541
542
0
  strbuf_addf(&buf_payload, "%s:%s", key, value->json.buf);
543
544
0
  perf_io_write_fl(file, line, event_name, repo, &us_elapsed_absolute,
545
0
       &us_elapsed_region, category, &buf_payload);
546
0
  strbuf_release(&buf_payload);
547
0
}
548
549
static void fn_printf_va_fl(const char *file, int line,
550
          uint64_t us_elapsed_absolute, const char *fmt,
551
          va_list ap)
552
0
{
553
0
  const char *event_name = "printf";
554
0
  struct strbuf buf_payload = STRBUF_INIT;
555
556
0
  maybe_append_string_va(&buf_payload, fmt, ap);
557
558
0
  perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
559
0
       NULL, NULL, &buf_payload);
560
0
  strbuf_release(&buf_payload);
561
0
}
562
563
static void fn_timer(const struct tr2_timer_metadata *meta,
564
         const struct tr2_timer *timer,
565
         int is_final_data)
566
0
{
567
0
  const char *event_name = is_final_data ? "timer" : "th_timer";
568
0
  struct strbuf buf_payload = STRBUF_INIT;
569
0
  double t_total = NS_TO_SEC(timer->total_ns);
570
0
  double t_min = NS_TO_SEC(timer->min_ns);
571
0
  double t_max = NS_TO_SEC(timer->max_ns);
572
573
0
  strbuf_addf(&buf_payload, ("name:%s"
574
0
           " intervals:%"PRIu64
575
0
           " total:%8.6f min:%8.6f max:%8.6f"),
576
0
        meta->name,
577
0
        timer->interval_count,
578
0
        t_total, t_min, t_max);
579
580
0
  perf_io_write_fl(__FILE__, __LINE__, event_name, NULL, NULL, NULL,
581
0
       meta->category, &buf_payload);
582
0
  strbuf_release(&buf_payload);
583
0
}
584
585
static void fn_counter(const struct tr2_counter_metadata *meta,
586
           const struct tr2_counter *counter,
587
           int is_final_data)
588
0
{
589
0
  const char *event_name = is_final_data ? "counter" : "th_counter";
590
0
  struct strbuf buf_payload = STRBUF_INIT;
591
592
0
  strbuf_addf(&buf_payload, "name:%s value:%"PRIu64,
593
0
        meta->name,
594
0
        counter->value);
595
596
0
  perf_io_write_fl(__FILE__, __LINE__, event_name, NULL, NULL, NULL,
597
0
       meta->category, &buf_payload);
598
0
  strbuf_release(&buf_payload);
599
0
}
600
601
struct tr2_tgt tr2_tgt_perf = {
602
  .pdst = &tr2dst_perf,
603
604
  .pfn_init = fn_init,
605
  .pfn_term = fn_term,
606
607
  .pfn_version_fl = fn_version_fl,
608
  .pfn_start_fl = fn_start_fl,
609
  .pfn_exit_fl = fn_exit_fl,
610
  .pfn_signal = fn_signal,
611
  .pfn_atexit = fn_atexit,
612
  .pfn_error_va_fl = fn_error_va_fl,
613
  .pfn_command_path_fl = fn_command_path_fl,
614
  .pfn_command_ancestry_fl = fn_command_ancestry_fl,
615
  .pfn_command_name_fl = fn_command_name_fl,
616
  .pfn_command_mode_fl = fn_command_mode_fl,
617
  .pfn_alias_fl = fn_alias_fl,
618
  .pfn_child_start_fl = fn_child_start_fl,
619
  .pfn_child_exit_fl = fn_child_exit_fl,
620
  .pfn_child_ready_fl = fn_child_ready_fl,
621
  .pfn_thread_start_fl = fn_thread_start_fl,
622
  .pfn_thread_exit_fl = fn_thread_exit_fl,
623
  .pfn_exec_fl = fn_exec_fl,
624
  .pfn_exec_result_fl = fn_exec_result_fl,
625
  .pfn_param_fl = fn_param_fl,
626
  .pfn_repo_fl = fn_repo_fl,
627
  .pfn_region_enter_printf_va_fl = fn_region_enter_printf_va_fl,
628
  .pfn_region_leave_printf_va_fl = fn_region_leave_printf_va_fl,
629
  .pfn_data_fl = fn_data_fl,
630
  .pfn_data_json_fl = fn_data_json_fl,
631
  .pfn_printf_va_fl = fn_printf_va_fl,
632
  .pfn_timer = fn_timer,
633
  .pfn_counter = fn_counter,
634
};