From 12bfd3fe264912ba8f0a9925f34cb21f37855db0 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Date: Wed, 25 Jan 2023 18:11:13 +0100 Subject: [PATCH] Add loom and proc --- src/emu/CMakeLists.txt | 16 +- src/emu/chan.c | 1 + src/emu/cpu.c | 23 +- src/emu/cpu.h | 17 +- src/emu/emu.c | 88 ++++---- src/emu/emu_system.h | 169 --------------- src/emu/loom.c | 168 +++++++++++++-- src/emu/loom.h | 24 ++- src/emu/metadata.c | 144 +++++++++++++ src/emu/metadata.h | 12 ++ src/emu/path.c | 15 ++ src/emu/path.h | 9 + src/emu/proc.c | 161 ++++++++------ src/emu/proc.h | 22 +- src/emu/{emu_system.c => system.c} | 333 ++++++++++++++--------------- src/emu/system.h | 41 ++++ test/unit/CMakeLists.txt | 3 + test/unit/cpu.c | 98 +++++++++ test/unit/loom.c | 134 ++++++++++++ test/unit/proc.c | 33 +++ test/unit/thread.c | 8 + 21 files changed, 1021 insertions(+), 498 deletions(-) delete mode 100644 src/emu/emu_system.h create mode 100644 src/emu/metadata.c create mode 100644 src/emu/metadata.h create mode 100644 src/emu/path.c create mode 100644 src/emu/path.h rename src/emu/{emu_system.c => system.c} (68%) create mode 100644 src/emu/system.h create mode 100644 test/unit/cpu.c create mode 100644 test/unit/loom.c create mode 100644 test/unit/proc.c create mode 100644 test/unit/thread.c diff --git a/src/emu/CMakeLists.txt b/src/emu/CMakeLists.txt index 2dd432f..554906c 100644 --- a/src/emu/CMakeLists.txt +++ b/src/emu/CMakeLists.txt @@ -14,10 +14,14 @@ include_directories( add_library(emu STATIC ../common.c cpu.c + loom.c + proc.c thread.c + path.c + metadata.c emu.c - emu_system.c - emu_system_thread.c + #emu_system.c + #emu_system_thread.c emu_args.c emu_stream.c emu_trace.c @@ -29,10 +33,10 @@ add_library(emu STATIC mux.c prv.c clkoff.c - ovni/probe.c - ovni/create.c - ovni/connect.c - ovni/event.c + #ovni/probe.c + #ovni/create.c + #ovni/connect.c + #ovni/event.c ) add_subdirectory(ovni) diff --git a/src/emu/chan.c b/src/emu/chan.c index 1cca152..20aac46 100644 --- a/src/emu/chan.c +++ b/src/emu/chan.c @@ -4,6 +4,7 @@ #include "chan.h" #include "common.h" #include +#include void chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...) diff --git a/src/emu/cpu.c b/src/emu/cpu.c index 1f22327..7f30a2c 100644 --- a/src/emu/cpu.c +++ b/src/emu/cpu.c @@ -8,13 +8,17 @@ #include "utlist.h" void -cpu_init(struct cpu *cpu, int i, int phyid, int is_virtual) +cpu_init(struct cpu *cpu, int phyid) { memset(cpu, 0, sizeof(struct cpu)); - cpu->i = i; cpu->phyid = phyid; - cpu->is_virtual = is_virtual; +} + +int +cpu_get_phyid(struct cpu *cpu) +{ + return cpu->phyid; } void @@ -24,17 +28,10 @@ cpu_set_gindex(struct cpu *cpu, int64_t gindex) } void -cpu_set_name(struct cpu *cpu, int64_t loom) +cpu_set_name(struct cpu *cpu, const char *name) { - int n; - if (cpu->is_virtual) - n = snprintf(cpu->name, PATH_MAX, "vCPU %ld.*", loom); - else - n = snprintf(cpu->name, PATH_MAX, "CPU %ld.%d", loom, cpu->i); - - /* Unlikely */ - if (n >= PATH_MAX) - die("cpu_set_name: cpu name too long\n"); + if (snprintf(cpu->name, PATH_MAX, "%s", name) >= PATH_MAX) + die("cpu name too long"); } static struct thread * diff --git a/src/emu/cpu.h b/src/emu/cpu.h index 63df1e4..535e278 100644 --- a/src/emu/cpu.h +++ b/src/emu/cpu.h @@ -6,9 +6,10 @@ struct cpu; -#include "loom.h" #include "thread.h" #include "chan.h" +#include "uthash.h" +#include struct cpu_chan { struct chan pid_running; @@ -21,7 +22,7 @@ struct cpu { char name[PATH_MAX]; /* Logical index: 0 to ncpus - 1 */ - int i; + //int index; /* Physical id: as reported by lscpu(1) */ int phyid; @@ -35,6 +36,10 @@ struct cpu { int is_virtual; + /* Loom list sorted by phyid */ + struct cpu *lnext; + struct cpu *lprev; + /* Global list */ struct cpu *next; struct cpu *prev; @@ -43,11 +48,15 @@ struct cpu { struct cpu_chan chan; //struct model_ctx ctx; + + UT_hash_handle hh; /* CPUs in the loom */ }; -void cpu_init(struct cpu *cpu, int i, int phyid, int is_virtual); +void cpu_init(struct cpu *cpu, int phyid); +int cpu_get_phyid(struct cpu *cpu); +//int cpu_get_index(struct cpu *cpu); void cpu_set_gindex(struct cpu *cpu, int64_t gindex); -void cpu_set_name(struct cpu *cpu, int64_t loom); +void cpu_set_name(struct cpu *cpu, const char *name); int cpu_add_thread(struct cpu *cpu, struct thread *thread); #endif /* CPU_H */ diff --git a/src/emu/emu.c b/src/emu/emu.c index aebe2b8..4942c36 100644 --- a/src/emu/emu.c +++ b/src/emu/emu.c @@ -22,39 +22,39 @@ emu_init(struct emu *emu, int argc, char *argv[]) return -1; } - /* Parse the trace and build the emu_system */ - if (emu_system_init(&emu->system, &emu->args, &emu->trace) != 0) { - err("emu_init: cannot init system for trace '%s'\n", - emu->args.tracedir); - return -1; - } - - if (emu_player_init(&emu->player, &emu->trace) != 0) { - err("emu_init: cannot init player for trace '%s'\n", - emu->args.tracedir); - return -1; - } - - /* Initialize the bay */ - bay_init(&emu->bay); - - /* Register all the models */ - emu_model_register(&emu->model, &ovni_model_spec, emu); - - if (ovni_model_spec.probe(emu) != 0) { - err("emu_init: ovni probe failed\n"); - return -1; - } - - if (ovni_model_spec.create(emu) != 0) { - err("emu_init: ovni create failed\n"); - return -1; - } - - if (ovni_model_spec.connect(emu) != 0) { - err("emu_init: ovni connect failed\n"); - return -1; - } +// /* Parse the trace and build the emu_system */ +// if (emu_system_init(&emu->system, &emu->args, &emu->trace) != 0) { +// err("emu_init: cannot init system for trace '%s'\n", +// emu->args.tracedir); +// return -1; +// } +// +// if (emu_player_init(&emu->player, &emu->trace) != 0) { +// err("emu_init: cannot init player for trace '%s'\n", +// emu->args.tracedir); +// return -1; +// } +// +// /* Initialize the bay */ +// bay_init(&emu->bay); +// +// /* Register all the models */ +// emu_model_register(&emu->model, &ovni_model_spec, emu); +// +// if (ovni_model_spec.probe(emu) != 0) { +// err("emu_init: ovni probe failed\n"); +// return -1; +// } +// +// if (ovni_model_spec.create(emu) != 0) { +// err("emu_init: ovni create failed\n"); +// return -1; +// } +// +// if (ovni_model_spec.connect(emu) != 0) { +// err("emu_init: ovni connect failed\n"); +// return -1; +// } return 0; } @@ -74,17 +74,17 @@ emu_step(struct emu *emu) return -1; } - emu->ev = emu_player_ev(&emu->player); - emu->stream = emu_player_stream(&emu->player); - emu->thread = emu_system_get_thread(emu->stream); - emu->proc = emu->thread->proc; - emu->loom = emu->proc->loom; - - /* Otherwise progress */ - if (ovni_model_spec.event(emu) != 0) { - err("emu_init: ovni event failed\n"); - return -1; - } +// emu->ev = emu_player_ev(&emu->player); +// emu->stream = emu_player_stream(&emu->player); +// emu->thread = emu_system_get_thread(emu->stream); +// emu->proc = emu->thread->proc; +// emu->loom = emu->proc->loom; +// +// /* Otherwise progress */ +// if (ovni_model_spec.event(emu) != 0) { +// err("emu_init: ovni event failed\n"); +// return -1; +// } return 0; } diff --git a/src/emu/emu_system.h b/src/emu/emu_system.h deleted file mode 100644 index 4fa5bca..0000000 --- a/src/emu/emu_system.h +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) - * SPDX-License-Identifier: GPL-3.0-or-later */ - -#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 - -struct emu_cpu; -struct emu_thread; -struct emu_proc; -struct emu_loom; -struct emu_system; - -#define MAX_MODELS 256 - -struct model_ctx { - void *data[MAX_MODELS]; -}; - -/* Emulated thread runtime status */ -enum emu_thread_state { - TH_ST_UNKNOWN, - TH_ST_RUNNING, - TH_ST_PAUSED, - TH_ST_DEAD, - TH_ST_COOLING, - TH_ST_WARMING, -}; - -struct emu_thread { - size_t gindex; /* In the system */ - - char name[PATH_MAX]; - char path[PATH_MAX]; - char relpath[PATH_MAX]; - - int tid; - int index; /* In loom */ - - /* The process associated with this thread */ - struct emu_proc *proc; - - enum emu_thread_state state; - int is_running; - int is_active; - - /* Stream linked to this thread */ - struct emu_stream *stream; - - /* Current cpu, NULL if not unique affinity */ - struct emu_cpu *cpu; - - /* Linked list of threads in each CPU */ - struct emu_thread *cpu_prev; - struct emu_thread *cpu_next; - - /* Local list */ - struct emu_thread *lprev; - struct emu_thread *lnext; - - /* Global list */ - struct emu_thread *gnext; - struct emu_thread *gprev; - - struct model_ctx ctx; -}; - -/* State of each emulated process */ -struct emu_proc { - size_t gindex; - - char name[PATH_MAX]; /* Proc directory name */ - char path[PATH_MAX]; - char relpath[PATH_MAX]; - - int pid; - int index; - int appid; - int rank; - - struct emu_loom *loom; - - JSON_Value *meta; - - int nthreads; - struct emu_thread *threads; - - /* Local list */ - struct emu_proc *lnext; - struct emu_proc *lprev; - - /* Global list */ - struct emu_proc *gnext; - struct emu_proc *gprev; - - struct model_ctx ctx; -}; - -struct emu_loom { - size_t gindex; - - char name[PATH_MAX]; /* Loom directory name */ - char path[PATH_MAX]; - char relpath[PATH_MAX]; /* Relative to tracedir */ - char hostname[PATH_MAX]; - - size_t max_ncpus; - size_t max_phyid; - size_t ncpus; - size_t offset_ncpus; - struct emu_cpu *cpu; - int rank_enabled; - - int64_t clock_offset; - - /* Virtual CPU */ - struct emu_cpu *vcpu; - - /* Local list */ - size_t nprocs; - struct emu_proc *procs; - - /* Global list */ - struct emu_loom *next; - struct emu_loom *prev; - - struct model_ctx ctx; -}; - -struct emu_system { - /* Total counters */ - size_t nlooms; - size_t nthreads; - size_t nprocs; - size_t ncpus; /* Physical */ - - struct emu_loom *looms; - struct emu_proc *procs; - struct emu_thread *threads; - struct emu_cpu *cpus; - - /* From current event */ - struct emu_loom *cur_loom; - struct emu_proc *cur_proc; - struct emu_thread *cur_thread; - - struct clkoff clkoff; - struct emu_args *args; - - struct model_ctx ctx; -}; - -int emu_system_init(struct emu_system *sys, struct emu_args *args, struct emu_trace *trace); -struct emu_thread *emu_system_get_thread(struct emu_stream *stream); -struct emu_cpu *emu_system_find_cpu(struct emu_loom *loom, int cpuid); - -int model_ctx_set(struct model_ctx *ctx, int model, void *data); -int model_ctx_get(struct model_ctx *ctx, int model, void *data); - -#endif /* EMU_SYSTEM_H */ diff --git a/src/emu/loom.c b/src/emu/loom.c index 7ebda48..ac135d8 100644 --- a/src/emu/loom.c +++ b/src/emu/loom.c @@ -3,10 +3,68 @@ #include "loom.h" -void -loom_init(struct loom *loom) +#include +#include "cpu.h" +#include "proc.h" +#include "uthash.h" +#include "utlist.h" + +static void +set_hostname(char host[PATH_MAX], const char name[PATH_MAX]) +{ + /* Copy until dot or end */ + int i; + for (i = 0; i < PATH_MAX - 1; i++) { + if (name[i] == '.' || name[i] == '\0') + break; + + host[i] = name[i]; + } + + host[i] = '\0'; +} + +static int +has_prefix(const char *path, const char *prefix) +{ + if (strncmp(path, prefix, strlen(prefix)) != 0) + return 0; + + return 1; +} + +int +loom_matches(const char *path) +{ + return has_prefix(path, "loom."); +} + +int +loom_init_begin(struct loom *loom, const char *name) { memset(loom, 0, sizeof(struct loom)); + + char prefix[] = "loom."; + if (!has_prefix(name, prefix)) { + err("loom name must start with '%s': %s", prefix, name); + return -1; + } + + if (strchr(name, '/') != NULL) { + err("loom name cannot contain '/': %s", name); + return -1; + } + + if (snprintf(loom->name, PATH_MAX, "%s", name) >= PATH_MAX) { + err("name too long: %s\n", name); + return -1; + } + + set_hostname(loom->hostname, loom->name); + loom->id = loom->name; + loom->is_ready = 0; + + return 0; } void @@ -15,11 +73,42 @@ loom_set_gindex(struct loom *loom, int64_t gindex) loom->gindex = gindex; } -void -loom_set_cpus(struct loom *loom, struct cpu *cpus, size_t ncpus) +struct cpu * +loom_find_cpu(struct loom *loom, int phyid) { - loom->ncpus = ncpus; - loom->cpu = cpus; + if (phyid == -1) + return loom->vcpu; + + struct cpu *cpu = NULL; + HASH_FIND_INT(loom->cpus, &phyid, cpu); + return cpu; +} + +int +loom_add_cpu(struct loom *loom, struct cpu *cpu) +{ + int phyid = cpu_get_phyid(cpu); + + if (phyid < 0) { + err("cannot use negative cpu phyid %d", phyid); + return -1; + } + + if (loom_find_cpu(loom, phyid) != NULL) { + err("cpu with phyid %d already in loom", phyid); + return -1; + } + + if (loom->is_ready) { + err("cannot modify CPUs of ready loom"); + return -1; + } + + HASH_ADD_INT(loom->cpus, phyid, cpu); + //DL_SORT2(loom->cpus, cmp_cpus, lprev, lnext); // Maybe? + loom->ncpus++; + + return 0; } void @@ -28,12 +117,65 @@ loom_set_vcpu(struct loom *loom, struct cpu *vcpu) loom->vcpu = vcpu; } -struct emu_proc * -loom_find_proc(struct emu_loom *loom, pid_t pid) +static int +cmp_cpus(struct cpu *c1, struct cpu *c2) { - for (struct emu_proc *proc = loom->procs; proc; proc = proc->lnext) { - if (proc->pid == pid) - return proc; - } - return NULL; + int id1 = cpu_get_phyid(c1); + int id2 = cpu_get_phyid(c2); + + if (id1 < id2) + return -1; + if (id1 > id2) + return +1; + else + return 0; } + +int +loom_init_end(struct loom *loom) +{ + /* Sort CPUs by phyid */ + DL_SORT2(loom->scpus, cmp_cpus, lprev, lnext); + + /* Set rank enabled */ + for (struct proc *p = loom->procs; p; p = p->hh.next) { + if (p->rank >= 0) { + loom->rank_enabled = 1; + break; + } + } + + loom->is_ready = 1; + + return 0; +} + +struct proc * +loom_find_proc(struct loom *loom, int pid) +{ + struct proc *proc = NULL; + HASH_FIND_INT(loom->procs, &pid, proc); + return proc; +} + +int +loom_add_proc(struct loom *loom, struct proc *proc) +{ + int pid = proc_get_pid(proc); + + if (loom_find_proc(loom, pid) != NULL) { + err("proc with pid %d already in loom", pid); + return -1; + } + + if (loom->is_ready) { + err("cannot modify procs of ready loom"); + return -1; + } + + HASH_ADD_INT(loom->procs, pid, proc); + loom->nprocs++; + + return 0; +} + diff --git a/src/emu/loom.h b/src/emu/loom.h index 97cdd7f..2f27577 100644 --- a/src/emu/loom.h +++ b/src/emu/loom.h @@ -9,24 +9,30 @@ struct loom; #include #include #include +#include struct loom { size_t gindex; + int is_ready; - char name[PATH_MAX]; /* Loom directory name */ - char path[PATH_MAX]; - char relpath[PATH_MAX]; /* Relative to tracedir */ + char name[PATH_MAX]; char hostname[PATH_MAX]; + char *id; size_t max_ncpus; size_t max_phyid; size_t ncpus; size_t offset_ncpus; - struct cpu *cpu; int rank_enabled; int64_t clock_offset; + /* Sorted double linked list of CPUs by phyid */ + struct cpu *scpus; + + /* Physical CPUs hash table by phyid */ + struct cpu *cpus; + /* Virtual CPU */ struct cpu *vcpu; @@ -41,6 +47,14 @@ struct loom { //struct model_ctx ctx; }; -void loom_init(struct loom *loom); +int loom_matches(const char *relpath); +int loom_init_begin(struct loom *loom, const char *name); +int loom_init_end(struct loom *loom); +int loom_add_cpu(struct loom *loom, struct cpu *cpu); +void loom_set_gindex(struct loom *loom, int64_t gindex); +struct cpu *loom_find_cpu(struct loom *loom, int phyid); +void loom_set_vcpu(struct loom *loom, struct cpu *vcpu); +struct proc *loom_find_proc(struct loom *loom, pid_t pid); +int loom_add_proc(struct loom *loom, struct proc *proc); #endif /* LOOM_H */ diff --git a/src/emu/metadata.c b/src/emu/metadata.c new file mode 100644 index 0000000..a6244c1 --- /dev/null +++ b/src/emu/metadata.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "metadata.h" + +#include "parson.h" + +static JSON_Object * +load_json(const char *path) +{ + JSON_Value *vmeta = json_parse_file_with_comments(path); + if (vmeta == NULL) { + err("json_parse_file_with_comments() failed"); + return NULL; + } + + JSON_Object *meta = json_value_get_object(vmeta); + if (meta == NULL) { + err("json_value_get_object() failed"); + return NULL; + } + + return 0; +} + +static int +check_version(JSON_Object *meta) +{ + JSON_Value *version_val = json_object_get_value(meta, "version"); + if (version_val == NULL) { + err("missing attribute \"version\""); + return -1; + } + + int version = (int) json_number(version_val); + + if (version != OVNI_METADATA_VERSION) { + err("metadata version mismatch %d (expected %d)", + version, OVNI_METADATA_VERSION); + return -1; + } + + JSON_Value *mversion_val = json_object_get_value(meta, "model_version"); + if (mversion_val == NULL) { + err("missing attribute \"model_version\""); + return -1; + } + + const char *mversion = json_string(mversion_val); + if (strcmp(mversion, OVNI_MODEL_VERSION) != 0) { + err("model version mismatch '%s' (expected '%s')", + mversion, OVNI_MODEL_VERSION); + return -1; + } + + return 0; +} + +static int +has_cpus(JSON_Object *meta) +{ + /* Only check for the "cpus" key, if it has zero elements is an error + * that will be reported later */ + if (json_object_get_array(meta, "cpus") != NULL) + return 1; + + return 0; +} + +static int +load_cpus(struct loom *loom, JSON_Object *meta) +{ + JSON_Array *cpuarray = json_object_get_array(meta, "cpus"); + if (cpuarray == NULL) { + err("cannot find 'cpus' array"); + return -1; + } + + size_t ncpus = json_array_get_count(cpuarray); + if (ncpus == 0) { + err("empty 'cpus' array in metadata"); + return -1; + } + + if (loom->ncpus > 0) { + err("loom %s already has cpus", loom->id); + return -1; + } + + for (size_t i = 0; i < ncpus; i++) { + JSON_Object *jcpu = json_array_get_object(cpuarray, i); + if (jcpu == NULL) { + err("json_array_get_object() failed for cpu"); + return -1; + } + + /* Cast from double */ + //int index = (int) json_object_get_number(jcpu, "index"); + int phyid = (int) json_object_get_number(jcpu, "phyid"); + + struct cpu *cpu = calloc(1, sizeof(struct cpu)); + if (cpu == NULL) { + err("calloc failed:"); + return -1; + } + + cpu_init(cpu, phyid); + + if (loom_add_cpu(loom, cpu) != 0) { + err("loom_add_cpu() failed"); + return -1; + } + } + + return 0; +} + +int +metadata_load(const char *path, struct loom *loom, struct proc *proc) +{ + JSON_Object *meta = load_json(path); + if (meta == NULL) { + err("cannot load metadata from file %s", path); + return -1; + } + + if (check_version(meta) != 0) { + err("version check failed"); + return -1; + } + + /* The appid is populated from the metadata */ + if (proc_load_metadata(proc, meta) != 0) { + err("cannot load process attributes"); + return -1; + } + + if (has_cpus(meta) && load_cpus(loom, meta) != 0) { + err("cannot load loom cpus"); + return -1; + } + + return 0; +} diff --git a/src/emu/metadata.h b/src/emu/metadata.h new file mode 100644 index 0000000..d3e711f --- /dev/null +++ b/src/emu/metadata.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef METADATA_H +#define METADATA_H + +#include "loom.h" +#include "proc.h" + +int metadata_load(const char *path, struct loom *loom, struct proc *proc); + +#endif /* METADATA_H */ diff --git a/src/emu/path.c b/src/emu/path.c new file mode 100644 index 0000000..e9521fa --- /dev/null +++ b/src/emu/path.c @@ -0,0 +1,15 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "path.h" + +#include + +int +path_has_prefix(const char *path, const char *prefix) +{ + if (strncmp(path, prefix, strlen(prefix)) != 0) + return 0; + + return 1; +} diff --git a/src/emu/path.h b/src/emu/path.h new file mode 100644 index 0000000..8530372 --- /dev/null +++ b/src/emu/path.h @@ -0,0 +1,9 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef PATH_H +#define PATH_H + +int path_has_prefix(const char *path, const char *prefix); + +#endif /* PATH_H */ diff --git a/src/emu/proc.c b/src/emu/proc.c index 321faed..93f5246 100644 --- a/src/emu/proc.c +++ b/src/emu/proc.c @@ -1,67 +1,39 @@ /* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "emu_system.h" +#include "proc.h" + #include "utlist.h" +#include "path.h" #include -void -proc_init(struct proc *proc, struct loom *loom, pid_t pid) -{ - memset(proc, 0, sizeof(struct proc)); - - if (snprintf(proc->name, PATH_MAX, "%s", name) >= PATH_MAX) - die("new_proc: name too long: %s\n", name); - - if (snprintf(proc->relpath, PATH_MAX, "%s/%s", loom->name, proc->name) >= PATH_MAX) - die("new_proc: relative path too long: %s/%s", loom->name, proc->name); - - if (snprintf(proc->path, PATH_MAX, "%s/%s", tracedir, proc->relpath) >= PATH_MAX) - die("new_proc: path too long: %s/%s", tracedir, proc->relpath); - - proc->pid = pid; - proc->loom = loom; - proc->id = proc->relpath; - - err("new proc '%s'\n", proc->id); -} +static const char prefix[] = "proc."; static int -check_proc_metadata(JSON_Value *meta_val, const char *path) +set_id(struct proc *proc, const char *id) { - JSON_Object *meta = json_value_get_object(meta_val); - if (meta == NULL) { - err("check_proc_metadata: json_value_get_object() failed: %s\n", - path); + /* The id must be like "loom.123/proc.345" */ + + const char *p = strchr(id, '/'); + if (p == NULL) { + err("proc relpath missing '/': %s", id); return -1; } - JSON_Value *version_val = json_object_get_value(meta, "version"); - if (version_val == NULL) { - err("check_proc_metadata: missing attribute \"version\": %s\n", - path); + p++; /* Skip slash */ + if (strchr(p, '/') != NULL) { + err("proc id contains multiple '/': %s", id); return -1; } - int version = (int) json_number(version_val); - - if (version != OVNI_METADATA_VERSION) { - err("check_proc_metadata: metadata version mismatch %d (expected %d) in %s\n", - version, OVNI_METADATA_VERSION, path); + /* Ensure the prefix is ok */ + if (!path_has_prefix(p, prefix)) { + err("proc name must start with '%s': %s", prefix, id); return -1; } - JSON_Value *mversion_val = json_object_get_value(meta, "model_version"); - if (mversion_val == NULL) { - err("check_proc_metadata: missing attribute \"model_version\" in %s\n", - path); - return -1; - } - - const char *mversion = json_string(mversion_val); - if (strcmp(mversion, OVNI_MODEL_VERSION) != 0) { - err("check_proc_metadata: model version mismatch '%s' (expected '%s') in %s\n", - mversion, OVNI_MODEL_VERSION, path); + if (snprintf(proc->id, PATH_MAX, "%s", id) >= PATH_MAX) { + err("proc id too long: %s", id); return -1; } @@ -69,44 +41,105 @@ check_proc_metadata(JSON_Value *meta_val, const char *path) } int -proc_load_metadata(struct emu_proc *proc, char *metadata_file) +proc_init(struct proc *proc, const char *id, int pid) { - if (proc->meta != NULL) { - err("proc_load_metadata: process '%s' already has metadata\n", - proc->id); + memset(proc, 0, sizeof(struct proc)); + + if (set_id(proc, id) != 0) { + err("cannot set process id"); return -1; } - proc->meta = json_parse_file_with_comments(metadata_file); - if (proc->meta == NULL) { - err("proc_load_metadata: failed to load metadata: %s\n", - metadata_file); + proc->pid = pid; + + return 0; +} + +static int +check_metadata_version(JSON_Object *meta) +{ + JSON_Value *version_val = json_object_get_value(meta, "version"); + if (version_val == NULL) { + err("missing attribute \"version\""); return -1; } - if (check_proc_metadata(proc->meta, path) != 0) { - err("load_proc_metadata: invalid metadata: %s\n", - metadata_file); + int version = (int) json_number(version_val); + + if (version != OVNI_METADATA_VERSION) { + err("metadata version mismatch %d (expected %d)", + version, OVNI_METADATA_VERSION); return -1; } - /* The appid is populated from the metadata */ - if (load_proc_attributes(proc, path) != 0) { - err("load_proc_metadata: invalid attributes: %s\n", - metadata_file); + JSON_Value *mversion_val = json_object_get_value(meta, "model_version"); + if (mversion_val == NULL) { + err("missing attribute \"model_version\""); + return -1; + } + + const char *mversion = json_string(mversion_val); + if (strcmp(mversion, OVNI_MODEL_VERSION) != 0) { + err("model version mismatch '%s' (expected '%s')", + mversion, OVNI_MODEL_VERSION); return -1; } return 0; } +static int +load_attributes(struct proc *proc, JSON_Object *meta) +{ + JSON_Value *appid_val = json_object_get_value(meta, "app_id"); + if (appid_val == NULL) { + err("missing attribute 'app_id' in metadata\n"); + return -1; + } + + 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); + else + proc->rank = -1; + + return 0; +} + +int +proc_load_metadata(struct proc *proc, JSON_Object *meta) +{ + if (proc->metadata_loaded) { + err("process %s already loaded metadata", proc->id); + return -1; + } + + if (load_attributes(proc, meta) != 0) { + err("cannot load attributes for process %s", proc->id); + return -1; + } + + proc->metadata_loaded = 1; + + return 0; +} + struct thread * -proc_find_thread(struct proc *proc, pid_t tid) +proc_find_thread(struct proc *proc, int tid) { struct thread *th; DL_FOREACH2(proc->threads, th, lnext) { - if (t->tid == tid) - return t; + if (th->tid == tid) + return th; } return NULL; } + +int +proc_get_pid(struct proc *proc) +{ + return proc->pid; +} diff --git a/src/emu/proc.h b/src/emu/proc.h index 698f6a0..fe85bfa 100644 --- a/src/emu/proc.h +++ b/src/emu/proc.h @@ -6,32 +6,24 @@ struct proc; -#include "loom.h" #include "thread.h" #include "parson.h" #include struct proc { size_t gindex; + char id[PATH_MAX]; - char name[PATH_MAX]; /* Proc directory name */ - char fullpath[PATH_MAX]; - char relpath[PATH_MAX]; - char *id; /* Points to relpath */ - - pid_t pid; + int metadata_loaded; + int pid; int index; int appid; int rank; - struct loom *loom; - - JSON_Value *meta; - int nthreads; struct thread *threads; - /* Local list */ + /* Loom list */ struct proc *lnext; struct proc *lprev; @@ -40,8 +32,12 @@ struct proc { struct proc *gprev; //struct model_ctx ctx; + UT_hash_handle hh; /* procs in the loom */ }; -void proc_init(struct proc *proc); +int proc_init(struct proc *proc, const char *id, int pid); +int proc_get_pid(struct proc *proc); +int proc_load_metadata(struct proc *proc, JSON_Object *meta); +struct thread *proc_find_thread(struct proc *proc, int tid); #endif /* PROC_H */ diff --git a/src/emu/emu_system.c b/src/emu/system.c similarity index 68% rename from src/emu/emu_system.c rename to src/emu/system.c index 5d9cdd4..aa78cbf 100644 --- a/src/emu/emu_system.c +++ b/src/emu/system.c @@ -1,7 +1,7 @@ /* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) * SPDX-License-Identifier: GPL-3.0-or-later */ -#include "emu_system.h" +#include "system.h" #include "utlist.h" #include @@ -14,10 +14,10 @@ has_prefix(const char *path, const char *prefix) return 1; } -static struct emu_thread * -new_thread(struct emu_proc *proc, const char *tracedir, const char *name, struct emu_stream *stream) +static struct thread * +new_thread(struct proc *proc, const char *tracedir, const char *name, struct emu_stream *stream) { - struct emu_thread *thread = calloc(1, sizeof(struct emu_thread)); + struct thread *thread = calloc(1, sizeof(struct thread)); if (thread == NULL) die("calloc failed\n"); @@ -39,18 +39,18 @@ new_thread(struct emu_proc *proc, const char *tracedir, const char *name, struct return thread; } -static struct emu_thread * -find_thread(struct emu_proc *proc, const char *name) +static struct thread * +find_thread(struct proc *proc, const char *name) { - for (struct emu_thread *t = proc->threads; t; t = t->lnext) { + for (struct thread *t = proc->threads; t; t = t->lnext) { if (strcmp(t->name, name) == 0) return t; } return NULL; } -static struct emu_thread * -create_thread(struct emu_proc *proc, const char *tracedir, struct emu_stream *stream) +static struct thread * +create_thread(struct proc *proc, const char *tracedir, struct emu_stream *stream) { char name[PATH_MAX]; if (snprintf(name, PATH_MAX, "%s", stream->relpath) >= PATH_MAX) { @@ -81,7 +81,7 @@ create_thread(struct emu_proc *proc, const char *tracedir, struct emu_stream *st return NULL; } - struct emu_thread *thread = find_thread(proc, threadname); + struct thread *thread = find_thread(proc, threadname); if (thread != NULL) { err("create_thread: thread already exists: %s\n", threadname); @@ -95,10 +95,10 @@ create_thread(struct emu_proc *proc, const char *tracedir, struct emu_stream *st return thread; } -static struct emu_proc * -new_proc(struct emu_loom *loom, const char *tracedir, const char *name) +static struct proc * +new_proc(struct loom *loom, const char *tracedir, const char *name) { - struct emu_proc *proc = calloc(1, sizeof(struct emu_proc)); + struct proc *proc = calloc(1, sizeof(struct proc)); if (proc == NULL) die("calloc failed\n"); @@ -119,18 +119,18 @@ new_proc(struct emu_loom *loom, const char *tracedir, const char *name) return proc; } -static struct emu_proc * -find_proc(struct emu_loom *loom, const char *name) +static struct proc * +find_proc(struct loom *loom, const char *name) { - for (struct emu_proc *proc = loom->procs; proc; proc = proc->lnext) { + for (struct proc *proc = loom->procs; proc; proc = proc->lnext) { if (strcmp(proc->name, name) == 0) return proc; } return NULL; } -static struct emu_proc * -create_proc(struct emu_loom *loom, const char *tracedir, const char *relpath) +static struct proc * +create_proc(struct loom *loom, const char *tracedir, const char *relpath) { char name[PATH_MAX]; if (snprintf(name, PATH_MAX, "%s", relpath) >= PATH_MAX) { @@ -155,7 +155,7 @@ create_proc(struct emu_loom *loom, const char *tracedir, const char *relpath) return NULL; } - struct emu_proc *proc = find_proc(loom, procname); + struct proc *proc = find_proc(loom, procname); if (proc == NULL) { proc = new_proc(loom, tracedir, procname); @@ -166,11 +166,11 @@ create_proc(struct emu_loom *loom, const char *tracedir, const char *relpath) return proc; } -static struct emu_loom * -find_loom(struct emu_system *sys, const char *name) +static struct loom * +find_loom(struct system *sys, const char *id) { - for (struct emu_loom *loom = sys->looms; loom; loom = loom->next) { - if (strcmp(loom->name, name) == 0) + for (struct loom *loom = sys->looms; loom; loom = loom->next) { + if (strcmp(loom->id, id) == 0) return loom; } return NULL; @@ -191,14 +191,17 @@ set_loom_hostname(char host[PATH_MAX], const char loom_name[PATH_MAX]) host[i] = '\0'; } -static struct emu_loom * +static struct loom * new_loom(const char *tracedir, const char *name) { - struct emu_loom *loom = calloc(1, sizeof(struct emu_loom)); + struct loom *loom = calloc(1, sizeof(struct loom)); if (loom == NULL) die("calloc failed\n"); + if (loom_init_begin(loom, name) != 0) + re + if (snprintf(loom->name, PATH_MAX, "%s", name) >= PATH_MAX) die("new_loom: name too long: %s\n", name); @@ -215,25 +218,35 @@ new_loom(const char *tracedir, const char *name) return loom; } -static struct emu_loom * -create_loom(struct emu_system *sys, const char *tracedir, const char *relpath) +static struct loom * +create_loom(struct system *sys, const char *tracedir, const char *relpath) { char name[PATH_MAX]; if (snprintf(name, PATH_MAX, "%s", relpath) >= PATH_MAX) { - err("create_loom: path too long: %s\n", relpath); + err("path too long: %s", relpath); return NULL; } if (strtok(name, "/") == NULL) { - err("create_looms: cannot find first '/': %s\n", - relpath); + err("cannot find first '/': %s", relpath); return NULL; } - struct emu_loom *loom = find_loom(sys, name); + struct loom *loom = find_loom(sys, name); if (loom == NULL) { - loom = new_loom(tracedir, name); + loom = malloc(sizeof(struct loom)); + + if (loom == NULL) { + err("calloc failed:"); + return NULL; + } + + if (loom_init_begin(loom, name) != 0) { + err("loom_init_begin failed"); + return NULL; + } + DL_APPEND(sys->looms, loom); sys->nlooms++; } @@ -242,32 +255,31 @@ create_loom(struct emu_system *sys, const char *tracedir, const char *relpath) } static int -create_lpt(struct emu_system *sys, struct emu_trace *trace) +create_lpt(struct system *sys, struct emu_trace *trace) { const char *dir = trace->tracedir; for (struct emu_stream *s = trace->streams; s ; s = s->next) { - if (!has_prefix(s->relpath, "loom")) { - err("warning: ignoring unknown steam %s\n", - s->relpath); + if (!loom_matches(s->relpath)) { + err("warning: ignoring unknown stream %s", s->relpath); continue; } - struct emu_loom *loom = create_loom(sys, dir, s->relpath); + struct loom *loom = create_loom(sys, dir, s->relpath); if (loom == NULL) { - err("create_lpt: create_loom failed\n"); + err("create_loom failed"); return -1; } - struct emu_proc *proc = create_proc(loom, dir, s->relpath); + struct proc *proc = create_proc(loom, dir, s->relpath); if (proc == NULL) { - err("create_lpt: create_proc failed\n"); + err("create_proc failed"); return -1; } /* The thread sets the stream */ - struct emu_thread *thread = create_thread(proc, dir, s); + struct thread *thread = create_thread(proc, dir, s); if (thread == NULL) { - err("create_lpt: create_thread failed\n"); + err("create_thread failed"); return -1; } } @@ -276,53 +288,53 @@ create_lpt(struct emu_system *sys, struct emu_trace *trace) } static int -cmp_thread(struct emu_thread *a, struct emu_thread *b) +cmp_thread(struct thread *a, struct thread *b) { return strcmp(a->name, b->name); } static void -sort_proc(struct emu_proc *proc) +sort_proc(struct proc *proc) { DL_SORT2(proc->threads, cmp_thread, lprev, lnext); } static int -cmp_proc(struct emu_proc *a, struct emu_proc *b) +cmp_proc(struct proc *a, struct proc *b) { return strcmp(a->name, b->name); } static void -sort_loom(struct emu_loom *loom) +sort_loom(struct loom *loom) { DL_SORT2(loom->procs, cmp_proc, lprev, lnext); - for (struct emu_proc *p = loom->procs; p; p = p->gnext) + for (struct proc *p = loom->procs; p; p = p->gnext) sort_proc(p); } static int -cmp_loom(struct emu_loom *a, struct emu_loom *b) +cmp_loom(struct loom *a, struct loom *b) { return strcmp(a->name, b->name); } static void -sort_lpt(struct emu_system *sys) +sort_lpt(struct system *sys) { DL_SORT(sys->looms, cmp_loom); - for (struct emu_loom *l = sys->looms; l; l = l->next) + for (struct loom *l = sys->looms; l; l = l->next) sort_loom(l); } static void -init_global_lpt_lists(struct emu_system *sys) +init_global_lpt_lists(struct system *sys) { - for (struct emu_loom *l = sys->looms; l; l = l->next) { - for (struct emu_proc *p = l->procs; p; p = p->lnext) { - for (struct emu_thread *t = p->threads; t; t = t->lnext) { + for (struct loom *l = sys->looms; l; l = l->next) { + for (struct proc *p = l->procs; p; p = p->lnext) { + for (struct thread *t = p->threads; t; t = t->lnext) { DL_APPEND2(sys->threads, t, gprev, gnext); } DL_APPEND2(sys->procs, p, gprev, gnext); @@ -333,9 +345,9 @@ init_global_lpt_lists(struct emu_system *sys) } static void -init_global_cpus_list(struct emu_system *sys) +init_global_cpus_list(struct system *sys) { - for (struct emu_loom *l = sys->looms; l; l = l->next) { + for (struct loom *l = sys->looms; l; l = l->next) { for (size_t i = 0; i < l->ncpus; i++) { struct cpu *cpu = &l->cpu[i]; DL_APPEND2(sys->cpus, cpu, prev, next); @@ -347,22 +359,22 @@ init_global_cpus_list(struct emu_system *sys) } static void -print_system(struct emu_system *sys) +print_system(struct system *sys) { err("content of system:\n"); - for (struct emu_loom *l = sys->looms; l; l = l->next) { + for (struct loom *l = sys->looms; l; l = l->next) { err("%s\n", l->name); err("- gindex %ld\n", l->gindex); err("- path %s\n", l->path); err("- relpath %s\n", l->relpath); err("- processes:\n"); - for (struct emu_proc *p = l->procs; p; p = p->lnext) { + for (struct proc *p = l->procs; p; p = p->lnext) { err(" %s\n", p->name); err(" - gindex %ld\n", p->gindex); err(" - path %s\n", p->path); err(" - relpath %s\n", p->relpath); err(" - threads:\n"); - for (struct emu_thread *t = p->threads; t; t = t->lnext) { + for (struct thread *t = p->threads; t; t = t->lnext) { err(" %s\n", t->name); err(" - gindex %ld\n", t->gindex); err(" - path %s\n", t->path); @@ -387,7 +399,7 @@ print_system(struct emu_system *sys) } static int -load_proc_attributes(struct emu_proc *proc, const char *path) +load_proc_attributes(struct proc *proc, const char *path) { JSON_Object *meta = json_value_get_object(proc->meta); if (meta == NULL) { @@ -458,7 +470,7 @@ check_proc_metadata(JSON_Value *pmeta, const char *path) } static int -load_proc_metadata(struct emu_proc *proc) +load_proc_metadata(struct proc *proc) { char path[PATH_MAX]; if (snprintf(path, PATH_MAX, "%s/%s", proc->path, "metadata.json") >= PATH_MAX) { @@ -489,9 +501,9 @@ load_proc_metadata(struct emu_proc *proc) } static int -load_metadata(struct emu_system *sys) +load_metadata(struct system *sys) { - for (struct emu_proc *p = sys->procs; p; p = p->gnext) { + for (struct proc *p = sys->procs; p; p = p->gnext) { if (load_proc_metadata(p) != 0) { err("error loading metadata for %s\n", p->relpath); return -1; @@ -521,27 +533,11 @@ has_cpus_array(JSON_Value *metadata) } static int -add_new_cpu(struct emu_loom *loom, int i, int phyid, int ncpus) -{ - struct cpu *cpu = &loom->cpu[i]; - - if (i < 0 || i >= ncpus) { - err("add_new_cpu: new CPU i=%d out of bounds in %s\n", - i, loom->relpath); - return -1; - } - - cpu_init(cpu, loom, i, phyid, 0); - - return 0; -} - -static int -load_proc_cpus(struct emu_proc *proc) +load_proc_cpus(struct proc *proc) { JSON_Object *meta = json_value_get_object(proc->meta); if (meta == NULL) { - err("load_proc_cpus: json_value_get_object() failed\n"); + err("json_value_get_object() failed"); return -1; } @@ -549,69 +545,65 @@ load_proc_cpus(struct emu_proc *proc) /* This process doesn't have the cpu list, but it should */ if (cpuarray == NULL) { - err("load_proc_cpus: json_object_get_array() failed\n"); + err("json_object_get_array() failed"); return -1; } size_t ncpus = json_array_get_count(cpuarray); if (ncpus == 0) { - err("load_proc_cpus: the 'cpus' array is empty in metadata of %s\n", - proc->relpath); - return -1; - } - - struct emu_loom *loom = proc->loom; - struct cpu *cpus = calloc(ncpus, sizeof(struct cpu)); - - if (loom->cpu == NULL) { - err("load_proc_cpus: calloc failed: %s\n", strerror(errno)); + err("empty cpus array in metadata of %s", proc->id); return -1; } + struct loom *loom = proc->loom; for (size_t i = 0; i < ncpus; i++) { - JSON_Object *cpu = json_array_get_object(cpuarray, i); - - if (cpu == NULL) { - err("proc_load_cpus: json_array_get_object() failed for cpu\n"); + JSON_Object *jcpu = json_array_get_object(cpuarray, i); + if (jcpu == NULL) { + err("json_array_get_object() failed for cpu"); return -1; } - int index = (int) json_object_get_number(cpu, "index"); - int phyid = (int) json_object_get_number(cpu, "phyid"); + /* Cast from double */ + int index = (int) json_object_get_number(jcpu, "index"); + int phyid = (int) json_object_get_number(jcpu, "phyid"); - if (add_new_cpu(loom, index, phyid) != 0) { - err("proc_load_cpus: add_new_cpu() failed\n"); + struct cpu *cpu = calloc(1, sizeof(struct cpu)); + if (cpu == NULL) { + err("calloc failed:"); + return -1; + } + + cpu_init(cpu, i, phyid, 0); + if (loom_add_cpu(loom, cpu) != 0) { + err("loom_add_cpu() failed"); return -1; } } - loom_set_cpus(loom, cpus, ncpus); - return 0; } static int -load_loom_cpus(struct emu_loom *loom) +load_loom_cpus(struct loom *loom) { /* The process that contains the CPU list */ - struct emu_proc *proc_cpus = NULL; + struct proc *proc_cpus = NULL; /* Search for the cpu list in all processes. * Only one should contain it. */ - for (struct emu_proc *p = loom->procs; p; p = p->lnext) { + for (struct proc *p = loom->procs; p; p = p->lnext) { if (!has_cpus_array(p->meta)) continue; if (proc_cpus != NULL) { - err("load_loom_cpus: duplicated cpu list provided in '%s' and '%s'\n", + err("duplicated cpu list provided in '%s' and '%s'", proc_cpus->relpath, p->relpath); return -1; } if (load_proc_cpus(p) != 0) { - err("load_loom_cpus: load_proc_cpus failed: %s\n", - p->relpath); + err("load_proc_cpus failed: %s", p->id); return -1; } @@ -639,9 +631,9 @@ load_loom_cpus(struct emu_loom *loom) /* Obtain CPUs in the metadata files and other data */ static int -init_cpus(struct emu_system *sys) +init_cpus(struct system *sys) { - for (struct emu_loom *l = sys->looms; l; l = l->next) { + for (struct loom *l = sys->looms; l; l = l->next) { if (load_loom_cpus(l) != 0) { err("init_cpus: load_loom_cpus() failed\n"); return -1; @@ -652,18 +644,18 @@ init_cpus(struct emu_system *sys) } static void -init_global_indices(struct emu_system *sys) +init_global_indices(struct system *sys) { size_t iloom = 0; - for (struct emu_loom *l = sys->looms; l; l = l->next) + for (struct loom *l = sys->looms; l; l = l->next) loom_set_gindex(l, iloom++); sys->nprocs = 0; - for (struct emu_proc *p = sys->procs; p; p = p->gnext) + for (struct proc *p = sys->procs; p; p = p->gnext) p->gindex = sys->nprocs++; sys->nthreads = 0; - for (struct emu_thread *t = sys->threads; t; t = t->gnext) + for (struct thread *t = sys->threads; t; t = t->gnext) t->gindex = sys->nprocs++; sys->ncpus = 0; @@ -692,7 +684,7 @@ init_cpu_name(struct cpu *cpu) } static int -init_cpu_names(struct emu_system *sys) +init_cpu_names(struct system *sys) { for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) { if (init_cpu_name(cpu) != 0) @@ -703,9 +695,9 @@ init_cpu_names(struct emu_system *sys) } static void -link_streams_to_threads(struct emu_system *sys) +link_streams_to_threads(struct system *sys) { - for (struct emu_thread *th = sys->threads; th; th = th->gnext) + for (struct thread *th = sys->threads; th; th = th->gnext) emu_stream_data_set(th->stream, th); } @@ -757,7 +749,7 @@ load_clock_offsets(struct clkoff *clkoff, struct emu_args *args) } static int -parse_clkoff_entry(struct emu_loom *looms, struct clkoff_entry *entry) +parse_clkoff_entry(struct loom *looms, struct clkoff_entry *entry) { size_t matches = 0; @@ -765,7 +757,7 @@ parse_clkoff_entry(struct emu_loom *looms, struct clkoff_entry *entry) size_t offset = entry->median; const char *host = entry->name; - struct emu_loom *loom; + struct loom *loom; DL_FOREACH(looms, loom) { /* Match the hostname exactly */ if (strcmp(loom->hostname, host) != 0) @@ -791,7 +783,7 @@ parse_clkoff_entry(struct emu_loom *looms, struct clkoff_entry *entry) } static int -init_offsets(struct emu_system *sys) +init_offsets(struct system *sys) { struct clkoff *table = &sys->clkoff; int n = clkoff_count(table); @@ -815,9 +807,9 @@ init_offsets(struct emu_system *sys) } /* Set the stream clock offsets too */ - struct emu_thread *thread; + struct thread *thread; DL_FOREACH2(sys->threads, thread, gnext) { - struct emu_loom *loom = thread->proc->loom; + struct loom *loom = thread->proc->loom; int64_t offset = loom->clock_offset; if (emu_stream_clkoff_set(thread->stream, offset) != 0) { err("init_offsets: cannot set clock offset\n"); @@ -829,63 +821,70 @@ init_offsets(struct emu_system *sys) } int -emu_system_init(struct emu_system *sys, struct emu_args *args, struct emu_trace *trace) +system_init(struct system *sys, struct emu_args *args, struct emu_trace *trace) { - memset(sys, 0, sizeof(struct emu_system)); + memset(sys, 0, sizeof(struct 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"); + err("system_init: create system failed\n"); return -1; } - /* Ensure they are sorted so they are easier to read */ - sort_lpt(sys); - /* Init global lists after sorting */ - init_global_lpt_lists(sys); + /* Create global lists and indices */ - /* Now load all process metadata and set attributes */ - if (load_metadata(sys) != 0) { - 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_init: load_cpus() failed\n"); - return -1; - } + /* Setup names */ - init_global_cpus_list(sys); - /* 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_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); +// /* Ensure they are sorted so they are easier to read */ +// sort_lpt(sys); +// +// /* Init global lists after sorting */ +// init_global_lpt_lists(sys); +// +// /* Now load all process metadata and set attributes */ +// if (load_metadata(sys) != 0) { +// err("system_init: load_metadata() failed\n"); +// return -1; +// } +// +// /* From the metadata extract the CPUs too */ +// if (init_cpus(sys) != 0) { +// err("system_init: load_cpus() failed\n"); +// return -1; +// } +// +// init_global_cpus_list(sys); +// +// /* 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("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("system_init: load_clock_offsets() failed\n"); +// return -1; +// } +// +// /* Set the offsets of the looms and streams */ +// if (init_offsets(sys) != 0) { +// err("system_init: init_offsets() failed\n"); +// return -1; +// } +// +// /* Finaly dump the system */ +// print_system(sys); return 0; } diff --git a/src/emu/system.h b/src/emu/system.h new file mode 100644 index 0000000..b7e7304 --- /dev/null +++ b/src/emu/system.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) + * SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef EMU_SYSTEM_H +#define EMU_SYSTEM_H + +#include "emu_args.h" +#include "emu_trace.h" +#include "emu_stream.h" +#include "loom.h" +#include "proc.h" +#include "thread.h" +#include "cpu.h" +#include "clkoff.h" +#include + +struct system { + /* Total counters */ + size_t nlooms; + size_t nthreads; + size_t nprocs; + size_t ncpus; /* Physical */ + + struct loom *looms; + struct proc *procs; + struct thread *threads; + struct cpu *cpus; + + struct clkoff clkoff; + struct emu_args *args; + + //struct model_ctx ctx; +}; + +int system_init(struct system *sys, struct emu_args *args, struct emu_trace *trace); +//struct emu_thread *system_get_thread(struct emu_stream *stream); +//struct emu_cpu *system_find_cpu(struct emu_loom *loom, int cpuid); +//int model_ctx_set(struct model_ctx *ctx, int model, void *data); +//int model_ctx_get(struct model_ctx *ctx, int model, void *data); + +#endif /* EMU_SYSTEM_H */ diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 97458a7..c0ad64a 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -19,3 +19,6 @@ unit_test(emu_trace.c) unit_test(emu.c) unit_test(clkoff.c) unit_test(emu_stream.c) +unit_test(loom.c) +unit_test(thread.c) +unit_test(proc.c) diff --git a/test/unit/cpu.c b/test/unit/cpu.c new file mode 100644 index 0000000..56525f8 --- /dev/null +++ b/test/unit/cpu.c @@ -0,0 +1,98 @@ +#include "emu/bay.h" +#include "common.h" + +static void +test_remove(struct bay *bay) +{ + struct chan chan; + chan_init(&chan, CHAN_SINGLE, "removeme"); + + if (bay_register(bay, &chan) != 0) + die("bay_register failed\n"); + + if (bay_find(bay, chan.name) == NULL) + die("bay_find failed\n"); + + if (bay_remove(bay, &chan) != 0) + die("bay_remove failed\n"); + + if (bay_find(bay, chan.name) != NULL) + die("bay_find didn't fail\n"); +} + +static void +test_duplicate(struct bay *bay) +{ + struct chan chan; + chan_init(&chan, CHAN_SINGLE, "dup"); + + if (bay_register(bay, &chan) != 0) + die("bay_register failed\n"); + + if (bay_register(bay, &chan) == 0) + die("bay_register didn't fail\n"); + + if (bay_remove(bay, &chan) != 0) + die("bay_remove failed\n"); +} + +static int +callback(struct chan *chan, void *ptr) +{ + struct value value; + if (chan_read(chan, &value) != 0) + die("callback: chan_read failed\n"); + + if (value.type != VALUE_INT64) + die("callback: unexpected value type\n"); + + int64_t *ival = ptr; + *ival = value.i; + + return 0; +} + +static void +test_callback(struct bay *bay) +{ + struct chan chan; + chan_init(&chan, CHAN_SINGLE, "testchan"); + + if (bay_register(bay, &chan) != 0) + die("bay_register failed\n"); + + int64_t data = 0; + if (bay_add_cb(bay, BAY_CB_DIRTY, &chan, callback, &data) != 0) + die("bay_add_cb failed\n"); + + if (data != 0) + die("data changed after bay_chan_append_cb\n"); + + if (chan_set(&chan, value_int64(1)) != 0) + die("chan_set failed\n"); + + if (data != 0) + die("data changed after chan_set\n"); + + /* Now the callback should modify 'data' */ + if (bay_propagate(bay) != 0) + die("bay_propagate failed\n"); + + if (data != 1) + die("data didn't change after bay_propagate\n"); + + if (bay_remove(bay, &chan) != 0) + die("bay_remove failed\n"); +} + +int main(void) +{ + struct bay bay; + bay_init(&bay); + + test_remove(&bay); + test_duplicate(&bay); + test_callback(&bay); + + return 0; +} diff --git a/test/unit/loom.c b/test/unit/loom.c new file mode 100644 index 0000000..b89c257 --- /dev/null +++ b/test/unit/loom.c @@ -0,0 +1,134 @@ +#include "emu/loom.h" +#include "emu/cpu.h" +#include "emu/proc.h" +#include "common.h" +#include "utlist.h" + +char testloom[] = "loom.0"; +char testproc[] = "loom.0/proc.1"; + +static void +test_bad_name(struct loom *loom) +{ + if (loom_init_begin(loom, "blah") == 0) + die("loom_init_begin didn't fail"); + + if (loom_init_begin(loom, "loom/blah") == 0) + die("loom_init_begin didn't fail"); + + if (loom_init_begin(loom, "loom.123/testloom") == 0) + die("loom_init_begin didn't fail"); + + if (loom_init_begin(loom, "loom.123/") == 0) + die("loom_init_begin didn't fail"); + + if (loom_init_begin(loom, "/loom.123") == 0) + die("loom_init_begin didn't fail"); + + if (loom_init_begin(loom, "./loom.123") == 0) + die("loom_init_begin didn't fail"); + + if (loom_init_begin(loom, "loom.123") != 0) + die("loom_init_begin failed"); + + err("ok"); +} + +static void +test_negative_cpu(struct loom *loom) +{ + if (loom_init_begin(loom, testloom) != 0) + die("loom_init_begin failed"); + + struct cpu cpu; + cpu_init(&cpu, -1); + + if (loom_add_cpu(loom, &cpu) == 0) + die("loom_add_cpu didn't fail"); + + err("ok"); +} + +static void +test_duplicate_cpus(struct loom *loom) +{ + if (loom_init_begin(loom, testloom) != 0) + die("loom_init_begin failed"); + + struct cpu cpu; + cpu_init(&cpu, 123); + if (loom_add_cpu(loom, &cpu) != 0) + die("loom_add_cpu failed"); + + if (loom_add_cpu(loom, &cpu) == 0) + die("loom_add_cpu didn't fail"); + + err("ok"); +} + +static void +test_sort_cpus(struct loom *loom) +{ + int ncpus = 10; + + if (loom_init_begin(loom, testloom) != 0) + die("loom_init_begin failed"); + + for (int i = 0; i < ncpus; i++) { + int phyid = 1000 - i * i; + struct cpu *cpu = malloc(sizeof(struct cpu)); + if (cpu == NULL) + die("malloc failed:"); + + cpu_init(cpu, phyid); + if (loom_add_cpu(loom, cpu) != 0) + die("loom_add_cpu failed"); + } + + if (loom_init_end(loom) != 0) + die("loom_init_end failed"); + + if (loom->ncpus != (size_t) ncpus) + die("ncpus mismatch"); + + struct cpu *cpu = NULL; + int lastphyid = -1; + DL_FOREACH2(loom->scpus, cpu, lnext) { + int phyid = cpu_get_phyid(cpu); + if (lastphyid >= phyid) + die("unsorted scpus"); + lastphyid = phyid; + } + + err("ok"); +} + +static void +test_duplicate_procs(struct loom *loom) +{ + if (loom_init_begin(loom, testloom) != 0) + die("loom_init_begin failed"); + + struct proc proc; + proc_init(&proc, testproc, 1); + if (loom_add_proc(loom, &proc) != 0) + die("loom_add_proc failed"); + + if (loom_add_proc(loom, &proc) == 0) + die("loom_add_proc didn't fail"); + + err("ok"); +} + +int main(void) +{ + struct loom loom; + + test_bad_name(&loom); + test_negative_cpu(&loom); + test_duplicate_cpus(&loom); + test_sort_cpus(&loom); + test_duplicate_procs(&loom); + + return 0; +} diff --git a/test/unit/proc.c b/test/unit/proc.c new file mode 100644 index 0000000..27e0dd4 --- /dev/null +++ b/test/unit/proc.c @@ -0,0 +1,33 @@ +#include "emu/proc.h" +#include "common.h" + +char meta[] = +"{\n" +" \"version\": 1,\n" +" \"model_version\": \"O1 V1 T1 M1 D1 K1 61\",\n" +" \"app_id\": 1,\n" +" \"cpus\": [ 0, 1, 2, 3 ]\n" +//" \"cpus\": [\n" +//" {\n" +//" \"index\": 0,\n" +//" \"phyid\": 0\n" +//" },\n" +//" {\n" +//" \"index\": 1,\n" +//" \"phyid\": 1\n" +//" },\n" +//" {\n" +//" \"index\": 2,\n" +//" \"phyid\": 2\n" +//" },\n" +//" {\n" +//" \"index\": 3,\n" +//" \"phyid\": 3\n" +//" }\n" +//" ]\n" +"}"; + +int main(void) +{ + return 0; +} diff --git a/test/unit/thread.c b/test/unit/thread.c new file mode 100644 index 0000000..482856f --- /dev/null +++ b/test/unit/thread.c @@ -0,0 +1,8 @@ +#include "emu/thread.h" +#include "common.h" + + +int main(void) +{ + return 0; +}