diff --git a/src/emu/old_emu.c b/src/emu/old_emu.c deleted file mode 100644 index 84f73f4..0000000 --- a/src/emu/old_emu.c +++ /dev/null @@ -1,1250 +0,0 @@ -/* Copyright (c) 2021-2022 Barcelona Supercomputing Center (BSC) - * SPDX-License-Identifier: GPL-3.0-or-later */ - -#define _POSIX_C_SOURCE 200112L - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "chan.h" -#include "emu.h" -#include "ovni.h" -#include "pcf.h" -#include "prv.h" -#include "trace.h" -#include "utlist.h" - -/* Obtains the corrected clock of the given event */ -static int64_t -evclock(struct ovni_stream *stream, struct ovni_ev *ev) -{ - return (int64_t) ovni_ev_get_clock(ev) + stream->clock_offset; -} - -static void -print_ev(struct ovni_stream *stream, struct ovni_ev *ev) -{ - int64_t clock = evclock(stream, ev); - - int64_t delta = clock - stream->lastclock; - UNUSED(delta); - - dbg(">>> %s.%d.%d %c %c %c % 20ld % 15ld ", - stream->loom->hostname, - stream->proc->pid, - stream->thread->tid, - ev->header.model, ev->header.category, ev->header.value, clock, delta); - - int payloadsize = ovni_payload_size(ev); - for (int i = 0; i < payloadsize; i++) { - dbg("%d ", ev->payload.u8[i]); - } - dbg("\n"); -} - -static void -print_cur_ev(struct ovni_emu *emu) -{ - print_ev(emu->cur_stream, emu->cur_ev); -} - -/* Update the tracking channel if needed */ -static void -cpu_update_tracking_chan(struct ovni_chan *cpu_chan, struct ovni_ethread *th) -{ - int cpu_enabled = 0; - - switch (cpu_chan->track) { - case CHAN_TRACK_TH_RUNNING: - cpu_enabled = th->is_running; - break; - case CHAN_TRACK_TH_ACTIVE: - cpu_enabled = th->is_active; - break; - default: - dbg("ignoring thread %d chan %d with track=%d\n", - th->tid, cpu_chan->id, cpu_chan->track); - return; - } - - struct ovni_chan *th_chan = &th->chan[cpu_chan->id]; - int th_enabled = chan_is_enabled(th_chan); - - /* Enable the cpu channel if needed */ - if (cpu_enabled && !chan_is_enabled(cpu_chan)) - chan_enable(cpu_chan, cpu_enabled); - - /* Copy the state from the thread channel if needed */ - if (th_enabled && cpu_enabled) { - /* Both enabled: simply follow the same value */ - chan_copy(cpu_chan, th_chan); - } else if (th_enabled && !cpu_enabled) { - /* Only thread enabled: disable CPU */ - if (chan_is_enabled(cpu_chan)) - chan_disable(cpu_chan); - } else if (!th_enabled && cpu_enabled) { - /* Only CPU enabled: is this possible? Set to bad */ - chan_set(cpu_chan, ST_BAD); - err("warning: cpu %s chan %d enabled but tracked thread %d chan disabled\n", - cpu_chan->cpu->name, - cpu_chan->id, - th->tid); - } else { - /* Both disabled: disable CPU channel if needed */ - if (chan_is_enabled(cpu_chan)) - chan_disable(cpu_chan); - } - - dbg("cpu %s chan %d enabled=%d state=%d\n", - cpu_chan->cpu->name, cpu_chan->id, - chan_is_enabled(cpu_chan), - chan_get_st(cpu_chan)); -} - -void -emu_cpu_update_chan(struct ovni_cpu *cpu, struct ovni_chan *cpu_chan) -{ - int count = 0; - struct ovni_ethread *th = NULL; - - /* Determine the source of tracking */ - - switch (cpu_chan->track) { - case CHAN_TRACK_TH_RUNNING: - count = cpu->nrunning_threads; - th = cpu->th_running; - break; - case CHAN_TRACK_TH_ACTIVE: - count = cpu->nactive_threads; - th = cpu->th_active; - break; - default: - dbg("ignoring %s chan %d with track=%d\n", - cpu->name, cpu_chan->id, cpu_chan->track); - return; - } - - /* Based on how many threads, determine the state */ - if (count == 0) { - /* The channel can be already disabled (migration of paused - * thread) so only disable it if needed. */ - if (chan_is_enabled(cpu_chan)) - chan_disable(cpu_chan); - } else if (count == 1) { - if (th == NULL) - die("emu_cpu_update_chan: tracking thread is NULL\n"); - - /* A unique thread found: copy the state */ - dbg("cpu_update_chan: unique thread %d found, updating chan %d\n", - th->tid, cpu_chan->id); - - cpu_update_tracking_chan(cpu_chan, th); - } else { - /* More than one thread: enable the channel and set it to a - * error value */ - if (!chan_is_enabled(cpu_chan)) - chan_enable(cpu_chan, 1); - - if (chan_get_st(cpu_chan) != ST_TOO_MANY_TH) - chan_set(cpu_chan, ST_TOO_MANY_TH); - } -} - -static void -propagate_channels(struct ovni_emu *emu) -{ - struct ovni_chan *th_chan = NULL; - struct ovni_chan *tmp = NULL; - - /* Only propagate thread channels to their corresponding CPU */ - - DL_FOREACH_SAFE(emu->th_chan, th_chan, tmp) - { - if (th_chan->thread == NULL) - die("propagate_channels: channel thread is NULL\n"); - - struct ovni_ethread *thread = th_chan->thread; - - /* No CPU in the thread */ - if (thread->cpu == NULL) - continue; - - struct ovni_cpu *cpu = thread->cpu; - - struct ovni_chan *cpu_chan = &cpu->chan[th_chan->id]; - - dbg("propagate thread %d chan %d in cpu %s\n", - thread->tid, th_chan->id, cpu->name); - - emu_cpu_update_chan(cpu, cpu_chan); - } -} - -static void -emit_channels(struct ovni_emu *emu) -{ - struct ovni_chan *cpu_chan, *th_chan; - - dbg("emu enters emit_channels -------------------\n"); - - /* Emit only the channels that have been updated. We need a list - * of updated channels */ - DL_FOREACH(emu->th_chan, th_chan) - { - dbg("emu emits th chan %d\n", th_chan->id); - chan_emit(th_chan); - } - - DL_FOREACH(emu->cpu_chan, cpu_chan) - { - dbg("emu emits cpu chan %d\n", cpu_chan->id); - chan_emit(cpu_chan); - } - - /* Reset the list of updated channels */ - dbg("emu resets the list of dirty channels -------------------\n"); - emu->th_chan = NULL; - emu->cpu_chan = NULL; -} - -static void -hook_init(struct ovni_emu *emu) -{ - hook_init_ovni(emu); - hook_init_nosv(emu); - hook_init_tampi(emu); - hook_init_openmp(emu); - hook_init_nodes(emu); - hook_init_kernel(emu); - hook_init_nanos6(emu); -} - -static void -hook_end(struct ovni_emu *emu) -{ - hook_end_nosv(emu); - hook_end_nanos6(emu); -} - -static void -hook_pre(struct ovni_emu *emu) -{ - switch (emu->cur_ev->header.model) { - case 'O': - hook_pre_ovni(emu); - break; - case 'V': - hook_pre_nosv(emu); - break; - case 'T': - hook_pre_tampi(emu); - break; - case 'M': - hook_pre_openmp(emu); - break; - case 'D': - hook_pre_nodes(emu); - break; - case 'K': - hook_pre_kernel(emu); - break; - case '6': - hook_pre_nanos6(emu); - break; - default: - break; - } -} - -static void -hook_post(struct ovni_emu *emu) -{ - switch (emu->cur_ev->header.model) { - default: - // dbg("unknown model %c\n", emu->cur_ev->model); - break; - } -} - -static void -set_current(struct ovni_emu *emu, struct ovni_stream *stream) -{ - emu->cur_stream = stream; - emu->cur_ev = stream->cur_ev; - emu->cur_loom = stream->loom; - emu->cur_proc = stream->proc; - emu->cur_thread = stream->thread; -} - -/* - * heap_node_compare_t - comparison function, returns: - - * > 0 if a > b - * < 0 if a < b - * = 0 if a == b - * - * Invert the comparison function to get a min-heap instead - */ -static inline int -stream_cmp(heap_node_t *a, heap_node_t *b) -{ - struct ovni_stream *sa, *sb; - - sa = heap_elem(a, struct ovni_stream, hh); - sb = heap_elem(b, struct ovni_stream, hh); - - if (sb->lastclock < sa->lastclock) - return -1; - else if (sb->lastclock > sa->lastclock) - return +1; - else - return 0; -} - -static double -get_time(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (double) ts.tv_sec + (double) ts.tv_nsec * 1.0e-9; -} - -static void -print_progress(struct ovni_emu *emu) -{ - double cpu_written = (double) ftell(emu->prv_cpu); - double th_written = (double) ftell(emu->prv_thread); - - double written = cpu_written + th_written; - - double progress = ((double) emu->global_offset) - / ((double) emu->global_size); - - double time_now = get_time(); - double time_elapsed = time_now - emu->start_emulation_time; - double time_total = time_elapsed / progress; - double time_left = time_total - time_elapsed; - - double speed_in = (double) emu->nev_processed / time_elapsed; - double speed_out = written / time_elapsed; - - int tmin = (int) (time_left / 60.0); - int sec = (int) ((time_left / 60.0 - tmin) * 60); - - err("%.1f%% done at %.0f Kev/s, out %.1f GB CPU / %.1f GB TH at %.1f MB/s (%d min %d s left)\n", - 100.0 * progress, - speed_in / 1024.0, - cpu_written / (1024.0 * 1024.0 * 1024.0), - th_written / (1024.0 * 1024.0 * 1024.0), - speed_out / (1024.0 * 1024), - tmin, sec); -} - -/* Loads the next event and sets the lastclock in the stream. - * Returns -1 if the stream has no more events. */ -static int -emu_step_stream(struct ovni_emu *emu, struct ovni_stream *stream) -{ - if (ovni_load_next_event(stream) < 0) - return -1; - - stream->lastclock = evclock(stream, stream->cur_ev); - - heap_insert(&emu->sorted_stream, &stream->hh, &stream_cmp); - - return 0; -} - -static int -next_event(struct ovni_emu *emu) -{ - static int done_first = 0; - - /* Extract the next stream based on the event clock */ - heap_node_t *node = heap_pop_max(&emu->sorted_stream, stream_cmp); - - /* No more streams */ - if (node == NULL) - return -1; - - struct ovni_stream *stream = heap_elem(node, struct ovni_stream, hh); - - if (stream == NULL) - die("next_event: heap_elem returned NULL\n"); - - set_current(emu, stream); - - emu->global_offset += ovni_ev_size(stream->cur_ev); - - // err("stream %d clock at %ld\n", stream->tid, stream->lastclock); - - /* This can happen if two events are not ordered in the stream, but the - * emulator picks other events in the middle. Example: - * - * Stream A: 10 3 ... - * Stream B: 5 12 - * - * emulator output: - * 5 - * 10 - * 3 -> warning! - * 12 - * ... - * */ - if (emu->lastclock > stream->lastclock) { - err("warning: backwards jump in time %lu -> %lu for tid %d\n", - emu->lastclock, stream->lastclock, stream->tid); - - if (emu->enable_linter) - abort(); - } - - emu->lastclock = stream->lastclock; - - if (!done_first) { - done_first = 1; - emu->firstclock = emu->lastclock; - } - - emu->delta_time = emu->lastclock - emu->firstclock; - - return 0; -} - -static void -emu_load_first_events(struct ovni_emu *emu) -{ - /* Prepare the stream heap */ - heap_init(&emu->sorted_stream); - - emu->lastclock = 0; - - /* Load initial streams and events */ - struct ovni_trace *trace = &emu->trace; - for (size_t i = 0; i < trace->nstreams; i++) { - struct ovni_stream *stream = &trace->stream[i]; - emu->global_size += stream->size; - - if (emu_step_stream(emu, stream) < 0) { - err("warning: empty stream for tid %d\n", stream->tid); - - if (emu->enable_linter) - abort(); - - continue; - } - } -} - -void -emu_run(struct ovni_emu *emu) -{ - emu->nev_processed = 0; - emu_load_first_events(emu); - emu->start_emulation_time = get_time(); - hook_init(emu); - emit_channels(emu); - - /* Then process all events */ - for (size_t i = 0; next_event(emu) == 0; i++) { - print_cur_ev(emu); - - hook_pre(emu); - - propagate_channels(emu); - emit_channels(emu); - - hook_post(emu); - - if (i >= 100000) { - print_progress(emu); - i = 0; - } - - emu->nev_processed++; - - emu_step_stream(emu, emu->cur_stream); - } - - hook_end(emu); - print_progress(emu); -} - -struct ovni_ethread * -emu_get_thread(struct ovni_eproc *proc, int tid) -{ - for (size_t i = 0; i < proc->nthreads; i++) { - struct ovni_ethread *thread = &proc->thread[i]; - if (thread->tid == tid) - return thread; - } - - return NULL; -} - -static void -add_new_cpu(struct ovni_emu *emu, struct ovni_loom *loom, int i, int phyid) -{ - struct ovni_cpu *cpu = &loom->cpu[i]; - - if (i < 0 || i >= (int) loom->ncpus) - die("CPU with index %d in loom %s is out of bounds\n", - i, loom->hostname); - - if (cpu->state != CPU_ST_UNKNOWN) - die("new cpu %d in unexpected state in loom %s\n", - i, loom->hostname); - - cpu->state = CPU_ST_READY; - cpu->i = i; - cpu->phyid = phyid; - cpu->gindex = emu->total_ncpus++; - cpu->loom = loom; - - dbg("new cpu %d at phyid=%d\n", cpu->gindex, phyid); -} - -static int -proc_load_cpus(struct ovni_emu *emu, struct ovni_loom *loom, - struct ovni_eproc *proc, - struct ovni_eproc *metadata_proc) -{ - JSON_Object *meta = json_value_get_object(proc->meta); - if (meta == NULL) - die("json_value_get_object() failed\n"); - - JSON_Array *cpuarray = json_object_get_array(meta, "cpus"); - - /* This process doesn't have the cpu list */ - if (cpuarray == NULL) - return -1; - - if (metadata_proc) - die("duplicated metadata for proc %d and %d in loom %s\n", - metadata_proc->pid, proc->pid, - loom->hostname); - - if (loom->ncpus != 0) - die("loom %s already has CPUs\n", loom->hostname); - - loom->ncpus = json_array_get_count(cpuarray); - - if (loom->ncpus == 0) - die("loom %s proc %d has metadata but no CPUs\n", - loom->hostname, proc->pid); - - loom->cpu = calloc(loom->ncpus, sizeof(struct ovni_cpu)); - - if (loom->cpu == NULL) - die("calloc failed: %s\n", strerror(errno)); - - for (size_t i = 0; i < loom->ncpus; i++) { - JSON_Object *cpu = json_array_get_object(cpuarray, i); - - if (cpu == NULL) - die("proc_load_cpus: json_array_get_object() failed\n"); - - int index = (int) json_object_get_number(cpu, "index"); - int phyid = (int) json_object_get_number(cpu, "phyid"); - - add_new_cpu(emu, loom, index, phyid); - } - - /* If we reach this point, all CPUs are in the ready state */ - - /* Init the vcpu as well */ - struct ovni_cpu *vcpu = &loom->vcpu; - if (vcpu->state != CPU_ST_UNKNOWN) - die("unexpected virtual CPU state in loom %s\n", - loom->hostname); - - vcpu->state = CPU_ST_READY; - vcpu->i = -1; - vcpu->phyid = -1; - vcpu->gindex = emu->total_ncpus++; - vcpu->loom = loom; - - dbg("new vcpu %d\n", vcpu->gindex); - - return 0; -} - -/* Obtain CPUs in the metadata files and other data */ -static void -load_metadata(struct ovni_emu *emu) -{ - struct ovni_trace *trace = &emu->trace; - - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - loom->offset_ncpus = emu->total_ncpus; - - struct ovni_eproc *metadata_proc = NULL; - - for (size_t j = 0; j < loom->nprocs; j++) { - struct ovni_eproc *proc = &loom->proc[j]; - - if (proc_load_cpus(emu, loom, proc, metadata_proc) < 0) - continue; - - if (metadata_proc) - die("duplicated metadata found in pid %d and %d\n", - metadata_proc->pid, - proc->pid); - - metadata_proc = proc; - } - - /* One of the process must have the list of CPUs */ - if (metadata_proc == NULL) - die("no metadata found in loom %s\n", loom->hostname); - - if (loom->ncpus == 0) - die("no CPUs found in loom %s\n", loom->hostname); - } -} - -static int -destroy_metadata(struct ovni_emu *emu) -{ - struct ovni_trace *trace = &emu->trace; - - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - for (size_t j = 0; j < loom->nprocs; j++) { - struct ovni_eproc *proc = &loom->proc[j]; - - if (proc->meta == NULL) - die("cannot destroy metadata: is NULL\n"); - - json_value_free(proc->meta); - } - - free(loom->cpu); - } - - return 0; -} - -static void -open_prvs(struct ovni_emu *emu, char *tracedir) -{ - char path[PATH_MAX]; - - sprintf(path, "%s/%s", tracedir, "thread.prv"); - - emu->prv_thread = fopen(path, "w"); - - if (emu->prv_thread == NULL) { - err("error opening thread PRV file %s: %s\n", path, - strerror(errno)); - exit(EXIT_FAILURE); - } - - sprintf(path, "%s/%s", tracedir, "cpu.prv"); - - emu->prv_cpu = fopen(path, "w"); - - if (emu->prv_cpu == NULL) { - err("error opening cpu PRV file %s: %s\n", path, - strerror(errno)); - exit(EXIT_FAILURE); - } - - prv_header(emu->prv_thread, emu->total_nthreads); - prv_header(emu->prv_cpu, emu->total_ncpus); -} - -static void -open_pcfs(struct ovni_emu *emu, char *tracedir) -{ - char path[PATH_MAX]; - - sprintf(path, "%s/%s", tracedir, "thread.pcf"); - pcf_open(&emu->pcf[CHAN_TH], path, CHAN_TH); - - sprintf(path, "%s/%s", tracedir, "cpu.pcf"); - pcf_open(&emu->pcf[CHAN_CPU], path, CHAN_CPU); -} - -/* Fix the trace duration at the end */ -static void -fix_prv_headers(struct ovni_emu *emu) -{ - prv_fix_header(emu->prv_thread, emu->delta_time, emu->total_nthreads); - prv_fix_header(emu->prv_cpu, emu->delta_time, emu->total_ncpus); -} - -static void -close_prvs(struct ovni_emu *emu) -{ - fclose(emu->prv_thread); - fclose(emu->prv_cpu); -} - -static void -close_pcfs(struct ovni_emu *emu) -{ - pcf_close(&emu->pcf[CHAN_TH]); - pcf_close(&emu->pcf[CHAN_CPU]); -} - -static void -usage(void) -{ - err("Usage: ovniemu [-c offsetfile] tracedir\n"); - err("\n"); - err("Options:\n"); - err(" -c offsetfile Use the given offset file to correct\n"); - err(" the clocks among nodes. It can be\n"); - err(" generated by the ovnisync program\n"); - err("\n"); - err(" tracedir The output trace dir generated by ovni.\n"); - err("\n"); - err("The output PRV files are placed in the tracedir directory.\n"); - - exit(EXIT_FAILURE); -} - -static void -parse_args(struct ovni_emu *emu, int argc, char *argv[]) -{ - int opt; - - while ((opt = getopt(argc, argv, "c:l")) != -1) { - switch (opt) { - case 'c': - emu->clock_offset_file = optarg; - break; - case 'l': - emu->enable_linter = 1; - break; - default: /* '?' */ - usage(); - } - } - - if (optind >= argc) { - err("missing tracedir\n"); - usage(); - } - - emu->tracedir = argv[optind]; -} - -static void -set_clock_offsets(struct ovni_emu *emu, const char *host, size_t offset) -{ - size_t matches = 0; - - for (size_t i = 0; i < emu->trace.nlooms; i++) { - struct ovni_loom *loom = &emu->trace.loom[i]; - - /* Match the hostname exactly */ - if (strcmp(loom->hostname, host) != 0) - continue; - - if (loom->clock_offset != 0) - die("loom %s already has a clock offset\n", loom->dname); - - loom->clock_offset = offset; - matches++; - } - - if (matches == 0) - die("no loom has hostname %s\n", host); -} - -static void -load_clock_offsets(struct ovni_emu *emu) -{ - FILE *f = NULL; - - if (emu->clock_offset_file != NULL) { - f = fopen(emu->clock_offset_file, "r"); - - /* If provided by the user, it must exist */ - if (f == NULL) { - err("error opening clock offset file %s: %s\n", - emu->clock_offset_file, - strerror(errno)); - exit(EXIT_FAILURE); - } - } else { - char path[PATH_MAX]; - if (snprintf(path, PATH_MAX, "%s/clock-offsets.txt", - emu->tracedir) - >= PATH_MAX) { - die("clock offset path too long\n"); - } - - f = fopen(path, "r"); - - if (f == NULL) { - /* May not exist, but is fine */ - return; - } - } - - /* Ignore header line */ - char buf[1024]; - if (fgets(buf, 1024, f) == NULL) { - err("missing header line in clock offset file"); - exit(EXIT_FAILURE); - } - - while (1) { - errno = 0; - int rank, ret; - double offset, mean, std; - char host[OVNI_MAX_HOSTNAME]; - ret = fscanf(f, "%d %s %lf %lf %lf", &rank, host, &offset, &mean, &std); - - if (ret == EOF) { - if (errno != 0) { - perror("fscanf failed"); - exit(EXIT_FAILURE); - } - - break; - } - - if (ret != 5) { - err("fscanf read %d instead of 5 fields in %s\n", - ret, emu->clock_offset_file); - exit(EXIT_FAILURE); - } - - set_clock_offsets(emu, host, (int64_t) offset); - } - - /* Then populate the stream offsets */ - - struct ovni_trace *trace = &emu->trace; - - for (size_t i = 0; i < trace->nstreams; i++) { - struct ovni_stream *stream = &trace->stream[i]; - struct ovni_loom *loom = stream->loom; - stream->clock_offset = loom->clock_offset; - } - - fclose(f); - - err("loaded clock offsets ok\n"); -} - -static void -write_row_cpu(struct ovni_emu *emu) -{ - char path[PATH_MAX]; - - sprintf(path, "%s/%s", emu->tracedir, "cpu.row"); - - FILE *f = fopen(path, "w"); - - if (f == NULL) { - perror("cannot open row file"); - exit(EXIT_FAILURE); - } - - fprintf(f, "LEVEL NODE SIZE 1\n"); - fprintf(f, "hostname\n"); - fprintf(f, "\n"); - - fprintf(f, "LEVEL THREAD SIZE %ld\n", emu->total_ncpus); - - for (size_t i = 0; i < emu->total_ncpus; i++) { - struct ovni_cpu *cpu = emu->global_cpu[i]; - fprintf(f, "%s\n", cpu->name); - } - - fclose(f); -} - -static void -write_row_thread(struct ovni_emu *emu) -{ - char path[PATH_MAX]; - - sprintf(path, "%s/%s", emu->tracedir, "thread.row"); - - FILE *f = fopen(path, "w"); - - if (f == NULL) { - perror("cannot open row file"); - exit(EXIT_FAILURE); - } - - fprintf(f, "LEVEL NODE SIZE 1\n"); - fprintf(f, "hostname\n"); - fprintf(f, "\n"); - - fprintf(f, "LEVEL THREAD SIZE %ld\n", emu->total_nthreads); - - for (size_t i = 0; i < emu->total_nthreads; i++) { - struct ovni_ethread *th = emu->global_thread[i]; - fprintf(f, "THREAD %d.%d\n", th->proc->appid, th->tid); - } - - fclose(f); -} - -static void -init_threads(struct ovni_emu *emu) -{ - emu->total_nthreads = 0; - emu->total_nprocs = 0; - - struct ovni_trace *trace = &emu->trace; - - /* Count total processes and threads */ - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - for (size_t j = 0; j < loom->nprocs; j++) { - struct ovni_eproc *proc = &loom->proc[j]; - emu->total_nprocs++; - for (size_t k = 0; k < proc->nthreads; k++) { - emu->total_nthreads++; - } - } - } - - emu->global_thread = calloc(emu->total_nthreads, - sizeof(*emu->global_thread)); - - if (emu->global_thread == NULL) { - perror("calloc failed"); - exit(EXIT_FAILURE); - } - - int gi = 0; - - /* Populate global_thread array */ - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - for (size_t j = 0; j < loom->nprocs; j++) { - struct ovni_eproc *proc = &loom->proc[j]; - for (size_t k = 0; k < proc->nthreads; k++) { - struct ovni_ethread *thread = &proc->thread[k]; - - emu->global_thread[gi++] = thread; - } - } - } -} - -static void -init_cpus(struct ovni_emu *emu) -{ - struct ovni_trace *trace = &emu->trace; - - emu->global_cpu = calloc(emu->total_ncpus, - sizeof(*emu->global_cpu)); - - if (emu->global_cpu == NULL) { - perror("calloc"); - exit(EXIT_FAILURE); - } - - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - for (size_t j = 0; j < loom->ncpus; j++) { - struct ovni_cpu *cpu = &loom->cpu[j]; - emu->global_cpu[cpu->gindex] = cpu; - - if (snprintf(cpu->name, MAX_CPU_NAME, "CPU %ld.%ld", i, j) - >= MAX_CPU_NAME) { - err("error cpu %ld.%ld name too long\n", i, j); - exit(EXIT_FAILURE); - } - cpu->virtual = 0; - } - - emu->global_cpu[loom->vcpu.gindex] = &loom->vcpu; - if (snprintf(loom->vcpu.name, MAX_CPU_NAME, "CPU %ld.*", i) - >= MAX_CPU_NAME) { - err("error cpu %ld.* name too long\n", i); - exit(EXIT_FAILURE); - } - loom->vcpu.virtual = 1; - } -} - -static void -create_pcf_cpus(struct ovni_emu *emu) -{ - /* Only needed for the thread PCF */ - struct pcf_file *pcf = &emu->pcf[CHAN_TH]; - int prvtype = chan_to_prvtype[CHAN_OVNI_CPU]; - struct pcf_type *type = pcf_find_type(pcf, prvtype); - - if (type == NULL) - die("cannot find PCF type for CHAN_OVNI_CPU\n"); - - for (size_t i = 0; i < emu->total_ncpus; i++) { - int value = i + 1; - char *label = emu->global_cpu[i]->name; - - pcf_add_value(type, value, label); - } -} - -void -emu_init(struct ovni_emu *emu, int argc, char *argv[]) -{ - memset(emu, 0, sizeof(*emu)); - - parse_args(emu, argc, argv); - - if (ovni_load_trace(&emu->trace, emu->tracedir)) { - err("error loading ovni trace\n"); - exit(EXIT_FAILURE); - } - - if (ovni_load_streams(&emu->trace)) { - err("error loading streams\n"); - exit(EXIT_FAILURE); - } - - load_metadata(emu); - - load_clock_offsets(emu); - - init_threads(emu); - init_cpus(emu); - - open_prvs(emu, emu->tracedir); - open_pcfs(emu, emu->tracedir); - - create_pcf_cpus(emu); - - emu->global_size = 0; - emu->global_offset = 0; - - for (size_t i = 0; i < emu->trace.nstreams; i++) - emu->global_offset += emu->trace.stream[i].offset; - - err("loaded %ld cpus and %ld threads\n", - emu->total_ncpus, - emu->total_nthreads); -} - -static int -copy_file(const char *src, const char *dst) -{ - char buffer[1024]; - - FILE *infile = fopen(src, "r"); - - if (infile == NULL) { - err("fopen(%s) failed: %s\n", src, strerror(errno)); - return -1; - } - - FILE *outfile = fopen(dst, "w"); - - if (outfile == NULL) { - err("fopen(%s) failed: %s\n", src, strerror(errno)); - return -1; - } - - size_t bytes; - while ((bytes = fread(buffer, 1, sizeof(buffer), infile)) > 0) - fwrite(buffer, 1, bytes, outfile); - - fclose(outfile); - fclose(infile); - - return 0; -} - -static int -copy_recursive(const char *src, const char *dst) -{ - DIR *dir; - int failed = 0; - - if ((dir = opendir(src)) == NULL) { - err("opendir \"%s\" failed: %s\n", src, strerror(errno)); - failed = 1; - goto bay; - } - - if (mkdir(dst, 0755) != 0) { - err("mkdir \"%s\" failed: %s\n", src, strerror(errno)); - failed = 1; - goto bay; - } - - /* Use the heap, as the recursion may exhaust the stack */ - char *newsrc = calloc(1, PATH_MAX); - if (newsrc == NULL) - die("calloc failed\n"); - - char *newdst = calloc(1, PATH_MAX); - if (newdst == NULL) - die("calloc failed\n"); - - struct dirent *dirent; - while ((dirent = readdir(dir)) != NULL) { - struct stat st; - sprintf(newsrc, "%s/%s", src, dirent->d_name); - - if (strcmp(dirent->d_name, ".") == 0) - continue; - - if (strcmp(dirent->d_name, "..") == 0) - continue; - - int n = snprintf(newsrc, PATH_MAX, "%s/%s", - src, dirent->d_name); - - if (n >= PATH_MAX) { - err("path too long \"%s/%s\"\n", src, dirent->d_name); - failed = 1; - continue; - } - - int m = snprintf(newdst, PATH_MAX, "%s/%s", - dst, dirent->d_name); - - if (m >= PATH_MAX) { - err("path too long \"%s/%s\"\n", dst, dirent->d_name); - failed = 1; - continue; - } - - if (stat(newsrc, &st) != 0) { - err("stat \"%s\" failed: %s\n", newsrc, - strerror(errno)); - failed = 1; - continue; - } - - if (S_ISDIR(st.st_mode)) { - if (copy_recursive(newsrc, newdst) != 0) { - failed = 1; - } - } else { - if (copy_file(newsrc, newdst) != 0) { - failed = 1; - } - } - } - - closedir(dir); - - free(newsrc); - free(newdst); - -bay: - return -failed; -} - -static void -copy_configs(struct ovni_emu *emu) -{ - /* Allow override so we can run the tests without install */ - char *src = getenv("OVNI_CONFIG_DIR"); - - if (src == NULL) - src = OVNI_CONFIG_DIR; - - char dst[PATH_MAX]; - if (snprintf(dst, PATH_MAX, "%s/cfg", emu->tracedir) >= PATH_MAX) { - err("cannot copy config files: path too long \"%s/cfg\"\n", - emu->tracedir); - return; - } - - struct stat st; - if (stat(dst, &st) == 0) { - err("existing cfg directory \"%s\", skipping config copy\n", dst); - if (emu->enable_linter) - die("cannot continue in linter mode\n"); - return; - } - - if (copy_recursive(src, dst) != 0) { - err("warning: cannot copy config files: recursive copy failed\n"); - if (emu->enable_linter) - die("cannot continue in linter mode\n"); - } -} - -void -emu_post(struct ovni_emu *emu) -{ - /* Write the PCF files */ - pcf_write(&emu->pcf[CHAN_TH]); - pcf_write(&emu->pcf[CHAN_CPU]); - - write_row_cpu(emu); - write_row_thread(emu); - - copy_configs(emu); -} - -void -emu_destroy(struct ovni_emu *emu) -{ - fix_prv_headers(emu); - close_prvs(emu); - close_pcfs(emu); - destroy_metadata(emu); - ovni_free_streams(&emu->trace); - ovni_free_trace(&emu->trace); - - free(emu->global_cpu); - free(emu->global_thread); -} - -void -edie(struct ovni_emu *emu, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - - fprintf(stderr, "fatal: "); - vfprintf(stderr, fmt, args); - va_end(args); - - fprintf(stderr, "fatal: while evaluating the event %c%c%c with clock=%ld in thread=%d\n", - emu->cur_ev->header.model, - emu->cur_ev->header.category, - emu->cur_ev->header.value, - emu->cur_ev->header.clock, - emu->cur_thread->tid); - - abort(); -} - -void -eerr(struct ovni_emu *emu, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - - fprintf(stderr, "fatal: "); - vfprintf(stderr, fmt, args); - va_end(args); - - fprintf(stderr, "fatal: while evaluating the event %c%c%c with clock=%ld in thread=%d\n", - emu->cur_ev->header.model, - emu->cur_ev->header.category, - emu->cur_ev->header.value, - emu->cur_ev->header.clock, - emu->cur_thread->tid); -} diff --git a/src/emu/old_emu.h b/src/emu/old_emu.h deleted file mode 100644 index ce8338e..0000000 --- a/src/emu/old_emu.h +++ /dev/null @@ -1,586 +0,0 @@ -/* Copyright (c) 2021 Barcelona Supercomputing Center (BSC) - * SPDX-License-Identifier: GPL-3.0-or-later */ - -#ifndef OVNI_EMU_H -#define OVNI_EMU_H - -#include - -#include "common.h" -#include "heap.h" -#include "ovni.h" -#include "parson.h" -#include "pcf.h" -#include "uthash.h" - -/* Emulated thread runtime status */ -enum ethread_state { - TH_ST_UNKNOWN, - TH_ST_RUNNING, - TH_ST_PAUSED, - TH_ST_DEAD, - TH_ST_COOLING, - TH_ST_WARMING, -}; - -enum task_state { - TASK_ST_CREATED, - TASK_ST_RUNNING, - TASK_ST_PAUSED, - TASK_ST_DEAD, -}; - -enum ovni_state { - ST_OVNI_FLUSHING = 1, -}; - -enum error_values { - ST_BAD = 666, - ST_TOO_MANY_TH = 777, -}; - -enum nosv_ss_values { - ST_NULL = 0, - ST_NOSV_SCHED_HUNGRY = 6, - ST_NOSV_SCHED_SERVING, - ST_NOSV_SCHED_SUBMITTING, - ST_NOSV_MEM_ALLOCATING, - ST_NOSV_MEM_FREEING, - ST_NOSV_TASK_RUNNING, - ST_NOSV_API_SUBMIT, - ST_NOSV_API_PAUSE, - ST_NOSV_API_YIELD, - ST_NOSV_API_WAITFOR, - ST_NOSV_API_SCHEDPOINT, - ST_NOSV_ATTACH, - ST_NOSV_WORKER, - ST_NOSV_DELEGATE, - - EV_NOSV_SCHED_RECV, - EV_NOSV_SCHED_SEND, - EV_NOSV_SCHED_SELF, -}; - -enum tampi_state { - ST_TAMPI_SEND = 1, - ST_TAMPI_RECV = 2, - ST_TAMPI_ISEND = 3, - ST_TAMPI_IRECV = 4, - ST_TAMPI_WAIT = 5, - ST_TAMPI_WAITALL = 6, -}; - -enum openmp_state { - ST_OPENMP_TASK = 1, - ST_OPENMP_PARALLEL = 2, -}; - -enum nodes_state { - ST_NODES_REGISTER = 1, - ST_NODES_UNREGISTER = 2, - ST_NODES_IF0_WAIT = 3, - ST_NODES_IF0_INLINE = 4, - ST_NODES_TASKWAIT = 5, - ST_NODES_CREATE = 6, - ST_NODES_SUBMIT = 7, - ST_NODES_SPAWN = 8, -}; - -/* The values of nanos6_ss_state are synced to the previous - * CTF implementation. */ -enum nanos6_ss_state { - ST_NANOS6_TASK_BODY = 1, - ST_NANOS6_TASK_CREATING, - ST_NANOS6_TASK_SUBMIT, - ST_NANOS6_TASK_SPAWNING, - ST_NANOS6_TASK_FOR, - ST_NANOS6_SCHED_ADDING, - ST_NANOS6_SCHED_PROCESSING, - ST_NANOS6_SCHED_SERVING, - ST_NANOS6_DEP_REG, - ST_NANOS6_DEP_UNREG, - ST_NANOS6_BLK_TASKWAIT, - ST_NANOS6_BLK_WAITFOR, - ST_NANOS6_BLK_BLOCKING, - ST_NANOS6_BLK_UNBLOCKING, - ST_NANOS6_ALLOCATING, - ST_NANOS6_FREEING, - ST_NANOS6_HANDLING_TASK, - ST_NANOS6_WORKER_LOOP, - ST_NANOS6_SWITCH_TO, - ST_NANOS6_MIGRATE, - ST_NANOS6_SUSPEND, - ST_NANOS6_RESUME, - - /* Value 51 is broken in old Paraver */ - EV_NANOS6_SCHED_RECV = 60, - EV_NANOS6_SCHED_SEND, - EV_NANOS6_SCHED_SELF, - EV_NANOS6_CPU_IDLE, - EV_NANOS6_CPU_ACTIVE, - EV_NANOS6_SIGNAL, -}; - -enum nanos6_thread_type { - ST_NANOS6_TH_LEADER = 1, - ST_NANOS6_TH_MAIN = 2, - ST_NANOS6_TH_WORKER = 3, - ST_NANOS6_TH_EXTERNAL = 4, -}; - -enum kernel_cs_state { - ST_KERNEL_CSOUT = 3, -}; - -struct ovni_ethread; -struct ovni_eproc; - -struct task_type { - uint32_t id; /* Per-process task identifier */ - uint32_t gid; /* Global identifier computed from the label */ - char label[MAX_PCF_LABEL]; - UT_hash_handle hh; -}; - -struct task { - uint32_t id; - struct task_type *type; - - /* The thread that has began to execute the task. It cannot - * change after being set, even if the task ends. */ - struct ovni_ethread *thread; - enum task_state state; - UT_hash_handle hh; - - /* List handle for nested task support */ - struct task *next; - struct task *prev; -}; - -struct task_info { - /* Both hash maps of all known tasks and types */ - struct task_type *types; - struct task *tasks; -}; - -struct task_stack { - union { - struct task *top; /* Synctactic sugar */ - struct task *tasks; - }; - struct ovni_ethread *thread; -}; - -#define MAX_CHAN_STACK 512 - -enum chan_track { - /* The channel is manually controlled. */ - CHAN_TRACK_NONE = 0, - - /* Enables the channel when the thread is running only. */ - CHAN_TRACK_TH_RUNNING, - - /* The thread active tracking mode a enables the channel when - * the thread is running, cooling or warming. Otherwise the - * channel is disabled. */ - CHAN_TRACK_TH_ACTIVE, -}; - -enum chan { - CHAN_OVNI_PID, - CHAN_OVNI_TID, - CHAN_OVNI_NRTHREADS, - CHAN_OVNI_STATE, - CHAN_OVNI_APPID, - CHAN_OVNI_CPU, - CHAN_OVNI_FLUSH, - - CHAN_NOSV_TASKID, - CHAN_NOSV_TYPE, - CHAN_NOSV_APPID, - CHAN_NOSV_SUBSYSTEM, - CHAN_NOSV_RANK, - - CHAN_TAMPI_MODE, - CHAN_OPENMP_MODE, - CHAN_NODES_SUBSYSTEM, - - CHAN_NANOS6_TASKID, - CHAN_NANOS6_TYPE, - CHAN_NANOS6_SUBSYSTEM, - CHAN_NANOS6_RANK, - CHAN_NANOS6_THREAD, - - CHAN_KERNEL_CS, - - CHAN_MAX -}; - -enum chan_type { - CHAN_TH = 0, - CHAN_CPU = 1, - CHAN_MAXTYPE = 2, -}; - -enum chan_dirty { - CHAN_CLEAN = 0, - - /* The channel is dirty because it has been enabled or disabled */ - CHAN_DIRTY_ACTIVE = 1, - - /* The channel is dirty because it changed the state */ - CHAN_DIRTY_VALUE = 2, -}; - -/* clang-format off */ -static const int chan_to_prvtype[CHAN_MAX] = { - [CHAN_OVNI_PID] = 1, - [CHAN_OVNI_TID] = 2, - [CHAN_OVNI_NRTHREADS] = 3, - [CHAN_OVNI_STATE] = 4, - [CHAN_OVNI_APPID] = 5, /* Not used */ - [CHAN_OVNI_CPU] = 6, - [CHAN_OVNI_FLUSH] = 7, - [CHAN_NOSV_TASKID] = 10, - [CHAN_NOSV_TYPE] = 11, - [CHAN_NOSV_APPID] = 12, - [CHAN_NOSV_SUBSYSTEM] = 13, - [CHAN_NOSV_RANK] = 14, - [CHAN_TAMPI_MODE] = 20, - [CHAN_OPENMP_MODE] = 25, - [CHAN_NODES_SUBSYSTEM] = 30, - [CHAN_NANOS6_TASKID] = 35, - [CHAN_NANOS6_TYPE] = 36, - [CHAN_NANOS6_SUBSYSTEM] = 37, - [CHAN_NANOS6_RANK] = 38, - [CHAN_NANOS6_THREAD] = 39, - [CHAN_KERNEL_CS] = 45, -}; -/* clang-format on */ - -struct ovni_chan { - /* Channel id */ - enum chan id; - - /* Number of states in the stack */ - int n; - - /* Stack of states */ - int stack[MAX_CHAN_STACK]; - - /* 1 if enabled, 0 if not. */ - int enabled; - - /* What state should be shown in errors */ - int badst; - - /* Last state emitted (-1 otherwise) */ - int lastst; - - /* Punctual event: -1 if not used */ - int ev; - - /* Emit events of this type */ - int type; - - /* A pointer to a clock to sample the time */ - int64_t *clock; - - /* The time of the last state or event */ - int64_t t; - - /* Paraver row */ - int row; - - /* Type of dirty */ - enum chan_dirty dirty; - - /* Where should the events be written to? */ - FILE *prv; - - /* What should cause the channel to become disabled? */ - enum chan_track track; - - /* The thread associated with the channel if any */ - struct ovni_ethread *thread; - - /* The CPU associated with the channel if any */ - struct ovni_cpu *cpu; - - struct ovni_chan **update_list; - - /* Used when the channel is a list */ - struct ovni_chan *prev; - struct ovni_chan *next; -}; - -#define MAX_BURSTS 100 - -/* State of each emulated thread */ -struct ovni_ethread { - /* Emulated thread tid */ - pid_t tid; - - int index; - int gindex; - - /* The process associated with this thread */ - struct ovni_eproc *proc; - - enum ethread_state state; - int is_running; - int is_active; - - /* Thread stream */ - struct ovni_stream *stream; - - /* Current cpu */ - struct ovni_cpu *cpu; - - /* FIXME: Use a table with registrable pointers to custom data - * structures */ - - /* Task stacks, top ones are the tasks currently runnable. */ - struct task_stack nosv_task_stack; - struct task_stack nanos6_task_stack; - - /* Channels are used to output the emulator state in PRV */ - struct ovni_chan chan[CHAN_MAX]; - - /* Burst times */ - int nbursts; - int64_t burst_time[MAX_BURSTS]; - - /* These pointers keep a linked list of threads in each CPU */ - struct ovni_ethread *prev; - struct ovni_ethread *next; - - /* Trace file path */ - char tracefile[PATH_MAX]; -}; - -/* State of each emulated process */ -struct ovni_eproc { - int pid; - int index; - int gindex; - int appid; - int rank; - - /* The loom of the current process */ - struct ovni_loom *loom; - - /* Path of the process tracedir */ - char dir[PATH_MAX]; - - /* Threads */ - size_t nthreads; - struct ovni_ethread *thread; - - JSON_Value *meta; - - /* ------ Subsystem specific data --------*/ - /* TODO: Use dynamic allocation */ - - struct task_info nosv_task_info; - struct task_info nanos6_task_info; -}; - - -/* ------------------ emulation ---------------- */ - -enum ovni_cpu_type { - CPU_REAL, - CPU_VIRTUAL, -}; - -enum ovni_cpu_state { - CPU_ST_UNKNOWN, - CPU_ST_READY, -}; - -#define MAX_CPU_NAME 32 - -struct ovni_cpu { - /* Logical index: 0 to ncpus - 1 */ - int i; - - /* Physical id: as reported by lscpu(1) */ - int phyid; - - /* Global index for all CPUs */ - int gindex; - - enum ovni_cpu_state state; - - /* The loom of the CPU */ - struct ovni_loom *loom; - - /* CPU channels */ - struct ovni_chan chan[CHAN_MAX]; - - /* The threads assigned to this CPU */ - size_t nthreads; - struct ovni_ethread *thread; - - /* Running threads */ - size_t nrunning_threads; - struct ovni_ethread *th_running; - - /* Active threads (not paused or dead) */ - size_t nactive_threads; - struct ovni_ethread *th_active; - - /* Cpu name as shown in paraver row */ - char name[MAX_CPU_NAME]; - - /* Is this a virtual CPU? */ - int virtual; -}; - -/* ----------------------- trace ------------------------ */ - -/* State of each loom on post-process */ -struct ovni_loom { - size_t nprocs; - char hostname[OVNI_MAX_HOSTNAME]; - char dname[PATH_MAX]; /* Loom directory name */ - char path[PATH_MAX]; /* Relative to cwd */ - - size_t max_ncpus; - size_t max_phyid; - size_t ncpus; - size_t offset_ncpus; - struct ovni_cpu *cpu; - int rank_enabled; - - int64_t clock_offset; - - /* Virtual CPU */ - struct ovni_cpu vcpu; - - struct ovni_eproc *proc; -}; - -#define MAX_VIRTUAL_EVENTS 16 - -struct ovni_trace { - size_t nlooms; - struct ovni_loom *loom; - - size_t nstreams; - struct ovni_stream *stream; -}; - -struct ovni_stream { - uint8_t *buf; - size_t size; - size_t offset; - - int tid; - struct ovni_loom *loom; - struct ovni_eproc *proc; - struct ovni_ethread *thread; - int loaded; - int active; - - double progress; - - struct ovni_ev *cur_ev; - int64_t lastclock; - int64_t clock_offset; - - heap_node_t hh; -}; - -struct ovni_emu { - struct ovni_trace trace; - - struct ovni_stream *cur_stream; - struct ovni_ev *cur_ev; - - struct ovni_loom *cur_loom; - struct ovni_eproc *cur_proc; - struct ovni_ethread *cur_thread; - - /* Indexed by gindex */ - struct ovni_ethread **global_thread; - struct ovni_cpu **global_cpu; - - /* Global processed size and offset of all streams */ - size_t global_size; - size_t global_offset; - double start_emulation_time; - - int64_t firstclock; - int64_t lastclock; - int64_t delta_time; - - /* Counters for statistics */ - int64_t nev_processed; - - /* Be strict */ - int enable_linter; - - FILE *prv_thread; - FILE *prv_cpu; - - struct pcf_file pcf[CHAN_MAXTYPE]; - - char *clock_offset_file; - char *tracedir; - - /* Total counters */ - size_t total_nthreads; - size_t total_nprocs; - size_t total_ncpus; - - uint32_t nosv_type_counter; - - /* Keep a list of dirty channels for the CPUs and threads */ - struct ovni_chan *cpu_chan; - struct ovni_chan *th_chan; - - heap_head_t sorted_stream; -}; - -/* Emulator function declaration */ - -void edie(struct ovni_emu *emu, const char *fmt, ...); -void eerr(struct ovni_emu *emu, const char *fmt, ...); - -void hook_init_ovni(struct ovni_emu *emu); -void hook_pre_ovni(struct ovni_emu *emu); - -void hook_init_nosv(struct ovni_emu *emu); -void hook_pre_nosv(struct ovni_emu *emu); -void hook_end_nosv(struct ovni_emu *emu); - -void hook_init_tampi(struct ovni_emu *emu); -void hook_pre_tampi(struct ovni_emu *emu); - -void hook_init_openmp(struct ovni_emu *emu); -void hook_pre_openmp(struct ovni_emu *emu); - -void hook_init_nodes(struct ovni_emu *emu); -void hook_pre_nodes(struct ovni_emu *emu); - -void hook_init_kernel(struct ovni_emu *emu); -void hook_pre_kernel(struct ovni_emu *emu); - -void hook_init_nanos6(struct ovni_emu *emu); -void hook_pre_nanos6(struct ovni_emu *emu); -void hook_end_nanos6(struct ovni_emu *emu); - -struct ovni_cpu *emu_get_cpu(struct ovni_loom *loom, int cpuid); - -struct ovni_ethread *emu_get_thread(struct ovni_eproc *proc, int tid); - -void emu_cpu_update_chan(struct ovni_cpu *cpu, struct ovni_chan *cpu_chan); - -void emu_init(struct ovni_emu *emu, int argc, char *argv[]); -void emu_run(struct ovni_emu *emu); -void emu_post(struct ovni_emu *emu); -void emu_destroy(struct ovni_emu *emu); - -#endif /* OVNI_EMU_H */ diff --git a/src/emu/old_trace.c b/src/emu/old_trace.c deleted file mode 100644 index 87e5706..0000000 --- a/src/emu/old_trace.c +++ /dev/null @@ -1,686 +0,0 @@ -/* Copyright (c) 2021-2022 Barcelona Supercomputing Center (BSC) - * SPDX-License-Identifier: GPL-3.0-or-later */ - -#include "trace.h" - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int -find_dir_prefix_str(const char *dirname, const char *prefix, const char **str) -{ - const char *p = dirname; - - /* Check the prefix */ - if (strncmp(p, prefix, strlen(prefix)) != 0) - return -1; - - p += strlen(prefix); - - /* Find the dot */ - if (*p != '.') - return -1; - - p++; - - if (str) - *str = p; - - return 0; -} - -static int -find_dir_prefix_int(const char *dirname, const char *prefix, int *num) -{ - const char *p = NULL; - - if (find_dir_prefix_str(dirname, prefix, &p) != 0) - return -1; - - /* Convert the suffix string to a number */ - *num = atoi(p); - - return 0; -} - -static size_t -count_dir_prefix(DIR *dir, const char *prefix) -{ - struct dirent *dirent; - size_t n = 0; - - while ((dirent = readdir(dir)) != NULL) { - if (find_dir_prefix_str(dirent->d_name, prefix, NULL) != 0) - continue; - - n++; - } - - return n; -} - -static int -load_thread(struct ovni_ethread *thread, struct ovni_eproc *proc, int index, int tid, char *filepath) -{ - static int total_threads = 0; - - thread->tid = tid; - thread->index = index; - thread->gindex = total_threads++; - thread->state = TH_ST_UNKNOWN; - thread->proc = proc; - - if (strlen(filepath) >= PATH_MAX) { - err("filepath too large: %s\n", filepath); - return -1; - } - - strcpy(thread->tracefile, filepath); - - return 0; -} - -static void -load_proc_metadata(struct ovni_eproc *proc, int *rank_enabled) -{ - JSON_Object *meta = json_value_get_object(proc->meta); - if (meta == NULL) - die("load_proc_metadata: json_value_get_object() failed\n"); - - JSON_Value *appid_val = json_object_get_value(meta, "app_id"); - if (appid_val == NULL) - die("process %d is missing app_id in metadata\n", proc->pid); - - proc->appid = (int) json_number(appid_val); - - JSON_Value *rank_val = json_object_get_value(meta, "rank"); - - if (rank_val != NULL) { - proc->rank = (int) json_number(rank_val); - *rank_enabled = 1; - } else { - proc->rank = -1; - } -} - -static void -check_metadata_version(struct ovni_eproc *proc) -{ - JSON_Object *meta = json_value_get_object(proc->meta); - if (meta == NULL) - die("check_metadata_version: json_value_get_object() failed\n"); - - JSON_Value *version_val = json_object_get_value(meta, "version"); - if (version_val == NULL) { - die("process %d is missing attribute \"version\" in metadata\n", - proc->pid); - } - - int version = (int) json_number(version_val); - - if (version != OVNI_METADATA_VERSION) { - die("pid %d: metadata version mismatch %d (expected %d)\n", - proc->pid, version, - OVNI_METADATA_VERSION); - } - - JSON_Value *mversion_val = json_object_get_value(meta, "model_version"); - if (mversion_val == NULL) { - die("process %d is missing attribute \"model_version\" in metadata\n", - proc->pid); - } - - const char *mversion = json_string(mversion_val); - - if (strcmp(mversion, OVNI_MODEL_VERSION) != 0) { - die("pid %d: metadata model version mismatch '%s' (expected '%s')\n", - proc->pid, mversion, - OVNI_MODEL_VERSION); - } -} - -static int -compare_int(const void *a, const void *b) -{ - int aa = *(const int *) a; - int bb = *(const int *) b; - - if (aa < bb) - return -1; - else if (aa > bb) - return +1; - else - return 0; -} - -static void -check_metadata_version(struct ovni_eproc *proc) -{ - JSON_Object *meta = json_value_get_object(proc->meta); - if (meta == NULL) - die("check_metadata_version: json_value_get_object() failed\n"); - - JSON_Value *version_val = json_object_get_value(meta, "version"); - if (version_val == NULL) { - die("process %d is missing attribute \"version\" in metadata\n", - proc->pid); - } - - int version = (int) json_number(version_val); - - if (version != OVNI_METADATA_VERSION) { - die("pid %d: metadata version mismatch %d (expected %d)\n", - proc->pid, version, - OVNI_METADATA_VERSION); - } - - JSON_Value *mversion_val = json_object_get_value(meta, "model_version"); - if (mversion_val == NULL) { - die("process %d is missing attribute \"model_version\" in metadata\n", - proc->pid); - } - - const char *mversion = json_string(mversion_val); - - if (strcmp(mversion, OVNI_MODEL_VERSION) != 0) { - die("pid %d: metadata model version mismatch '%s' (expected '%s')\n", - proc->pid, mversion, - OVNI_MODEL_VERSION); - } -} - -static int -load_proc(struct ovni_eproc *proc, struct ovni_loom *loom, int index, int pid, char *procdir) -{ - static int total_procs = 0; - - proc->pid = pid; - proc->index = index; - proc->gindex = total_procs++; - proc->loom = loom; - - char path[PATH_MAX]; - if (snprintf(path, PATH_MAX, "%s/%s", procdir, "metadata.json") >= PATH_MAX) { - err("snprintf: path too large: %s\n", procdir); - abort(); - } - - proc->meta = json_parse_file_with_comments(path); - if (proc->meta == NULL) { - err("error loading metadata from %s\n", path); - return -1; - } - - check_metadata_version(proc); - - /* The appid is populated from the metadata */ - load_proc_metadata(proc, &loom->rank_enabled); - - DIR *dir; - if ((dir = opendir(procdir)) == NULL) { - fprintf(stderr, "opendir %s failed: %s\n", - procdir, strerror(errno)); - return -1; - } - - proc->nthreads = count_dir_prefix(dir, "thread"); - - if (proc->nthreads <= 0) { - err("cannot find any thread for process %d\n", - proc->pid); - return -1; - } - - proc->thread = calloc(proc->nthreads, sizeof(struct ovni_ethread)); - - if (proc->thread == NULL) { - perror("calloc failed"); - return -1; - } - - int *tids; - - if ((tids = calloc(proc->nthreads, sizeof(int))) == NULL) { - perror("calloc failed\n"); - return -1; - } - - rewinddir(dir); - - for (size_t i = 0; i < proc->nthreads;) { - struct dirent *dirent = readdir(dir); - - if (dirent == NULL) { - err("inconsistent: readdir returned NULL\n"); - return -1; - } - - if (find_dir_prefix_int(dirent->d_name, "thread", &tids[i]) != 0) - continue; - - i++; - } - - closedir(dir); - - /* Sort threads by ascending TID */ - qsort(tids, proc->nthreads, sizeof(int), compare_int); - - for (size_t i = 0; i < proc->nthreads; i++) { - int tid = tids[i]; - - if (snprintf(path, PATH_MAX, "%s/thread.%d", procdir, tid) >= PATH_MAX) { - err("snprintf: path too large: %s\n", procdir); - abort(); - } - - struct ovni_ethread *thread = &proc->thread[i]; - - if (load_thread(thread, proc, i, tid, path) != 0) - return -1; - } - - free(tids); - - return 0; -} - -static int -load_loom(struct ovni_loom *loom, char *loomdir) -{ - DIR *dir = NULL; - - if ((dir = opendir(loomdir)) == NULL) { - fprintf(stderr, "opendir %s failed: %s\n", - loomdir, strerror(errno)); - return -1; - } - - loom->rank_enabled = 0; - loom->nprocs = count_dir_prefix(dir, "proc"); - - if (loom->nprocs <= 0) { - err("cannot find any process directory in loom %s\n", - loom->hostname); - return -1; - } - - loom->proc = calloc(loom->nprocs, sizeof(struct ovni_eproc)); - - if (loom->proc == NULL) { - perror("calloc failed"); - return -1; - } - - rewinddir(dir); - - size_t i = 0; - struct dirent *dirent = NULL; - while ((dirent = readdir(dir)) != NULL) { - int pid; - if (find_dir_prefix_int(dirent->d_name, "proc", &pid) != 0) - continue; - - if (i >= loom->nprocs) { - err("more process than expected\n"); - abort(); - } - - struct ovni_eproc *proc = &loom->proc[i]; - - if (snprintf(proc->dir, PATH_MAX, "%s/%s", loomdir, dirent->d_name) >= PATH_MAX) { - err("error: process dir name %s too long\n", dirent->d_name); - return -1; - } - - if (load_proc(&loom->proc[i], loom, i, pid, proc->dir) != 0) - return -1; - - i++; - } - - if (i != loom->nprocs) { - err("unexpected number of processes\n"); - abort(); - } - - closedir(dir); - - /* Ensure all process have the rank, if enabled in any */ - if (loom->rank_enabled) { - for (i = 0; i < loom->nprocs; i++) { - struct ovni_eproc *proc = &loom->proc[i]; - if (proc->rank < 0) { - die("process %d is missing the rank\n", - proc->pid); - } - } - } - - return 0; -} - -static int -compare_looms(const void *a, const void *b) -{ - struct ovni_loom *la = (struct ovni_loom *) a; - struct ovni_loom *lb = (struct ovni_loom *) b; - return strcmp(la->dname, lb->dname); -} - -static void -loom_to_host(const char *loom_name, char *host, int n) -{ - int i = 0; - for (i = 0; i < n; i++) { - /* Copy until dot or end */ - if (loom_name[i] != '.' && loom_name[i] != '\0') - host[i] = loom_name[i]; - else - break; - } - - if (i == n) - die("loom host name %s too long\n", loom_name); - - host[i] = '\0'; -} - -int -ovni_load_trace(struct ovni_trace *trace, char *tracedir) -{ - DIR *dir = NULL; - - if ((dir = opendir(tracedir)) == NULL) { - err("opendir %s failed: %s\n", tracedir, strerror(errno)); - return -1; - } - - trace->nlooms = count_dir_prefix(dir, "loom"); - - if (trace->nlooms == 0) { - err("cannot find any loom in %s\n", tracedir); - return -1; - } - - trace->loom = calloc(trace->nlooms, sizeof(struct ovni_loom)); - - if (trace->loom == NULL) { - perror("calloc failed\n"); - return -1; - } - - rewinddir(dir); - - size_t l = 0; - struct dirent *dirent = NULL; - - while ((dirent = readdir(dir)) != NULL) { - struct ovni_loom *loom = &trace->loom[l]; - const char *loom_name; - if (find_dir_prefix_str(dirent->d_name, "loom", &loom_name) != 0) { - /* Ignore other files in tracedir */ - continue; - } - - if (l >= trace->nlooms) { - err("extra loom detected\n"); - return -1; - } - - /* Copy the complete loom directory name to looms */ - if (snprintf(loom->dname, PATH_MAX, "%s", dirent->d_name) >= PATH_MAX) { - err("error: loom name %s too long\n", dirent->d_name); - return -1; - } - - l++; - } - - closedir(dir); - - /* Sort the looms, so we get the hostnames in alphanumeric order */ - qsort(trace->loom, trace->nlooms, sizeof(struct ovni_loom), - compare_looms); - - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - const char *name = NULL; - - if (find_dir_prefix_str(loom->dname, "loom", &name) != 0) { - err("error: mismatch for loom %s\n", loom->dname); - return -1; - } - - loom_to_host(name, loom->hostname, sizeof(loom->hostname)); - - if (snprintf(loom->path, PATH_MAX, "%s/%s", - tracedir, loom->dname) - >= PATH_MAX) { - err("error: loom path %s/%s too long\n", - tracedir, loom->dname); - return -1; - } - - if (load_loom(loom, loom->path) != 0) - return -1; - } - - return 0; -} - -static int -check_stream_header(struct ovni_stream *stream) -{ - int ret = 0; - - if (stream->size < sizeof(struct ovni_stream_header)) { - err("stream %d: incomplete stream header\n", - stream->tid); - return -1; - } - - struct ovni_stream_header *h = - (struct ovni_stream_header *) stream->buf; - - if (memcmp(h->magic, OVNI_STREAM_MAGIC, 4) != 0) { - char magic[5]; - memcpy(magic, h->magic, 4); - magic[4] = '\0'; - err("stream %d: wrong stream magic '%s' (expected '%s')\n", - stream->tid, magic, OVNI_STREAM_MAGIC); - ret = -1; - } - - if (h->version != OVNI_STREAM_VERSION) { - err("stream %d: stream version mismatch %u (expected %u)\n", - stream->tid, h->version, OVNI_STREAM_VERSION); - ret = -1; - } - - return ret; -} - -static int -load_stream_fd(struct ovni_stream *stream, int fd) -{ - struct stat st; - if (fstat(fd, &st) < 0) { - perror("fstat failed"); - return -1; - } - - /* Error because it doesn't have the header */ - if (st.st_size == 0) { - err("stream %d is empty\n", stream->tid); - return -1; - } - - int prot = PROT_READ | PROT_WRITE; - stream->buf = mmap(NULL, st.st_size, prot, MAP_PRIVATE, fd, 0); - - if (stream->buf == MAP_FAILED) { - perror("mmap failed"); - return -1; - } - - stream->size = st.st_size; - - return 0; -} - -static int -load_stream_buf(struct ovni_stream *stream, struct ovni_ethread *thread) -{ - int fd; - - if ((fd = open(thread->tracefile, O_RDWR)) == -1) { - perror("open failed"); - return -1; - } - - if (load_stream_fd(stream, fd) != 0) - return -1; - - if (check_stream_header(stream) != 0) { - err("stream %d: bad header\n", stream->tid); - return -1; - } - - stream->offset = sizeof(struct ovni_stream_header); - - if (stream->offset == stream->size) - stream->active = 0; - else - stream->active = 1; - - /* No need to keep the fd open */ - if (close(fd)) { - perror("close failed"); - return -1; - } - - return 0; -} - -/* Populates the streams in a single array */ -int -ovni_load_streams(struct ovni_trace *trace) -{ - trace->nstreams = 0; - - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - for (size_t j = 0; j < loom->nprocs; j++) { - struct ovni_eproc *proc = &loom->proc[j]; - for (size_t k = 0; k < proc->nthreads; k++) { - trace->nstreams++; - } - } - } - - trace->stream = calloc(trace->nstreams, sizeof(struct ovni_stream)); - - if (trace->stream == NULL) { - perror("calloc failed"); - return -1; - } - - err("loaded %ld streams\n", trace->nstreams); - - size_t s = 0; - for (size_t i = 0; i < trace->nlooms; i++) { - struct ovni_loom *loom = &trace->loom[i]; - for (size_t j = 0; j < loom->nprocs; j++) { - struct ovni_eproc *proc = &loom->proc[j]; - for (size_t k = 0; k < proc->nthreads; k++) { - struct ovni_ethread *thread = &proc->thread[k]; - struct ovni_stream *stream = &trace->stream[s++]; - - stream->tid = thread->tid; - stream->thread = thread; - stream->proc = proc; - stream->loom = loom; - stream->lastclock = 0; - stream->offset = 0; - stream->cur_ev = NULL; - - if (load_stream_buf(stream, thread) != 0) { - err("load_stream_buf failed\n"); - return -1; - } - } - } - } - - return 0; -} - -void -ovni_free_streams(struct ovni_trace *trace) -{ - for (size_t i = 0; i < trace->nstreams; i++) { - struct ovni_stream *stream = &trace->stream[i]; - if (munmap(stream->buf, stream->size) != 0) - die("munmap stream failed: %s\n", strerror(errno)); - } - - free(trace->stream); -} - -void -ovni_free_trace(struct ovni_trace *trace) -{ - for (size_t i = 0; i < trace->nlooms; i++) { - for (size_t j = 0; j < trace->loom[i].nprocs; j++) { - free(trace->loom[i].proc[j].thread); - } - - free(trace->loom[i].proc); - } - - free(trace->loom); -} - -int -ovni_load_next_event(struct ovni_stream *stream) -{ - if (stream->active == 0) { - dbg("stream is inactive, cannot load more events\n"); - return -1; - } - - /* Only step the offset if we have load an event */ - if (stream->cur_ev != NULL) - stream->offset += ovni_ev_size(stream->cur_ev); - - /* It cannot overflow, otherwise we are reading garbage */ - if (stream->offset > stream->size) - die("ovni_load_next_event: stream offset exceeds size\n"); - - /* We have reached the end */ - if (stream->offset == stream->size) { - stream->active = 0; - stream->cur_ev = NULL; - dbg("stream %d runs out of events\n", stream->tid); - return -1; - } - - stream->cur_ev = (struct ovni_ev *) &stream->buf[stream->offset]; - - return 0; -} diff --git a/src/emu/old_trace.h b/src/emu/old_trace.h deleted file mode 100644 index 998a77f..0000000 --- a/src/emu/old_trace.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (c) 2021 Barcelona Supercomputing Center (BSC) - * SPDX-License-Identifier: GPL-3.0-or-later */ - -#ifndef OVNI_TRACE_H -#define OVNI_TRACE_H - -#include "emu.h" -#include "ovni.h" - -int ovni_load_next_event(struct ovni_stream *stream); - -int ovni_load_trace(struct ovni_trace *trace, char *tracedir); - -int ovni_load_streams(struct ovni_trace *trace); - -void ovni_free_streams(struct ovni_trace *trace); - -void ovni_free_trace(struct ovni_trace *trace); - -#endif /* OVNI_TRACE_H */