Coverage Report

Created: 2023-11-19 07:08

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