diff --git a/src/emu/emu_system.c b/src/emu/emu_system.c index bfcc552..b7c223f 100644 --- a/src/emu/emu_system.c +++ b/src/emu/emu_system.c @@ -176,6 +176,21 @@ find_loom(struct emu_system *sys, const char *name) return NULL; } +static void +set_loom_hostname(char host[PATH_MAX], const char loom_name[PATH_MAX]) +{ + /* Copy until dot or end */ + int i; + for (i = 0; i < PATH_MAX - 1; i++) { + if (loom_name[i] == '.' || loom_name[i] == '\0') + break; + + host[i] = loom_name[i]; + } + + host[i] = '\0'; +} + static struct emu_loom * new_loom(const char *tracedir, const char *name) { @@ -193,6 +208,8 @@ new_loom(const char *tracedir, const char *name) if (snprintf(loom->path, PATH_MAX, "%s/%s", tracedir, loom->relpath) >= PATH_MAX) die("new_loom: path too long: %s/%s\n", tracedir, loom->relpath); + set_loom_hostname(loom->hostname, loom->name); + err("new loom '%s'\n", loom->name); return loom; @@ -212,7 +229,7 @@ create_loom(struct emu_system *sys, const char *tracedir, const char *relpath) relpath); return NULL; } - + struct emu_loom *loom = find_loom(sys, name); if (loom == NULL) { @@ -225,7 +242,7 @@ create_loom(struct emu_system *sys, const char *tracedir, const char *relpath) } static int -create_system(struct emu_system *sys, struct emu_trace *trace) +create_lpt(struct emu_system *sys, struct emu_trace *trace) { const char *dir = trace->tracedir; for (struct emu_stream *s = trace->streams; s ; s = s->next) { @@ -237,20 +254,20 @@ create_system(struct emu_system *sys, struct emu_trace *trace) struct emu_loom *loom = create_loom(sys, dir, s->relpath); if (loom == NULL) { - err("create_system: create_loom failed\n"); + err("create_lpt: create_loom failed\n"); return -1; } struct emu_proc *proc = create_proc(loom, dir, s->relpath); if (proc == NULL) { - err("create_system: create_proc failed\n"); + err("create_lpt: create_proc failed\n"); return -1; } /* The thread sets the stream */ struct emu_thread *thread = create_thread(proc, dir, s); if (thread == NULL) { - err("create_system: create_thread failed\n"); + err("create_lpt: create_thread failed\n"); return -1; } } @@ -292,7 +309,7 @@ cmp_loom(struct emu_loom *a, struct emu_loom *b) } static void -sort_system(struct emu_system *sys) +sort_lpt(struct emu_system *sys) { DL_SORT(sys->looms, cmp_loom); @@ -724,30 +741,148 @@ link_streams_to_threads(struct emu_system *sys) emu_stream_data_set(th->stream, th); } -int -emu_system_load(struct emu_system *sys, struct emu_trace *trace) +static int +load_clock_offsets(struct clkoff *clkoff, struct emu_args *args) { - /* Parse the emu_trace and create the looms, procs and threads */ - if (create_system(sys, trace) != 0) { - err("emu_system_load: create system failed\n"); + const char *tracedir = args->tracedir; + char def_file[PATH_MAX]; + char def_name[] = "clock-offsets.txt"; + + clkoff_init(clkoff); + + if (snprintf(def_file, PATH_MAX, "%s/%s", + tracedir, def_name) >= PATH_MAX) { + err("load_clock_offsets: path too long\n"); + return -1; + } + + const char *offset_file = args->clock_offset_file; + int is_optional = 0; + + /* Use the default path if not given */ + if (offset_file == NULL) { + offset_file = def_file; + is_optional = 1; + } + + FILE *f = fopen(offset_file, "r"); + + if (f == NULL) { + if (is_optional) { + return 0; + } + + err("load_clock_offsets: fopen %s failed: %s\n", + offset_file, strerror(errno)); + return -1; + } + + if (clkoff_load(clkoff, f) != 0) { + err("load_clock_offsets: clkoff_load failed\n"); + } + + err("loaded clock offset table from '%s' with %d entries\n", + offset_file, clkoff_count(clkoff)); + + fclose(f); + return 0; +} + +static int +parse_clkoff_entry(struct emu_loom *looms, struct clkoff_entry *entry) +{ + size_t matches = 0; + + /* Use the median as the offset */ + size_t offset = entry->median; + const char *host = entry->name; + + struct emu_loom *loom; + DL_FOREACH(looms, loom) { + /* Match the hostname exactly */ + if (strcmp(loom->hostname, host) != 0) + continue; + + if (loom->clock_offset != 0) { + err("parse_clkoff_entry: loom %s already has a clock offset\n", + loom->name); + return -1; + } + + loom->clock_offset = offset; + matches++; + } + + if (matches == 0) { + err("parse_clkoff_entry: cannot find any loom with hostname '%s'\n", + host); + return -1; + } + + return 0; +} + +static int +init_offsets(struct emu_system *sys) +{ + struct clkoff *table = &sys->clkoff; + int n = clkoff_count(table); + + /* If we have more than one hostname and no offset table has been found, + * we won't be able to synchronize the clocks */ + if (n == 0 && sys->nlooms > 1) { + err("warning: no clock offset file loaded with %ld looms\n", + sys->nlooms); + + if (sys->args->linter_mode) + abort(); + } + + for (int i = 0; i < n; i++) { + struct clkoff_entry *entry = clkoff_get(table, i); + if (parse_clkoff_entry(sys->looms, entry) != 0) { + err("init_offsets: cannot parse clock offset entry %d\n", i); + return -1; + } + } + + /* Set the stream clock offsets too */ + struct emu_thread *thread; + DL_FOREACH2(sys->threads, thread, gnext) { + struct emu_loom *loom = thread->proc->loom; + emu_stream_clkoff(thread->stream, loom->clock_offset); + } + + return 0; +} + +int +emu_system_init(struct emu_system *sys, struct emu_args *args, struct emu_trace *trace) +{ + memset(sys, 0, sizeof(struct emu_system)); + sys->args = args; + + /* Parse the trace and create the looms, procs and threads */ + if (create_lpt(sys, trace) != 0) { + err("emu_system_init: create system failed\n"); return -1; } /* Ensure they are sorted so they are easier to read */ - sort_system(sys); + sort_lpt(sys); - /* Init global lists build after sorting */ + /* Init global lists after sorting */ init_global_lpt_lists(sys); /* Now load all process metadata and set attributes */ if (load_metadata(sys) != 0) { - err("emu_system_load: load_metadata() failed\n"); + err("emu_system_init: load_metadata() failed\n"); return -1; } /* From the metadata extract the CPUs too */ if (init_cpus(sys) != 0) { - err("emu_system_load: load_cpus() failed\n"); + err("emu_system_init: load_cpus() failed\n"); return -1; } @@ -756,13 +891,27 @@ emu_system_load(struct emu_system *sys, struct emu_trace *trace) /* Now that we have loaded all resources, populate the indices */ init_global_indices(sys); + /* Set CPU names like "CPU 1.34" */ if (init_cpu_names(sys) != 0) { - err("emu_system_load: init_cpu_names() failed\n"); + err("emu_system_init: init_cpu_names() failed\n"); return -1; } + /* We need to retrieve the thread from the stream too */ link_streams_to_threads(sys); + /* Load the clock offsets table */ + if (load_clock_offsets(&sys->clkoff, args) != 0) { + err("emu_system_init: load_clock_offsets() failed\n"); + return -1; + } + + /* Set the offsets of the looms and streams */ + if (init_offsets(sys) != 0) { + err("emu_system_init: init_offsets() failed\n"); + return -1; + } + /* Finaly dump the system */ print_system(sys); diff --git a/src/emu/emu_system.h b/src/emu/emu_system.h index 23321ca..2995c00 100644 --- a/src/emu/emu_system.h +++ b/src/emu/emu_system.h @@ -4,9 +4,12 @@ #ifndef EMU_SYSTEM_H #define EMU_SYSTEM_H +#include "emu_args.h" #include "emu_trace.h" +#include "emu_stream.h" #include "parson.h" #include "ovni.h" +#include "clkoff.h" #include #define MAX_CPU_NAME 32 @@ -146,8 +149,7 @@ struct emu_loom { char name[PATH_MAX]; /* Loom directory name */ char path[PATH_MAX]; char relpath[PATH_MAX]; /* Relative to tracedir */ - - char hostname[OVNI_MAX_HOSTNAME]; + char hostname[PATH_MAX]; size_t max_ncpus; size_t max_phyid; @@ -189,10 +191,13 @@ struct emu_system { struct emu_proc *cur_proc; struct emu_thread *cur_thread; + struct clkoff clkoff; + struct emu_args *args; + struct model_ctx ctx; }; -int emu_system_load(struct emu_system *system, struct emu_trace *trace); +int emu_system_init(struct emu_system *sys, struct emu_args *args, struct emu_trace *trace); int model_ctx_set(struct model_ctx *ctx, int model, void *data); int model_ctx_get(struct model_ctx *ctx, int model, void *data);