25#include "yac_config.h"
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"
192 yac_pak_event_type_pairs,
208 yac_pak_event_type_pairs,
209 (
size_t)yac_pak_event_type_pairs_size,
225 yac_pak_trace_write_mode_pairs,
236 yac_pak_trace_write_mode_pairs,
237 (
size_t)yac_pak_trace_write_mode_pairs_size, str_value);
241 "\"%s\" is not a valid value for environment variable %s "
242 "(expected \"at_finalize\" or \"instant\")",
252 return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
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);
273 struct yac_pak const * pak,
char const * suffix,
int rank) {
277 strlen(dir) + 1 + strlen(comp) + 16 + strlen(suffix) + 1;
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);
305 va_list args, args_size;
307 va_copy(args_size, args);
309 int const n = vsnprintf(NULL, 0, fmt, args_size);
311 YAC_ASSERT(n >= 0,
"vsnprintf failed while building a trace string");
314 vsnprintf(str->buf + str->len, (
size_t)n + 1, fmt, args);
315 str->len += (size_t)n;
334 "# epoch_ref=%.9f\n",
337 str_appendf(str,
"# flush_duration_s=%.6f\n", flush_dur);
341 str,
"# component_rank=%d\n# component_size=%d\n",
345 "rank\tfield\tcomponent\tgrid\ttype"
346 "\tput_idx\tdatetime\taction"
347 "\ttstart\ttend\tduration\n");
369 char const * t = yac_pak_event_type_to_str(entry->
info.
type);
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",
390 FILE * out,
struct yac_pak const * pak,
395 fwrite(row.
buf, 1, row.
len, out);
406 struct yac_pak const * pak,
double flush_dur_rank0) {
408 char * trace_metadata_path =
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));
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",
429 &meta,
",\n \"flush_duration_s_rank0\": %.6f", flush_dur_rank0);
432 fwrite(meta.
buf, 1, meta.
len, trace_metadata_file);
433 fclose(trace_metadata_file);
435 free(trace_metadata_path);
441 enum {TRACE_DIR_BUF_SIZE = 512};
442 char path[TRACE_DIR_BUF_SIZE];
445 if (pak->
rank == 0) {
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';
457 " exists; appending a numeric suffix to avoid overwriting"
458 " previous traces.\n",
461 for (
int s = 1; s <= 99; ++s) {
462 char candidate[TRACE_DIR_BUF_SIZE];
464 snprintf(candidate,
sizeof(candidate),
"%s_%d", path, s);
466 n >= 0 && (
size_t)n <
sizeof(candidate),
467 "candidate path truncated (n=%d)", n);
469 strncpy(path, candidate,
sizeof(path) - 1);
470 path[
sizeof(path) - 1] =
'\0';
476 found,
"could not find a unique trace directory (base: '%s')",
484 time_t now = time(NULL);
485 struct tm const * tm_info = localtime(&now);
486 YAC_ASSERT(tm_info != NULL,
"localtime() failed");
489 strftime(base,
sizeof(base),
"traces_%Y%m%d_%H%M%S", tm_info);
491 int npath = snprintf(path,
sizeof(path),
"%s_N%d_v%s",
494 npath >= 0 && (
size_t)npath <
sizeof(path),
495 "auto-generated path exceeds maximum length of %zu",
502 MPI_Bcast(path, (
int)
sizeof(path), MPI_CHAR, 0, pak->
comm),
525 size_t open_event_idx = SIZE_MAX;
532 if (open_event_idx == SIZE_MAX) {
548 open_event_idx = old_cap;
551 return open_event_idx;
568 pak->
open_file,
"no .open file (only write mode \"instant\" has one)");
589 len >= 0,
"could not determine the size of '%s': %s",
591 int const rc = ftruncate(fileno(pak->
open_file), (off_t)len);
593 rc == 0,
"could not truncate '%s': %s",
603 "no open trace file (only write mode \"instant\" has one)");
617 struct yac_pak const * pak,
char ** path,
char const * suffix) {
622 rename(*path, new_path) == 0,
"could not rename '%s' to '%s': %s",
623 *path, new_path, strerror(errno));
639 struct yac_pak * pak,
char const * component) {
643 if (!component)
return;
644 YAC_ASSERT(component[0] !=
'\0',
"empty component name is not supported");
674 pak->
open_file,
"could not open '%s': %s",
687 end >= 0,
"could not determine the size of '%s': %s",
698 fread(rows, 1, rows_len, pak->
trace_file) == rows_len,
699 "could not read back '%s': %s", pak->
trace_file_path, strerror(errno));
706 if (rows_len > 0) fwrite(rows, 1, rows_len, pak->
trace_file);
738 YAC_ASSERT(
comm != MPI_COMM_NULL,
"comm must not be MPI_COMM_NULL");
827 clock_gettime(CLOCK_REALTIME, &ts);
866 "[%s] YAC PAK: per-rank traces written to %s/*.csv\n",
930 struct yac_pak * pak,
char const * comp_name,
931 int comp_rank,
int comp_size) {
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);
965 }
else if (is_writer) {
980 char const * field,
char const * component,
982 double tstart,
double tend) {
991 .component = (
char *)component,
993 .grid = (
char *)grid,
1019 char const * component,
1023 char const * datetime,
1026 if (!pak)
return -1;
1052 return (
int)event_idx;
1056 if (!pak)
return -1;
1057 if (handle < 0)
return -1;
1060 double const tend = MPI_Wtime();
1093 if (!pak)
return -1;
1099 double rank0_flush_dur = -1.0;
1102 double const t_flush_start = MPI_Wtime();
1106 double const flush_dur = MPI_Wtime() - t_flush_start;
1107 if (pak->
rank == 0) rank0_flush_dur = flush_dur;
1111 FILE * file_out = fopen(filepath,
"w");
1113 file_out,
"could not open '%s': %s", filepath, strerror(errno));
1116 "[%s] YAC PAK: Writing per-rank traces to %s/*.csv\n",
1122 fwrite(header.buf, 1, header.len, file_out);
1123 if (rows.
len > 0) fwrite(rows.
buf, 1, rows.
len, file_out);
1152 if (!pak)
return -1;
1163 if (!pak)
return -1;
1164 if ((
size_t)idx >= pak->
num_timers)
return -1;
1171 if (!pak)
return -1;
1172 if ((
size_t)idx >= pak->
num_timers)
return -1;
1174 double const dt = MPI_Wtime() - pak->
timers[idx].
start;
1182 if (!pak)
return -1;
1183 if (!out) out = stdout;
1184 if (!pak->
timers)
return -1;
1186 typedef struct {
double val;
int rank; } double_int_t;
1188 for (
size_t i = 0; i < pak->
num_timers; ++i) {
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;
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) {
1207 "Timer '%s': total_sum=%.6f,"
1208 " min=%.6f(rank %d), max=%.6f(rank %d),"
1209 " avg(per-rank)=%.6f, total_counts=%d\n",
1211 global_min_loc.val, global_min_loc.rank,
1212 global_max_loc.val, global_max_loc.rank,
1213 avg, global_sum_count);
#define YAC_ASSERT(exp, msg)
#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)
#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)
#define DEF_NAME_TYPE_PAIRS(NAME,...)
#define YAC_PAK_VERSION_STRING
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.
int yac_pak_trace_start_setup(struct yac_pak *pak, char const *name, yac_pak_event_type_t type)
Setup-phase event tracing.
int yac_pak_register(struct yac_pak *pak, char const *name)
Register a named timer.
int yac_pak_trace_is_enabled(struct yac_pak const *pak)
Event tracing support.
int yac_pak_setup_trace_is_enabled(struct yac_pak const *pak)
Check whether setup-phase tracing is active.
int yac_pak_start(struct yac_pak *pak, int idx)
Start a registered timer.
void yac_pak_delete(struct yac_pak *pak)
Destroy a YAC PAK object.
struct yac_pak * yac_pak_new(MPI_Comm comm, int capacity)
Construct a new YAC PAK object.
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...
yac_pak_trace_level_t
YAC PAK coupling trace level.
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.
int yac_pak_report(struct yac_pak *pak, FILE *out)
Generate collective timer report.
char const * yac_pak_get_config_output_path(struct yac_pak const *pak)
Return the coupling configuration output file path if enabled.
int yac_pak_trace_stop(struct yac_pak *pak, int handle)
Stop a trace event.
int yac_pak_flush_trace(struct yac_pak *pak)
Flush trace data to disk.
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.
int yac_pak_stop(struct yac_pak *pak, int idx)
Stop a registered timer.
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.
@ YAC_PAK_EVENT_TYPE_WAIT
@ YAC_PAK_EVENT_TYPE_FINALIZE
@ YAC_PAK_EVENT_TYPE_INIT
@ YAC_PAK_EVENT_TYPE_SYNC_DEF
@ YAC_PAK_EVENT_TYPE_AGET
@ YAC_PAK_EVENT_TYPE_DEF_COMP
@ YAC_PAK_EVENT_TYPE_UPDATE
@ YAC_PAK_EVENT_TYPE_ENDDEF
@ YAC_PAK_EVENT_TYPE_REGION
@ YAC_PAK_TRACE_LEVEL_MAX
highest level
@ YAC_PAK_TRACE_LEVEL_OFF
no coupling events
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.
#define xcalloc(nmemb, size)
yac_pak_event_type_t type
yac_pak_trace_level_t level
yac_pak_event_info_t info
char * buf
NULL until the first append.
size_t len
length excluding the terminating null byte
yac_pak_event_info_t info
yac_pak_trace_write_mode_t trace_write_mode
size_t trace_file_header_len
yac_pak_output_mode_t output_mode
yac_pak_open_event_t * pending_events
yac_pak_trace_entry_t * finished_events
char * config_output_path
int yac_getenv_int(const char *name, int default_value, int threshold, MPI_Comm comm)
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)
char * yac_string_dup(char const *string)
#define YAC_ASSERT_F(exp, format,...)
#define yac_mpi_call(call, comm)
static void rename_open_file(struct yac_pak const *pak, char **path, char const *suffix)
static int yac_pak_event_type_is_setup(yac_pak_event_type_t type)
static void open_instant_files(struct yac_pak *pak)
static int compute_is_writer(struct yac_pak const *pak)
static void write_trace_row_instant(struct yac_pak *pak, yac_pak_trace_entry_t const *entry)
static void discard_instant_files(struct yac_pak *pak)
static void rewrite_instant_header(struct yac_pak *pak)
static size_t get_open_event_idx(struct yac_pak *pak)
#define YAC_PAK_TRACE_SETUP_ENV
static size_t get_finished_event_idx(struct yac_pak *pak)
static char const * get_component_name(struct yac_pak const *pak)
#define YAC_PAK_TRACE_WRITE_MODE_ENV
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)
static void write_trace_row(FILE *out, struct yac_pak const *pak, yac_pak_trace_entry_t const *entry, int in_progress)
static char * build_output_path_per_rank(struct yac_pak const *pak, char const *suffix, int rank)
static void pak_make_trace_dir(char const *path, int verbose)
yac_pak_trace_write_mode_t
@ YAC_PAK_TRACE_WRITE_AT_FINALIZE
@ YAC_PAK_TRACE_WRITE_INSTANT
static void rewrite_open_file(struct yac_pak *pak)
static void write_metadata_json_file(struct yac_pak const *pak, double flush_dur_rank0)
#define YAC_PAK_TRACE_CAPACITY_ENV
static void str_appendf(yac_pak_str_t *str, char const *fmt,...) __attribute__((format(printf
@ YAC_PAK_OUTPUT_FILE_PER_RANK
#define YAC_PAK_TRACE_DIR_ENV
static void append_trace_header(yac_pak_str_t *str, struct yac_pak const *pak, double flush_dur)
#define YAC_PAK_TRACE_FLUSH_TIME_ENV
#define YAC_PAK_TRACE_ENV
static void release_open_event(struct yac_pak *pak, size_t handle)
#define YAC_PAK_TRACE_VERBOSE_ENV
static int directory_exists(char const *path)
@ YAC_PAK_TRACE_CAPACITY_MIN
@ YAC_PAK_TRACE_CAPACITY_DEFAULT
static void yac_pak_setup_trace_dir(struct yac_pak *pak)
#define YAC_PAK_TRACE_CONFIG_ENV
static void set_component_name(struct yac_pak *pak, char const *component)
#define YAC_PAK_TRACE_LEVEL_ENV
#define YAC_PAK_TRACE_STRIDE_ENV