YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
yac_pak.c
Go to the documentation of this file.
1// Copyright (c) 2026 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5/*
6 * YAC PAK - YAC Performance Analysis Kit
7 * Lightweight per-rank event tracing tool
8 */
9
10#include <mpi.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <stdarg.h>
15#include <sys/stat.h>
16#include <unistd.h>
17#include <errno.h>
18#include <limits.h>
19#include <time.h>
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include "yac_config.h"
26#include "yac_pak.h"
27#include "yac_assert.h"
28#include "yac_mpi_common.h"
29#include "ensure_array_size.h"
30#include "utils_core.h"
31#include "utils_common.h"
32#include "io_utils.h"
33
34/* Environment variables:
35 * YAC_PAK_TRACE=0|1 enable tracing (default: 0)
36 * YAC_PAK_TRACE_LEVEL=0|1|2 coupling trace level (default: 1);
37 * level 0: no coupling events (setup events
38 * still recorded if TRACE_SETUP=1)
39 * level 1: PUT/GET/AGET exchange events
40 * level 2: additionally the nested
41 * interpolation/compute regions
42 * YAC_PAK_TRACE_SETUP=0|1 also record setup-phase events (default: 0)
43 * YAC_PAK_TRACE_CAPACITY=<n> event buffer size per rank (default: 4096)
44 * buffer grows automatically; aborts on OOM
45 * YAC_PAK_TRACE_DIR=<path> output directory (default: auto-generated)
46 * YAC_PAK_TRACE_STRIDE=<n> write only every n-th rank of each component
47 * (default: 1) the first rank of a component
48 * always writes
49 * YAC_PAK_TRACE_FLUSH_TIME=0|1 include flush_duration_s in header
50 * (default: 1)
51 * YAC_PAK_TRACE_CONFIG=0|1 store coupling configuration in trace
52 * directory at enddef (default: 0)
53 * (only for YAC_PAK_TRACE=1)
54 * YAC_PAK_TRACE_WRITE_MODE=at_finalize|instant
55 * when event rows are written (default:
56 * at_finalize). "instant" writes each row as
57 * it occurs and keeps a {..}.open file with
58 * the events currently in progress.
59 *
60 * Output: each rank writes {dir}/{component}_r{rank}.csv
61 */
62
63#define YAC_PAK_TRACE_ENV "YAC_PAK_TRACE"
64#define YAC_PAK_TRACE_LEVEL_ENV "YAC_PAK_TRACE_LEVEL"
65#define YAC_PAK_TRACE_SETUP_ENV "YAC_PAK_TRACE_SETUP"
66#define YAC_PAK_TRACE_CAPACITY_ENV "YAC_PAK_TRACE_CAPACITY"
67#define YAC_PAK_TRACE_DIR_ENV "YAC_PAK_TRACE_DIR"
68#define YAC_PAK_TRACE_STRIDE_ENV "YAC_PAK_TRACE_STRIDE"
69#define YAC_PAK_TRACE_FLUSH_TIME_ENV "YAC_PAK_TRACE_FLUSH_TIME"
70#define YAC_PAK_TRACE_CONFIG_ENV "YAC_PAK_TRACE_CONFIG"
71#define YAC_PAK_TRACE_WRITE_MODE_ENV "YAC_PAK_TRACE_WRITE_MODE"
72#define YAC_PAK_TRACE_VERBOSE_ENV "YAC_PAK_TRACE_VERBOSE"
73
74enum {
77};
78
82
88
89typedef struct {
90 char * name;
91 double total;
92 int count;
93 double start;
96
97typedef struct {
98 char * field;
99 char * component;
101 char * grid;
103 char * datetime;
106
107/* In-progress (pending) event slot */
114
119typedef struct {
120 char * buf;
121 size_t len;
122 size_t capacity;
124
125/* Completed (finished) event record */
131
133struct yac_pak {
134
135 /* --- general --- */
136 MPI_Comm comm;
137 int rank;
138 int size;
139
140 /* --- timers --- */
144
145 /* --- tracing --- */
154
156
157 /* Only used by write mode "instant": the trace file, kept open for the
158 * whole run, and a companion file holding the events currently in
159 * progress. Both are NULL in write mode "at_finalize". */
161 FILE * open_file;
166
169
173
177
179 /* -1 until yac_pak_set_component */
182
185};
186
187/* ------------------------------------------------------------------ */
188/* Static helpers */
189/* ------------------------------------------------------------------ */
190
192 yac_pak_event_type_pairs,
204
205static char const * yac_pak_event_type_to_str(yac_pak_event_type_t type) {
206 char const * name =
208 yac_pak_event_type_pairs,
209 (size_t)yac_pak_event_type_pairs_size,
210 (int)type);
211 return name ? name : "UNKNOWN";
212}
213
214/* Setup-phase lifecycle events (gated by YAC_PAK_TRACE_SETUP, independently
215 * of the coupling trace level). */
223
225 yac_pak_trace_write_mode_pairs,
228
229static yac_pak_trace_write_mode_t get_trace_write_mode(MPI_Comm comm) {
230
231 char * str_value =
232 yac_getenv_str(YAC_PAK_TRACE_WRITE_MODE_ENV, "at_finalize", comm);
233
234 int const mode =
236 yac_pak_trace_write_mode_pairs,
237 (size_t)yac_pak_trace_write_mode_pairs_size, str_value);
238
240 mode != INT_MAX,
241 "\"%s\" is not a valid value for environment variable %s "
242 "(expected \"at_finalize\" or \"instant\")",
244
245 free(str_value);
246
247 return (yac_pak_trace_write_mode_t)mode;
248}
249
250static int directory_exists(char const * path) {
251 struct stat st;
252 return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
253}
254
255static char const * get_component_name(struct yac_pak const * pak) {
256 return pak->component_name ? pak->component_name : "yac_pak_unknown";
257}
258
259/* within the component once it is known, in the communicator before that */
260static int compute_is_writer(struct yac_pak const * pak) {
261 int const rank = (pak->comp_rank >= 0) ? pak->comp_rank : pak->rank;
262 return (rank % pak->trace_stride) == 0;
263}
264
265static void pak_make_trace_dir(char const * path, int verbose) {
267 !mkdir(path, 0755), "could not create trace directory '%s': %s",
268 path, strerror(errno));
269 if (verbose) fprintf(stderr, "YAC PAK trace: writing to %s/\n", path);
270}
271
273 struct yac_pak const * pak, char const * suffix, int rank) {
274 char const * comp = get_component_name(pak);
275 char const * dir = pak->output_dir ? pak->output_dir : ".";
276 size_t const len =
277 strlen(dir) + 1 + strlen(comp) + 16 + strlen(suffix) + 1;
278 char * path = xmalloc(len);
279 int const n =
280 snprintf(path, len, "%s/%s_r%d%s", dir, comp, rank, suffix);
282 n >= 0 && (size_t)n < len, "snprintf failed or truncated (n=%d)", n);
283 return path;
284}
285
286/* ------------------------------------------------------------------ */
287/* Trace file format */
288/* Single definition of the header and of a row. */
289/* ------------------------------------------------------------------ */
290
300static void str_appendf(yac_pak_str_t * str, char const * fmt, ...)
301 __attribute__((format(printf, 2, 3)));
302
303static void str_appendf(yac_pak_str_t * str, char const * fmt, ...) {
304
305 va_list args, args_size;
306 va_start(args, fmt);
307 va_copy(args_size, args);
308
309 int const n = vsnprintf(NULL, 0, fmt, args_size);
310 va_end(args_size);
311 YAC_ASSERT(n >= 0, "vsnprintf failed while building a trace string");
312
313 ENSURE_ARRAY_SIZE(str->buf, str->capacity, str->len + (size_t)n + 1);
314 vsnprintf(str->buf + str->len, (size_t)n + 1, fmt, args);
315 str->len += (size_t)n;
316
317 va_end(args);
318}
319
328 yac_pak_str_t * str, struct yac_pak const * pak, double flush_dur) {
329
331 str,
332 "# yac_pak_version=v" YAC_PAK_VERSION_STRING "\n"
333 "# wtime_ref=%.9f\n"
334 "# epoch_ref=%.9f\n",
336 if (pak->trace_flush_time && (flush_dur >= 0.0))
337 str_appendf(str, "# flush_duration_s=%.6f\n", flush_dur);
338 str_appendf(str, "# trace_stride=%d\n", pak->trace_stride);
339 if (pak->comp_size > 0)
341 str, "# component_rank=%d\n# component_size=%d\n",
342 pak->comp_rank, pak->comp_size);
344 str,
345 "rank\tfield\tcomponent\tgrid\ttype"
346 "\tput_idx\tdatetime\taction"
347 "\ttstart\ttend\tduration\n");
348}
349
363 yac_pak_str_t * str, struct yac_pak const * pak,
364 yac_pak_trace_entry_t const * entry, int in_progress) {
365
366 char const * f = entry->info.field ? entry->info.field : "";
367 char const * c = entry->info.component ? entry->info.component : "";
368 char const * g = entry->info.grid ? entry->info.grid : "";
369 char const * t = yac_pak_event_type_to_str(entry->info.type);
370 char const * dt = entry->info.datetime ? entry->info.datetime : "";
371
373 str,
374 in_progress?
375 "%d\t%s\t%s\t%s\t%s\t%d\t%s\t%d\t%.9f\t\t\n":
376 "%d\t%s\t%s\t%s\t%s\t%d\t%s\t%d\t%.9f\t%.9f\t%.9f\n",
377 pak->rank, f, c, g, t, entry->info.put_idx, dt, entry->info.action,
378 entry->tstart, entry->tend, entry->tend - entry->tstart);
379}
380
389static void write_trace_row(
390 FILE * out, struct yac_pak const * pak,
391 yac_pak_trace_entry_t const * entry, int in_progress) {
392
393 yac_pak_str_t row = {0};
394 append_trace_row(&row, pak, entry, in_progress);
395 fwrite(row.buf, 1, row.len, out);
396 free(row.buf);
397}
398
406 struct yac_pak const * pak, double flush_dur_rank0) {
407
408 char * trace_metadata_path =
409 yac_file_path_join(pak->output_dir, "trace_metadata.json", NULL);
410 FILE * trace_metadata_file = fopen(trace_metadata_path, "w");
412 trace_metadata_file, "could not open '%s': %s",
413 trace_metadata_path, strerror(errno));
414
415 yac_pak_str_t meta = {0};
417 &meta,
418 "{\n"
419 " \"yac_pak_version\": \"v" YAC_PAK_VERSION_STRING "\",\n"
420 " \"yac_version\": \"v" YAC_VERSION "\",\n"
421 " \"mpi_size\": %d,\n"
422 " \"trace_stride\": %d,\n"
423 " \"init_epoch_sec\": %.9f,\n"
424 " \"wtime_ref_rank0\": %.9f",
425 pak->size, pak->trace_stride,
427 if (pak->trace_flush_time && (flush_dur_rank0 >= 0.0))
429 &meta, ",\n \"flush_duration_s_rank0\": %.6f", flush_dur_rank0);
430 str_appendf(&meta, "\n}\n");
431
432 fwrite(meta.buf, 1, meta.len, trace_metadata_file);
433 fclose(trace_metadata_file);
434 free(meta.buf);
435 free(trace_metadata_path);
436}
437
438static void yac_pak_setup_trace_dir(struct yac_pak * pak) {
439 /* one size for the directory path and for any candidate derived from it,
440 * so that the truncation checks below guard the copy back */
441 enum {TRACE_DIR_BUF_SIZE = 512};
442 char path[TRACE_DIR_BUF_SIZE];
443 path[0] = '\0';
444
445 if (pak->rank == 0) {
446 char const * dir_env = getenv(YAC_PAK_TRACE_DIR_ENV);
447 if (dir_env && strlen(dir_env) > 0) {
449 strlen(dir_env) < sizeof(path),
450 "YAC_PAK_TRACE_DIR path \"%s\" exceeds maximum length of %zu",
451 dir_env, sizeof(path) - 1);
452 strncpy(path, dir_env, sizeof(path) - 1);
453 path[sizeof(path) - 1] = '\0';
454 if (directory_exists(path)) {
455 fprintf(stderr,
456 "WARNING: YAC trace: " YAC_PAK_TRACE_DIR_ENV "='%s' already"
457 " exists; appending a numeric suffix to avoid overwriting"
458 " previous traces.\n",
459 path);
460 int found = 0;
461 for (int s = 1; s <= 99; ++s) {
462 char candidate[TRACE_DIR_BUF_SIZE];
463 int const n =
464 snprintf(candidate, sizeof(candidate), "%s_%d", path, s);
466 n >= 0 && (size_t)n < sizeof(candidate),
467 "candidate path truncated (n=%d)", n);
468 if (!directory_exists(candidate)) {
469 strncpy(path, candidate, sizeof(path) - 1);
470 path[sizeof(path) - 1] = '\0';
471 found = 1;
472 break;
473 }
474 }
476 found, "could not find a unique trace directory (base: '%s')",
477 dir_env);
479 } else {
481 }
482 } else {
483 /* Auto-generate: traces_YYYYMMDD_HHMMSS_N{size}_v{YAC PAK VER} */
484 time_t now = time(NULL);
485 struct tm const * tm_info = localtime(&now);
486 YAC_ASSERT(tm_info != NULL, "localtime() failed");
487 char base[256];
488 size_t nbase =
489 strftime(base, sizeof(base), "traces_%Y%m%d_%H%M%S", tm_info);
490 YAC_ASSERT(nbase > 0, "strftime() failed");
491 int npath = snprintf(path, sizeof(path), "%s_N%d_v%s",
492 base, pak->size, YAC_PAK_VERSION_STRING);
494 npath >= 0 && (size_t)npath < sizeof(path),
495 "auto-generated path exceeds maximum length of %zu",
496 sizeof(path) - 1);
498 }
499 }
500
502 MPI_Bcast(path, (int)sizeof(path), MPI_CHAR, 0, pak->comm),
503 pak->comm);
504 free(pak->output_dir);
505 pak->output_dir = yac_string_dup(path);
506}
507
508static size_t get_finished_event_idx(struct yac_pak * pak) {
509 if (pak->finished_count >= pak->finished_capacity) {
510 size_t const old_cap = pak->finished_capacity;
512 pak->finished_count + 1);
513 for (size_t i = old_cap; i < pak->finished_capacity; ++i) {
514 pak->finished_events[i].info.field = NULL;
515 pak->finished_events[i].info.component = NULL;
516 pak->finished_events[i].info.grid = NULL;
517 pak->finished_events[i].info.datetime = NULL;
518 pak->finished_events[i].tstart = pak->finished_events[i].tend = 0.0;
519 }
520 }
521 return pak->finished_count++;
522}
523
524static size_t get_open_event_idx(struct yac_pak * pak) {
525 size_t open_event_idx = SIZE_MAX;
526
527 for (size_t i = 0;
528 (i < pak->pending_capacity) && (open_event_idx == SIZE_MAX); ++i)
529 if (!pak->pending_events[i].in_use)
530 open_event_idx = i;
531
532 if (open_event_idx == SIZE_MAX) {
533 size_t const old_cap = pak->pending_capacity;
535 old_cap + 1);
536 for (size_t i = old_cap; i < pak->pending_capacity; ++i) {
537 pak->pending_events[i].info.field = NULL;
538 pak->pending_events[i].info.component = NULL;
540 pak->pending_events[i].info.grid = NULL;
541 pak->pending_events[i].info.datetime = NULL;
542 pak->pending_events[i].info.put_idx = -1;
543 pak->pending_events[i].info.action = -1;
545 pak->pending_events[i].tstart = 0.0;
546 pak->pending_events[i].in_use = 0;
547 }
548 open_event_idx = old_cap;
549 }
550
551 return open_event_idx;
552}
553
554/* ------------------------------------------------------------------ */
555/* Write mode "instant" */
556/* ------------------------------------------------------------------ */
557
565static void rewrite_open_file(struct yac_pak * pak) {
566
568 pak->open_file, "no .open file (only write mode \"instant\" has one)");
569
570 yac_pak_str_t content = {0};
571 append_trace_header(&content, pak, -1.0);
572 for (size_t i = 0; i < pak->pending_capacity; ++i) {
573 if (!pak->pending_events[i].in_use) continue;
574 yac_pak_trace_entry_t const entry =
575 {.info = pak->pending_events[i].info,
576 .tstart = pak->pending_events[i].tstart,
577 .tend = 0.0};
578 append_trace_row(&content, pak, &entry, 1);
579 }
580
581 rewind(pak->open_file);
582 fwrite(content.buf, 1, content.len, pak->open_file);
583 free(content.buf);
584 fflush(pak->open_file);
585
586 /* Stale rows here would look like a rank being stuck in an event */
587 long const len = ftell(pak->open_file);
589 len >= 0, "could not determine the size of '%s': %s",
590 pak->open_file_path, strerror(errno));
591 int const rc = ftruncate(fileno(pak->open_file), (off_t)len);
593 rc == 0, "could not truncate '%s': %s",
594 pak->open_file_path, strerror(errno));
595}
596
599 struct yac_pak * pak, yac_pak_trace_entry_t const * entry) {
600
602 pak->trace_file,
603 "no open trace file (only write mode \"instant\" has one)");
604 write_trace_row(pak->trace_file, pak, entry, 0);
605 fflush(pak->trace_file);
606}
607
617 struct yac_pak const * pak, char ** path, char const * suffix) {
618
619 char * new_path = build_output_path_per_rank(pak, suffix, pak->rank);
620
622 rename(*path, new_path) == 0, "could not rename '%s' to '%s': %s",
623 *path, new_path, strerror(errno));
624 free(*path);
625 *path = new_path;
626}
627
639 struct yac_pak * pak, char const * component) {
640
641 if (pak->component_name) return;
642 /* setup events (yac_init, yac_enddef, ...) carry no component name */
643 if (!component) return;
644 YAC_ASSERT(component[0] != '\0', "empty component name is not supported");
645
646 pak->component_name = xstrdup(component);
647
648 /* only write mode "instant" has files open here and only those still
649 * carry the placeholder name */
650 if (!pak->trace_file) return;
651
652 rename_open_file(pak, &pak->trace_file_path, ".csv");
653 rename_open_file(pak, &pak->open_file_path, ".open");
654}
655
656static void open_instant_files(struct yac_pak * pak) {
657
658 pak->trace_file_path = build_output_path_per_rank(pak, ".csv", pak->rank);
659 /* "w+": rewrite_instant_header reads the rows back */
660 pak->trace_file = fopen(pak->trace_file_path, "w+");
662 pak->trace_file, "could not open '%s': %s",
663 pak->trace_file_path, strerror(errno));
664 yac_pak_str_t header = {0};
665 append_trace_header(&header, pak, -1.0);
666 fwrite(header.buf, 1, header.len, pak->trace_file);
667 pak->trace_file_header_len = header.len;
668 free(header.buf);
669 fflush(pak->trace_file);
670
671 pak->open_file_path = build_output_path_per_rank(pak, ".open", pak->rank);
672 pak->open_file = fopen(pak->open_file_path, "w");
674 pak->open_file, "could not open '%s': %s",
675 pak->open_file_path, strerror(errno));
677}
678
679/* The header was written before the component was known, so it reports the
680 communicator stride and no component. The rows written since are kept. */
681static void rewrite_instant_header(struct yac_pak * pak) {
682
683 YAC_ASSERT(pak->trace_file, "no open trace file");
684
685 long const end = (fflush(pak->trace_file), ftell(pak->trace_file));
687 end >= 0, "could not determine the size of '%s': %s",
688 pak->trace_file_path, strerror(errno));
689
690 size_t const rows_len = (size_t)end - pak->trace_file_header_len;
691 char * rows = NULL;
692 if (rows_len > 0) {
693 rows = xmalloc(rows_len);
695 fseek(pak->trace_file, (long)pak->trace_file_header_len, SEEK_SET) == 0,
696 "could not seek in '%s': %s", pak->trace_file_path, strerror(errno));
698 fread(rows, 1, rows_len, pak->trace_file) == rows_len,
699 "could not read back '%s': %s", pak->trace_file_path, strerror(errno));
700 }
701
702 yac_pak_str_t header = {0};
703 append_trace_header(&header, pak, -1.0);
704 rewind(pak->trace_file);
705 fwrite(header.buf, 1, header.len, pak->trace_file);
706 if (rows_len > 0) fwrite(rows, 1, rows_len, pak->trace_file);
707 pak->trace_file_header_len = header.len;
708 free(header.buf);
709 free(rows);
710 fflush(pak->trace_file);
711
713 ftruncate(
714 fileno(pak->trace_file), (off_t)(pak->trace_file_header_len + rows_len))
715 == 0,
716 "could not truncate '%s': %s", pak->trace_file_path, strerror(errno));
717}
718
719static void discard_instant_files(struct yac_pak * pak) {
720
721 if (pak->trace_file) { fclose(pak->trace_file); pak->trace_file = NULL; }
722 if (pak->open_file) { fclose(pak->open_file); pak->open_file = NULL; }
723 if (pak->trace_file_path) remove(pak->trace_file_path);
724 if (pak->open_file_path) remove(pak->open_file_path);
725 free(pak->trace_file_path); pak->trace_file_path = NULL;
726 free(pak->open_file_path); pak->open_file_path = NULL;
727}
728
729static void release_open_event(struct yac_pak * pak, size_t handle) {
730 pak->pending_events[handle].in_use = 0;
731}
732
733/* ------------------------------------------------------------------ */
734/* Public API */
735/* ------------------------------------------------------------------ */
736
737struct yac_pak * yac_pak_new(MPI_Comm comm, int capacity) {
738 YAC_ASSERT(comm != MPI_COMM_NULL, "comm must not be MPI_COMM_NULL");
739
740 // return NULL if tracing is not enabled
741 if (!yac_getenv_bool(YAC_PAK_TRACE_ENV, 0, comm)) return NULL;
742
743 struct yac_pak * pak = xmalloc(1 * sizeof(*pak));
744
745 pak->comm = comm;
746 yac_mpi_call(MPI_Comm_rank(comm, &pak->rank), comm);
747 yac_mpi_call(MPI_Comm_size(comm, &pak->size), comm);
748
749 pak->num_timers = 0;
750 pak->cap_timers = 0;
751 pak->timers = NULL;
752
754 pak->output_dir = NULL;
755 pak->trace_stride = 1;
756 pak->trace_flush_time = 1;
757 pak->trace_is_writer = 0;
758 pak->trace_verbose = 0;
759
761 pak->trace_file = NULL;
762 pak->open_file = NULL;
763 pak->trace_file_path = NULL;
764 pak->open_file_path = NULL;
765
766 pak->pending_events = NULL;
767 pak->pending_capacity = 0;
768
769 pak->finished_events = NULL;
770 pak->finished_count = 0;
771 pak->finished_capacity = 0;
772
773 pak->trace_enabled = 1;
774 // default 1: YAC_PAK_TRACE=1 records the PUT/GET/AGET events
778
779 pak->component_name = NULL;
780 pak->comp_rank = -1;
781 pak->comp_size = -1;
782
783 pak->trace_flush_time =
785 pak->trace_verbose =
787
788 // 0 means "no coupling events" (setup-phase events are still
789 // recorded if YAC_PAK_TRACE_SETUP=1); 1 = PUT/GET/AGET, 2 = + nested regions.
791 (pak->trace_level >= 0) && (pak->trace_level <= YAC_PAK_TRACE_LEVEL_MAX),
792 YAC_PAK_TRACE_LEVEL_ENV " must be between 0 and %d, but "
793 YAC_PAK_TRACE_LEVEL_ENV "=%d was specified",
795
797 UNUSED(pak->output_mode);
798
800
801 pak->config_output_path =
803 yac_file_path_join(pak->output_dir, "coupling_config.yaml", NULL) : NULL;
804
805 pak->trace_stride =
808
809 pak->trace_write_mode = get_trace_write_mode(pak->comm);
810
811 /* write mode "instant" does not need an event buffer */
812 pak->finished_capacity =
814 ? 0
815 : (capacity > 0
816 ? (size_t)capacity
817 : (size_t)yac_getenv_int(
820 pak->finished_events =
821 (pak->finished_capacity > 0)
822 ? xcalloc(pak->finished_capacity, sizeof(*pak->finished_events))
823 : NULL;
824
825 {
826 struct timespec ts;
827 clock_gettime(CLOCK_REALTIME, &ts);
828 pak->trace_init_wtime = MPI_Wtime();
829 pak->trace_init_epoch = (double)ts.tv_sec + ts.tv_nsec * 1e-9;
830 }
831
832 /* Write mode "instant" writes while the run is going, so its files have to
833 * exist from the start. The component name is only known once the first
834 * event carries one, so they start out under the placeholder name and are
835 * renamed later (see set_component_name). */
837 pak->trace_is_writer)
839
841 (pak->rank == 0))
842 write_metadata_json_file(pak, -1.0);
843
844 return pak;
845}
846
847void yac_pak_delete(struct yac_pak * pak) {
848 if (!pak) return;
849
850 if (pak->trace_enabled) {
851 if (pak->pending_events) {
852 for (size_t i = 0; i < pak->pending_capacity; ++i)
853 if (pak->pending_events[i].in_use)
854 yac_pak_trace_stop(pak, (int)i);
855 }
856 if (yac_getenv_bool("YAC_PAK_TRACE_AUTOFLUSH", 1, pak->comm)) {
857 if (pak->finished_count > 0)
859 }
860
861 if (pak->trace_file) {
862 fclose(pak->trace_file);
863 pak->trace_file = NULL;
864 if (pak->trace_verbose && (pak->rank == 0))
865 fprintf(stderr,
866 "[%s] YAC PAK: per-rank traces written to %s/*.csv\n",
868 pak->output_dir ? pak->output_dir : ".");
869 }
870 if (pak->open_file) {
871 fclose(pak->open_file);
872 pak->open_file = NULL;
873 remove(pak->open_file_path);
874 }
875 }
876
877 for (size_t i = 0; i < pak->num_timers; ++i)
878 free(pak->timers[i].name);
879 free(pak->timers);
880
881 free(pak->pending_events);
882
883 if (pak->finished_events) {
884 for (size_t i = 0; i < pak->finished_count; ++i) {
885 free(pak->finished_events[i].info.field);
886 free(pak->finished_events[i].info.component);
887 free(pak->finished_events[i].info.grid);
888 free(pak->finished_events[i].info.datetime);
889 }
890 free(pak->finished_events);
891 }
892
893 free(pak->component_name);
894 free(pak->output_dir);
895 free(pak->config_output_path);
896 free(pak->trace_file_path);
897 free(pak->open_file_path);
898 free(pak);
899}
900
901/* ------------------------------------------------------------------ */
902/* Tracing */
903/* ------------------------------------------------------------------ */
904
905int yac_pak_trace_is_enabled(struct yac_pak const * pak) {
906 return pak && pak->trace_enabled;
907}
908
910 return pak && pak->trace_enabled && pak->setup_trace_enabled;
911}
912
914 struct yac_pak const * pak, yac_pak_trace_level_t level) {
915 // region events are coupling events: gated by the coupling-level
916 // threshold (`level` is the event category, not the nesting depth).
917 if (!pak || !pak->trace_enabled) return 0;
918 // in write mode "instant" a rank that does not write records nothing, so
919 // instrumenting it would be pointless (matches yac_pak_trace_start_ex)
921 !pak->trace_is_writer) return 0;
922 return (int)level <= pak->trace_level;
923}
924
925char const * yac_pak_get_config_output_path(struct yac_pak const * pak) {
926 return pak ? pak->config_output_path : NULL;
927}
928
930 struct yac_pak * pak, char const * comp_name,
931 int comp_rank, int comp_size) {
932
933 if (!pak) return;
935 !pak->component_name,
936 "component name was already set to '%s'", pak->component_name);
938 comp_name && (comp_name[0] != '\0'),
939 "invalid component name (has to be a non-empty string)");
941 (comp_size > 0) && (comp_rank >= 0) && (comp_rank < comp_size),
942 "invalid component rank %d for component size %d", comp_rank, comp_size);
943 pak->component_name = yac_string_dup(comp_name);
944 pak->comp_rank = comp_rank;
945 pak->comp_size = comp_size;
946
947 /* the stride basis changes here, so the writing ranks can change */
948 int const was_writer = pak->trace_is_writer;
949 int const is_writer = compute_is_writer(pak);
950 pak->trace_is_writer = is_writer;
951
952 /* only "instant" already has files, under the placeholder name */
954 if (was_writer) {
955 if (is_writer) {
956 // still a writer: rename the files and correct their header
957 rename_open_file(pak, &pak->trace_file_path, ".csv");
958 rename_open_file(pak, &pak->open_file_path, ".open");
961 } else {
962 // no longer a writer: discard what was written so far
964 }
965 } else if (is_writer) {
966 // newly a writer: start its files here
968 }
969 }
970}
971
973 char const * name, yac_pak_event_type_t type) {
974 // level is ignored for setup-type events (gated by YAC_PAK_TRACE_SETUP)
976 pak, name, NULL, NULL, type, -1, NULL, -1, YAC_PAK_TRACE_LEVEL_OFF);
977}
978
980 char const * field, char const * component,
981 char const * grid, yac_pak_event_type_t type,
982 double tstart, double tend) {
983 if (!pak) return -1;
984 if (!pak->trace_enabled || !pak->setup_trace_enabled) return -1;
985 set_component_name(pak, component);
986
988 if (pak->trace_is_writer) {
989 yac_pak_trace_entry_t const entry =
990 {.info = {.field = (char *)field,
991 .component = (char *)component,
992 .type = type,
993 .grid = (char *)grid,
994 .put_idx = -1,
995 .datetime = NULL,
996 .action = -1},
997 .tstart = tstart,
998 .tend = tend};
999 write_trace_row_instant(pak, &entry);
1000 }
1001 } else {
1002 size_t const idx = get_finished_event_idx(pak);
1003 pak->finished_events[idx].info.field = yac_string_dup(field);
1004 pak->finished_events[idx].info.component = yac_string_dup(component);
1005 pak->finished_events[idx].info.type = type;
1006 pak->finished_events[idx].info.grid = yac_string_dup(grid);
1007 pak->finished_events[idx].info.put_idx = -1;
1008 pak->finished_events[idx].info.datetime = NULL;
1009 pak->finished_events[idx].info.action = -1;
1010 pak->finished_events[idx].tstart = tstart;
1011 pak->finished_events[idx].tend = tend;
1012 }
1013
1014 return 0;
1015}
1016
1018 char const * field,
1019 char const * component,
1020 char const * grid,
1022 int put_idx,
1023 char const * datetime,
1024 int action,
1025 yac_pak_trace_level_t level) {
1026 if (!pak) return -1;
1028 if (!pak->trace_enabled || !pak->setup_trace_enabled) return -1;
1029 } else if (!yac_pak_region_trace_is_enabled(pak, level)) {
1030 return -1;
1031 }
1032 set_component_name(pak, component);
1033
1035 !pak->trace_is_writer) return -1;
1036
1037 size_t const event_idx = get_open_event_idx(pak);
1038 pak->pending_events[event_idx].info.field = yac_string_dup(field);
1039 pak->pending_events[event_idx].info.component = yac_string_dup(component);
1040 pak->pending_events[event_idx].info.type = type;
1041 pak->pending_events[event_idx].info.grid = yac_string_dup(grid);
1042 pak->pending_events[event_idx].info.put_idx = put_idx;
1043 pak->pending_events[event_idx].info.datetime = yac_string_dup(datetime);
1044 pak->pending_events[event_idx].info.action = action;
1045 pak->pending_events[event_idx].level = level;
1046 pak->pending_events[event_idx].tstart = MPI_Wtime();
1047 pak->pending_events[event_idx].in_use = 1;
1048
1050 rewrite_open_file(pak);
1051
1052 return (int)event_idx;
1053}
1054
1055int yac_pak_trace_stop(struct yac_pak * pak, int handle) {
1056 if (!pak) return -1;
1057 if (handle < 0) return -1;
1058 if ((size_t)handle >= pak->pending_capacity) return -1;
1059 if (!pak->pending_events[handle].in_use) return -1;
1060 double const tend = MPI_Wtime();
1061
1063 /* DEF_COMP is open across yac_pak_set_component, which may close it */
1064 if (pak->trace_file) {
1065 yac_pak_trace_entry_t const entry =
1066 {.info = pak->pending_events[handle].info,
1067 .tstart = pak->pending_events[handle].tstart,
1068 .tend = tend};
1069 write_trace_row_instant(pak, &entry);
1070 }
1071 free(pak->pending_events[handle].info.field);
1072 free(pak->pending_events[handle].info.component);
1073 free(pak->pending_events[handle].info.grid);
1074 free(pak->pending_events[handle].info.datetime);
1075 } else {
1076 size_t const idx = get_finished_event_idx(pak);
1077 pak->finished_events[idx].info = pak->pending_events[handle].info;
1078 pak->finished_events[idx].tstart = pak->pending_events[handle].tstart;
1079 pak->finished_events[idx].tend = tend;
1080 }
1081
1082 pak->pending_events[handle].info = (yac_pak_event_info_t){0};
1083 release_open_event(pak, (size_t)handle);
1084
1086 pak->open_file)
1087 rewrite_open_file(pak);
1088
1089 return 0;
1090}
1091
1092int yac_pak_flush_trace(struct yac_pak * pak) {
1093 if (!pak) return -1;
1094 if (!pak->finished_events && !pak->trace_enabled) return -1;
1095 if (pak->finished_count == 0) return 0;
1096
1097 {
1098 int const should_write = pak->trace_is_writer;
1099 double rank0_flush_dur = -1.0;
1100
1101 if (should_write) {
1102 double const t_flush_start = MPI_Wtime();
1103 yac_pak_str_t rows = {0};
1104 for (size_t i = 0; i < pak->finished_count; ++i)
1105 append_trace_row(&rows, pak, &pak->finished_events[i], 0);
1106 double const flush_dur = MPI_Wtime() - t_flush_start;
1107 if (pak->rank == 0) rank0_flush_dur = flush_dur;
1108
1109 char * filepath =
1110 build_output_path_per_rank(pak, ".csv", pak->rank);
1111 FILE * file_out = fopen(filepath, "w");
1113 file_out, "could not open '%s': %s", filepath, strerror(errno));
1114 if (pak->trace_verbose && (pak->rank == 0))
1115 fprintf(stderr,
1116 "[%s] YAC PAK: Writing per-rank traces to %s/*.csv\n",
1117 get_component_name(pak),
1118 pak->output_dir ? pak->output_dir : ".");
1119
1120 yac_pak_str_t header = {0};
1121 append_trace_header(&header, pak, flush_dur);
1122 fwrite(header.buf, 1, header.len, file_out);
1123 if (rows.len > 0) fwrite(rows.buf, 1, rows.len, file_out);
1124 fclose(file_out);
1125 free(header.buf);
1126 free(rows.buf);
1127 free(filepath);
1128 }
1129
1130 /* metadata JSON by rank 0 */
1131 if (pak->rank == 0 && pak->output_dir)
1132 write_metadata_json_file(pak, rank0_flush_dur);
1133 }
1134
1135 for (size_t i = 0; i < pak->finished_count; ++i) {
1136 free(pak->finished_events[i].info.field);
1137 free(pak->finished_events[i].info.component);
1138 free(pak->finished_events[i].info.grid);
1139 free(pak->finished_events[i].info.datetime);
1140 }
1141 pak->finished_count = 0;
1142 return 0;
1143}
1144
1145/* ------------------------------------------------------------------ */
1146/* Performance Timers */
1147/* Separate feature from event tracing, not used yet. */
1148/* TODO: Extend and add tests for timer functionality */
1149/* ------------------------------------------------------------------ */
1150
1151int yac_pak_register(struct yac_pak * pak, char const * name) {
1152 if (!pak) return -1;
1153 ENSURE_ARRAY_SIZE(pak->timers, pak->cap_timers, pak->num_timers + 1);
1155 pak->timers[pak->num_timers].total = 0.0;
1156 pak->timers[pak->num_timers].count = 0;
1157 pak->timers[pak->num_timers].start = 0.0;
1158 pak->timers[pak->num_timers].running = 0;
1159 return pak->num_timers++;
1160}
1161
1162int yac_pak_start(struct yac_pak * pak, int idx) {
1163 if (!pak) return -1;
1164 if ((size_t)idx >= pak->num_timers) return -1;
1165 pak->timers[idx].start = MPI_Wtime();
1166 pak->timers[idx].running = 1;
1167 return 0;
1168}
1169
1170int yac_pak_stop(struct yac_pak * pak, int idx) {
1171 if (!pak) return -1;
1172 if ((size_t)idx >= pak->num_timers) return -1;
1173 if (!pak->timers[idx].running) return -1;
1174 double const dt = MPI_Wtime() - pak->timers[idx].start;
1175 pak->timers[idx].total += dt;
1176 pak->timers[idx].count += 1;
1177 pak->timers[idx].running = 0;
1178 return 0;
1179}
1180
1181int yac_pak_report(struct yac_pak * pak, FILE * out) {
1182 if (!pak) return -1;
1183 if (!out) out = stdout;
1184 if (!pak->timers) return -1;
1185 int comm_size = 1;
1186 typedef struct { double val; int rank; } double_int_t;
1187 yac_mpi_call(MPI_Comm_size(pak->comm, &comm_size), pak->comm);
1188 for (size_t i = 0; i < pak->num_timers; ++i) {
1189 double const local_total = pak->timers[i].total;
1190 int const local_count = pak->timers[i].count;
1191 double global_sum_total = 0.0;
1192 int global_sum_count = 0;
1193 double_int_t const local_loc = {local_total, pak->rank};
1194 double_int_t global_min_loc, global_max_loc;
1195
1196 yac_mpi_call(MPI_Allreduce(&local_total, &global_sum_total,
1197 1, MPI_DOUBLE, MPI_SUM, pak->comm), pak->comm);
1198 yac_mpi_call(MPI_Allreduce(&local_loc, &global_min_loc,
1199 1, MPI_DOUBLE_INT, MPI_MINLOC, pak->comm), pak->comm);
1200 yac_mpi_call(MPI_Allreduce(&local_loc, &global_max_loc,
1201 1, MPI_DOUBLE_INT, MPI_MAXLOC, pak->comm), pak->comm);
1202 yac_mpi_call(MPI_Allreduce(&local_count, &global_sum_count,
1203 1, MPI_INT, MPI_SUM, pak->comm), pak->comm);
1204 double const avg = global_sum_total / (double)comm_size;
1205 if (pak->rank == 0) {
1206 fprintf(out,
1207 "Timer '%s': total_sum=%.6f,"
1208 " min=%.6f(rank %d), max=%.6f(rank %d),"
1209 " avg(per-rank)=%.6f, total_counts=%d\n",
1210 pak->timers[i].name, global_sum_total,
1211 global_min_loc.val, global_min_loc.rank,
1212 global_max_loc.val, global_max_loc.rank,
1213 avg, global_sum_count);
1214 }
1215 }
1216 return 0;
1217}
#define YAC_ASSERT(exp, msg)
#define UNUSED(x)
Definition core.h:72
#define __attribute__(x)
Definition core.h:69
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
int yac_name_type_pair_get_type(struct yac_name_type_pair const *pairs, size_t count, char const *name)
Definition utils_core.c:23
#define DEF_NAME_TYPE_PAIR(NAME, TYPE)
char const * yac_name_type_pair_get_name(struct yac_name_type_pair const *pairs, size_t count, int type)
Definition utils_core.c:14
#define DEF_NAME_TYPE_PAIRS(NAME,...)
#define YAC_PAK_VERSION_STRING
Definition yac_pak.h:39
int yac_pak_region_trace_is_enabled(struct yac_pak const *pak, yac_pak_trace_level_t level)
Check whether region events at a given trace level will be recorded.
Definition yac_pak.c:913
int yac_pak_trace_start_setup(struct yac_pak *pak, char const *name, yac_pak_event_type_t type)
Setup-phase event tracing.
Definition yac_pak.c:972
int yac_pak_register(struct yac_pak *pak, char const *name)
Register a named timer.
Definition yac_pak.c:1151
int yac_pak_trace_is_enabled(struct yac_pak const *pak)
Event tracing support.
Definition yac_pak.c:905
int yac_pak_setup_trace_is_enabled(struct yac_pak const *pak)
Check whether setup-phase tracing is active.
Definition yac_pak.c:909
int yac_pak_start(struct yac_pak *pak, int idx)
Start a registered timer.
Definition yac_pak.c:1162
void yac_pak_delete(struct yac_pak *pak)
Destroy a YAC PAK object.
Definition yac_pak.c:847
struct yac_pak * yac_pak_new(MPI_Comm comm, int capacity)
Construct a new YAC PAK object.
Definition yac_pak.c:737
yac_pak_event_type_t
Event type for YAC PAK trace entries. Defines the type of events that can be recorded in YAC PAK trac...
Definition yac_pak.h:48
yac_pak_trace_level_t
YAC PAK coupling trace level.
Definition yac_pak.h:71
int yac_pak_trace_record(struct yac_pak *pak, char const *field, char const *component, char const *grid, yac_pak_event_type_t type, double tstart, double tend)
Record a complete trace entry with explicit timestamps.
Definition yac_pak.c:979
int yac_pak_report(struct yac_pak *pak, FILE *out)
Generate collective timer report.
Definition yac_pak.c:1181
char const * yac_pak_get_config_output_path(struct yac_pak const *pak)
Return the coupling configuration output file path if enabled.
Definition yac_pak.c:925
int yac_pak_trace_stop(struct yac_pak *pak, int handle)
Stop a trace event.
Definition yac_pak.c:1055
int yac_pak_flush_trace(struct yac_pak *pak)
Flush trace data to disk.
Definition yac_pak.c:1092
void yac_pak_set_component(struct yac_pak *pak, char const *comp_name, int comp_rank, int comp_size)
Set the component this process belongs to.
Definition yac_pak.c:929
int yac_pak_stop(struct yac_pak *pak, int idx)
Stop a registered timer.
Definition yac_pak.c:1170
int yac_pak_trace_start_ex(struct yac_pak *pak, char const *field, char const *component, char const *grid, yac_pak_event_type_t type, int put_idx, char const *datetime, int action, yac_pak_trace_level_t level)
Start a trace event with full metadata.
Definition yac_pak.c:1017
@ YAC_PAK_EVENT_TYPE_GET
Definition yac_pak.h:54
@ YAC_PAK_EVENT_TYPE_WAIT
Definition yac_pak.h:59
@ YAC_PAK_EVENT_TYPE_PUT
Definition yac_pak.h:56
@ YAC_PAK_EVENT_TYPE_FINALIZE
Definition yac_pak.h:53
@ YAC_PAK_EVENT_TYPE_INIT
Definition yac_pak.h:49
@ YAC_PAK_EVENT_TYPE_SYNC_DEF
Definition yac_pak.h:51
@ YAC_PAK_EVENT_TYPE_AGET
Definition yac_pak.h:55
@ YAC_PAK_EVENT_TYPE_DEF_COMP
Definition yac_pak.h:50
@ YAC_PAK_EVENT_TYPE_UPDATE
Definition yac_pak.h:58
@ YAC_PAK_EVENT_TYPE_ENDDEF
Definition yac_pak.h:52
@ YAC_PAK_EVENT_TYPE_REGION
Definition yac_pak.h:57
@ YAC_PAK_TRACE_LEVEL_MAX
highest level
Definition yac_pak.h:75
@ YAC_PAK_TRACE_LEVEL_OFF
no coupling events
Definition yac_pak.h:72
enum callback_type type
char * yac_file_path_join(char const *path_prefix, char const *path_suffix, char const *extension)
Join two path components with a '/' and optional extension.
Definition io_utils.c:426
#define xstrdup(s)
Definition ppm_xfuncs.h:84
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:64
#define xmalloc(size)
Definition ppm_xfuncs.h:66
yac_pak_event_type_t type
Definition yac_pak.c:100
yac_pak_trace_level_t level
Definition yac_pak.c:110
yac_pak_event_info_t info
Definition yac_pak.c:109
size_t capacity
Definition yac_pak.c:122
char * buf
NULL until the first append.
Definition yac_pak.c:120
size_t len
length excluding the terminating null byte
Definition yac_pak.c:121
char * name
Definition yac_pak.c:90
double start
Definition yac_pak.c:93
double total
Definition yac_pak.c:91
Definition yac_pak.c:126
yac_pak_event_info_t info
Definition yac_pak.c:127
double tend
Definition yac_pak.c:129
double tstart
Definition yac_pak.c:128
size_t finished_capacity
Definition yac_pak.c:172
char * component_name
Definition yac_pak.c:178
char * output_dir
Definition yac_pak.c:147
yac_pak_trace_write_mode_t trace_write_mode
Definition yac_pak.c:155
int rank
Definition yac_pak.c:137
size_t trace_file_header_len
Definition yac_pak.c:165
int trace_is_writer
Definition yac_pak.c:151
int trace_level
Definition yac_pak.c:175
yac_pak_timer_t * timers
Definition yac_pak.c:141
int setup_trace_enabled
Definition yac_pak.c:176
yac_pak_output_mode_t output_mode
Definition yac_pak.c:146
FILE * trace_file
Definition yac_pak.c:160
double trace_init_wtime
Definition yac_pak.c:183
int trace_enabled
Definition yac_pak.c:174
size_t pending_capacity
Definition yac_pak.c:168
double trace_init_epoch
Definition yac_pak.c:184
int comp_size
Definition yac_pak.c:181
FILE * open_file
Definition yac_pak.c:161
MPI_Comm comm
Definition yac_pak.c:136
int comp_rank
Definition yac_pak.c:180
char * open_file_path
Definition yac_pak.c:163
size_t num_timers
Definition yac_pak.c:142
size_t cap_timers
Definition yac_pak.c:143
yac_pak_open_event_t * pending_events
Definition yac_pak.c:167
int trace_flush_time
Definition yac_pak.c:150
char * trace_file_path
Definition yac_pak.c:162
yac_pak_trace_entry_t * finished_events
Definition yac_pak.c:170
int trace_stride
Definition yac_pak.c:149
int size
Definition yac_pak.c:138
char * config_output_path
Definition yac_pak.c:148
size_t finished_count
Definition yac_pak.c:171
int trace_verbose
Definition yac_pak.c:153
char const * name
Definition toy_scrip.c:114
int yac_getenv_int(const char *name, int default_value, int threshold, MPI_Comm comm)
Definition utils_core.c:89
int yac_getenv_bool(const char *name, int default_value, MPI_Comm comm)
char * yac_getenv_str(const char *name, const char *default_value, MPI_Comm comm)
Definition utils_core.c:125
char * yac_string_dup(char const *string)
Definition utils_core.c:33
#define YAC_ASSERT_F(exp, format,...)
Definition yac_assert.h:39
#define yac_mpi_call(call, comm)
static void rename_open_file(struct yac_pak const *pak, char **path, char const *suffix)
Definition yac_pak.c:616
static int yac_pak_event_type_is_setup(yac_pak_event_type_t type)
Definition yac_pak.c:216
static void open_instant_files(struct yac_pak *pak)
Definition yac_pak.c:656
static int compute_is_writer(struct yac_pak const *pak)
Definition yac_pak.c:260
static void write_trace_row_instant(struct yac_pak *pak, yac_pak_trace_entry_t const *entry)
Definition yac_pak.c:598
static void discard_instant_files(struct yac_pak *pak)
Definition yac_pak.c:719
static void rewrite_instant_header(struct yac_pak *pak)
Definition yac_pak.c:681
static size_t get_open_event_idx(struct yac_pak *pak)
Definition yac_pak.c:524
#define YAC_PAK_TRACE_SETUP_ENV
Definition yac_pak.c:65
static size_t get_finished_event_idx(struct yac_pak *pak)
Definition yac_pak.c:508
static char const * get_component_name(struct yac_pak const *pak)
Definition yac_pak.c:255
#define YAC_PAK_TRACE_WRITE_MODE_ENV
Definition yac_pak.c:71
static void append_trace_row(yac_pak_str_t *str, struct yac_pak const *pak, yac_pak_trace_entry_t const *entry, int in_progress)
Definition yac_pak.c:362
static void write_trace_row(FILE *out, struct yac_pak const *pak, yac_pak_trace_entry_t const *entry, int in_progress)
Definition yac_pak.c:389
static char * build_output_path_per_rank(struct yac_pak const *pak, char const *suffix, int rank)
Definition yac_pak.c:272
static void pak_make_trace_dir(char const *path, int verbose)
Definition yac_pak.c:265
yac_pak_trace_write_mode_t
Definition yac_pak.c:84
@ YAC_PAK_TRACE_WRITE_AT_FINALIZE
Definition yac_pak.c:85
@ YAC_PAK_TRACE_WRITE_INSTANT
Definition yac_pak.c:86
static void rewrite_open_file(struct yac_pak *pak)
Definition yac_pak.c:565
static void write_metadata_json_file(struct yac_pak const *pak, double flush_dur_rank0)
Definition yac_pak.c:405
#define YAC_PAK_TRACE_CAPACITY_ENV
Definition yac_pak.c:66
static void str_appendf(yac_pak_str_t *str, char const *fmt,...) __attribute__((format(printf
Definition yac_pak.c:303
yac_pak_output_mode_t
Definition yac_pak.c:79
@ YAC_PAK_OUTPUT_FILE_PER_RANK
Definition yac_pak.c:80
#define YAC_PAK_TRACE_DIR_ENV
Definition yac_pak.c:67
static void append_trace_header(yac_pak_str_t *str, struct yac_pak const *pak, double flush_dur)
Definition yac_pak.c:327
#define YAC_PAK_TRACE_FLUSH_TIME_ENV
Definition yac_pak.c:69
#define YAC_PAK_TRACE_ENV
Definition yac_pak.c:63
static void release_open_event(struct yac_pak *pak, size_t handle)
Definition yac_pak.c:729
#define YAC_PAK_TRACE_VERBOSE_ENV
Definition yac_pak.c:72
static int directory_exists(char const *path)
Definition yac_pak.c:250
@ YAC_PAK_TRACE_CAPACITY_MIN
Definition yac_pak.c:76
@ YAC_PAK_TRACE_CAPACITY_DEFAULT
Definition yac_pak.c:75
static void yac_pak_setup_trace_dir(struct yac_pak *pak)
Definition yac_pak.c:438
#define YAC_PAK_TRACE_CONFIG_ENV
Definition yac_pak.c:70
static void set_component_name(struct yac_pak *pak, char const *component)
Definition yac_pak.c:638
#define YAC_PAK_TRACE_LEVEL_ENV
Definition yac_pak.c:64
#define YAC_PAK_TRACE_STRIDE_ENV
Definition yac_pak.c:68