Add loom and proc

This commit is contained in:
Rodrigo Arias 2023-01-25 18:11:13 +01:00 committed by Rodrigo Arias Mallo
parent f5db3a9814
commit 12bfd3fe26
21 changed files with 1021 additions and 498 deletions

View File

@ -14,10 +14,14 @@ include_directories(
add_library(emu STATIC add_library(emu STATIC
../common.c ../common.c
cpu.c cpu.c
loom.c
proc.c
thread.c thread.c
path.c
metadata.c
emu.c emu.c
emu_system.c #emu_system.c
emu_system_thread.c #emu_system_thread.c
emu_args.c emu_args.c
emu_stream.c emu_stream.c
emu_trace.c emu_trace.c
@ -29,10 +33,10 @@ add_library(emu STATIC
mux.c mux.c
prv.c prv.c
clkoff.c clkoff.c
ovni/probe.c #ovni/probe.c
ovni/create.c #ovni/create.c
ovni/connect.c #ovni/connect.c
ovni/event.c #ovni/event.c
) )
add_subdirectory(ovni) add_subdirectory(ovni)

View File

@ -4,6 +4,7 @@
#include "chan.h" #include "chan.h"
#include "common.h" #include "common.h"
#include <string.h> #include <string.h>
#include <stdarg.h>
void void
chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...) chan_init(struct chan *chan, enum chan_type type, const char *fmt, ...)

View File

@ -8,13 +8,17 @@
#include "utlist.h" #include "utlist.h"
void 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)); memset(cpu, 0, sizeof(struct cpu));
cpu->i = i;
cpu->phyid = phyid; cpu->phyid = phyid;
cpu->is_virtual = is_virtual; }
int
cpu_get_phyid(struct cpu *cpu)
{
return cpu->phyid;
} }
void void
@ -24,17 +28,10 @@ cpu_set_gindex(struct cpu *cpu, int64_t gindex)
} }
void void
cpu_set_name(struct cpu *cpu, int64_t loom) cpu_set_name(struct cpu *cpu, const char *name)
{ {
int n; if (snprintf(cpu->name, PATH_MAX, "%s", name) >= PATH_MAX)
if (cpu->is_virtual) die("cpu name too long");
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");
} }
static struct thread * static struct thread *

View File

@ -6,9 +6,10 @@
struct cpu; struct cpu;
#include "loom.h"
#include "thread.h" #include "thread.h"
#include "chan.h" #include "chan.h"
#include "uthash.h"
#include <linux/limits.h>
struct cpu_chan { struct cpu_chan {
struct chan pid_running; struct chan pid_running;
@ -21,7 +22,7 @@ struct cpu {
char name[PATH_MAX]; char name[PATH_MAX];
/* Logical index: 0 to ncpus - 1 */ /* Logical index: 0 to ncpus - 1 */
int i; //int index;
/* Physical id: as reported by lscpu(1) */ /* Physical id: as reported by lscpu(1) */
int phyid; int phyid;
@ -35,6 +36,10 @@ struct cpu {
int is_virtual; int is_virtual;
/* Loom list sorted by phyid */
struct cpu *lnext;
struct cpu *lprev;
/* Global list */ /* Global list */
struct cpu *next; struct cpu *next;
struct cpu *prev; struct cpu *prev;
@ -43,11 +48,15 @@ struct cpu {
struct cpu_chan chan; struct cpu_chan chan;
//struct model_ctx ctx; //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_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); int cpu_add_thread(struct cpu *cpu, struct thread *thread);
#endif /* CPU_H */ #endif /* CPU_H */

View File

@ -22,39 +22,39 @@ emu_init(struct emu *emu, int argc, char *argv[])
return -1; return -1;
} }
/* Parse the trace and build the emu_system */ // /* Parse the trace and build the emu_system */
if (emu_system_init(&emu->system, &emu->args, &emu->trace) != 0) { // if (emu_system_init(&emu->system, &emu->args, &emu->trace) != 0) {
err("emu_init: cannot init system for trace '%s'\n", // err("emu_init: cannot init system for trace '%s'\n",
emu->args.tracedir); // emu->args.tracedir);
return -1; // return -1;
} // }
//
if (emu_player_init(&emu->player, &emu->trace) != 0) { // if (emu_player_init(&emu->player, &emu->trace) != 0) {
err("emu_init: cannot init player for trace '%s'\n", // err("emu_init: cannot init player for trace '%s'\n",
emu->args.tracedir); // emu->args.tracedir);
return -1; // return -1;
} // }
//
/* Initialize the bay */ // /* Initialize the bay */
bay_init(&emu->bay); // bay_init(&emu->bay);
//
/* Register all the models */ // /* Register all the models */
emu_model_register(&emu->model, &ovni_model_spec, emu); // emu_model_register(&emu->model, &ovni_model_spec, emu);
//
if (ovni_model_spec.probe(emu) != 0) { // if (ovni_model_spec.probe(emu) != 0) {
err("emu_init: ovni probe failed\n"); // err("emu_init: ovni probe failed\n");
return -1; // return -1;
} // }
//
if (ovni_model_spec.create(emu) != 0) { // if (ovni_model_spec.create(emu) != 0) {
err("emu_init: ovni create failed\n"); // err("emu_init: ovni create failed\n");
return -1; // return -1;
} // }
//
if (ovni_model_spec.connect(emu) != 0) { // if (ovni_model_spec.connect(emu) != 0) {
err("emu_init: ovni connect failed\n"); // err("emu_init: ovni connect failed\n");
return -1; // return -1;
} // }
return 0; return 0;
} }
@ -74,17 +74,17 @@ emu_step(struct emu *emu)
return -1; return -1;
} }
emu->ev = emu_player_ev(&emu->player); // emu->ev = emu_player_ev(&emu->player);
emu->stream = emu_player_stream(&emu->player); // emu->stream = emu_player_stream(&emu->player);
emu->thread = emu_system_get_thread(emu->stream); // emu->thread = emu_system_get_thread(emu->stream);
emu->proc = emu->thread->proc; // emu->proc = emu->thread->proc;
emu->loom = emu->proc->loom; // emu->loom = emu->proc->loom;
//
/* Otherwise progress */ // /* Otherwise progress */
if (ovni_model_spec.event(emu) != 0) { // if (ovni_model_spec.event(emu) != 0) {
err("emu_init: ovni event failed\n"); // err("emu_init: ovni event failed\n");
return -1; // return -1;
} // }
return 0; return 0;
} }

View File

@ -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 <stddef.h>
#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 */

View File

@ -3,10 +3,68 @@
#include "loom.h" #include "loom.h"
void #include <string.h>
loom_init(struct loom *loom) #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)); 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 void
@ -15,11 +73,42 @@ loom_set_gindex(struct loom *loom, int64_t gindex)
loom->gindex = gindex; loom->gindex = gindex;
} }
void struct cpu *
loom_set_cpus(struct loom *loom, struct cpu *cpus, size_t ncpus) loom_find_cpu(struct loom *loom, int phyid)
{ {
loom->ncpus = ncpus; if (phyid == -1)
loom->cpu = cpus; 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 void
@ -28,12 +117,65 @@ loom_set_vcpu(struct loom *loom, struct cpu *vcpu)
loom->vcpu = vcpu; loom->vcpu = vcpu;
} }
struct emu_proc * static int
loom_find_proc(struct emu_loom *loom, pid_t pid) cmp_cpus(struct cpu *c1, struct cpu *c2)
{ {
for (struct emu_proc *proc = loom->procs; proc; proc = proc->lnext) { int id1 = cpu_get_phyid(c1);
if (proc->pid == pid) 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; return proc;
} }
return NULL;
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;
}

View File

@ -9,24 +9,30 @@ struct loom;
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <sys/types.h>
struct loom { struct loom {
size_t gindex; size_t gindex;
int is_ready;
char name[PATH_MAX]; /* Loom directory name */ char name[PATH_MAX];
char path[PATH_MAX];
char relpath[PATH_MAX]; /* Relative to tracedir */
char hostname[PATH_MAX]; char hostname[PATH_MAX];
char *id;
size_t max_ncpus; size_t max_ncpus;
size_t max_phyid; size_t max_phyid;
size_t ncpus; size_t ncpus;
size_t offset_ncpus; size_t offset_ncpus;
struct cpu *cpu;
int rank_enabled; int rank_enabled;
int64_t clock_offset; 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 */ /* Virtual CPU */
struct cpu *vcpu; struct cpu *vcpu;
@ -41,6 +47,14 @@ struct loom {
//struct model_ctx ctx; //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 */ #endif /* LOOM_H */

144
src/emu/metadata.c Normal file
View File

@ -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;
}

12
src/emu/metadata.h Normal file
View File

@ -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 */

15
src/emu/path.c Normal file
View File

@ -0,0 +1,15 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "path.h"
#include <string.h>
int
path_has_prefix(const char *path, const char *prefix)
{
if (strncmp(path, prefix, strlen(prefix)) != 0)
return 0;
return 1;
}

9
src/emu/path.h Normal file
View File

@ -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 */

View File

@ -1,67 +1,39 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) /* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */ * SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu_system.h" #include "proc.h"
#include "utlist.h" #include "utlist.h"
#include "path.h"
#include <errno.h> #include <errno.h>
void static const char prefix[] = "proc.";
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 int 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); /* The id must be like "loom.123/proc.345" */
if (meta == NULL) {
err("check_proc_metadata: json_value_get_object() failed: %s\n", const char *p = strchr(id, '/');
path); if (p == NULL) {
err("proc relpath missing '/': %s", id);
return -1; return -1;
} }
JSON_Value *version_val = json_object_get_value(meta, "version"); p++; /* Skip slash */
if (version_val == NULL) { if (strchr(p, '/') != NULL) {
err("check_proc_metadata: missing attribute \"version\": %s\n", err("proc id contains multiple '/': %s", id);
path);
return -1; return -1;
} }
int version = (int) json_number(version_val); /* Ensure the prefix is ok */
if (!path_has_prefix(p, prefix)) {
if (version != OVNI_METADATA_VERSION) { err("proc name must start with '%s': %s", prefix, id);
err("check_proc_metadata: metadata version mismatch %d (expected %d) in %s\n",
version, OVNI_METADATA_VERSION, path);
return -1; return -1;
} }
JSON_Value *mversion_val = json_object_get_value(meta, "model_version"); if (snprintf(proc->id, PATH_MAX, "%s", id) >= PATH_MAX) {
if (mversion_val == NULL) { err("proc id too long: %s", id);
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);
return -1; return -1;
} }
@ -69,44 +41,105 @@ check_proc_metadata(JSON_Value *meta_val, const char *path)
} }
int 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) { memset(proc, 0, sizeof(struct proc));
err("proc_load_metadata: process '%s' already has metadata\n",
proc->id); if (set_id(proc, id) != 0) {
err("cannot set process id");
return -1; return -1;
} }
proc->meta = json_parse_file_with_comments(metadata_file); proc->pid = pid;
if (proc->meta == NULL) {
err("proc_load_metadata: failed to load metadata: %s\n", return 0;
metadata_file); }
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; return -1;
} }
if (check_proc_metadata(proc->meta, path) != 0) { int version = (int) json_number(version_val);
err("load_proc_metadata: invalid metadata: %s\n",
metadata_file); if (version != OVNI_METADATA_VERSION) {
err("metadata version mismatch %d (expected %d)",
version, OVNI_METADATA_VERSION);
return -1; return -1;
} }
/* The appid is populated from the metadata */ JSON_Value *mversion_val = json_object_get_value(meta, "model_version");
if (load_proc_attributes(proc, path) != 0) { if (mversion_val == NULL) {
err("load_proc_metadata: invalid attributes: %s\n", err("missing attribute \"model_version\"");
metadata_file); 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 -1;
} }
return 0; 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 * struct thread *
proc_find_thread(struct proc *proc, pid_t tid) proc_find_thread(struct proc *proc, int tid)
{ {
struct thread *th; struct thread *th;
DL_FOREACH2(proc->threads, th, lnext) { DL_FOREACH2(proc->threads, th, lnext) {
if (t->tid == tid) if (th->tid == tid)
return t; return th;
} }
return NULL; return NULL;
} }
int
proc_get_pid(struct proc *proc)
{
return proc->pid;
}

View File

@ -6,32 +6,24 @@
struct proc; struct proc;
#include "loom.h"
#include "thread.h" #include "thread.h"
#include "parson.h" #include "parson.h"
#include <stddef.h> #include <stddef.h>
struct proc { struct proc {
size_t gindex; size_t gindex;
char id[PATH_MAX];
char name[PATH_MAX]; /* Proc directory name */ int metadata_loaded;
char fullpath[PATH_MAX]; int pid;
char relpath[PATH_MAX];
char *id; /* Points to relpath */
pid_t pid;
int index; int index;
int appid; int appid;
int rank; int rank;
struct loom *loom;
JSON_Value *meta;
int nthreads; int nthreads;
struct thread *threads; struct thread *threads;
/* Local list */ /* Loom list */
struct proc *lnext; struct proc *lnext;
struct proc *lprev; struct proc *lprev;
@ -40,8 +32,12 @@ struct proc {
struct proc *gprev; struct proc *gprev;
//struct model_ctx ctx; //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 */ #endif /* PROC_H */

View File

@ -1,7 +1,7 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC) /* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */ * SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu_system.h" #include "system.h"
#include "utlist.h" #include "utlist.h"
#include <errno.h> #include <errno.h>
@ -14,10 +14,10 @@ has_prefix(const char *path, const char *prefix)
return 1; return 1;
} }
static struct emu_thread * static struct thread *
new_thread(struct emu_proc *proc, const char *tracedir, const char *name, struct emu_stream *stream) 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) if (thread == NULL)
die("calloc failed\n"); die("calloc failed\n");
@ -39,18 +39,18 @@ new_thread(struct emu_proc *proc, const char *tracedir, const char *name, struct
return thread; return thread;
} }
static struct emu_thread * static struct thread *
find_thread(struct emu_proc *proc, const char *name) 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) if (strcmp(t->name, name) == 0)
return t; return t;
} }
return NULL; return NULL;
} }
static struct emu_thread * static struct thread *
create_thread(struct emu_proc *proc, const char *tracedir, struct emu_stream *stream) create_thread(struct proc *proc, const char *tracedir, struct emu_stream *stream)
{ {
char name[PATH_MAX]; char name[PATH_MAX];
if (snprintf(name, PATH_MAX, "%s", stream->relpath) >= 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; return NULL;
} }
struct emu_thread *thread = find_thread(proc, threadname); struct thread *thread = find_thread(proc, threadname);
if (thread != NULL) { if (thread != NULL) {
err("create_thread: thread already exists: %s\n", threadname); 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; return thread;
} }
static struct emu_proc * static struct proc *
new_proc(struct emu_loom *loom, const char *tracedir, const char *name) 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) if (proc == NULL)
die("calloc failed\n"); die("calloc failed\n");
@ -119,18 +119,18 @@ new_proc(struct emu_loom *loom, const char *tracedir, const char *name)
return proc; return proc;
} }
static struct emu_proc * static struct proc *
find_proc(struct emu_loom *loom, const char *name) 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) if (strcmp(proc->name, name) == 0)
return proc; return proc;
} }
return NULL; return NULL;
} }
static struct emu_proc * static struct proc *
create_proc(struct emu_loom *loom, const char *tracedir, const char *relpath) create_proc(struct loom *loom, const char *tracedir, const char *relpath)
{ {
char name[PATH_MAX]; char name[PATH_MAX];
if (snprintf(name, PATH_MAX, "%s", relpath) >= 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; return NULL;
} }
struct emu_proc *proc = find_proc(loom, procname); struct proc *proc = find_proc(loom, procname);
if (proc == NULL) { if (proc == NULL) {
proc = new_proc(loom, tracedir, procname); proc = new_proc(loom, tracedir, procname);
@ -166,11 +166,11 @@ create_proc(struct emu_loom *loom, const char *tracedir, const char *relpath)
return proc; return proc;
} }
static struct emu_loom * static struct loom *
find_loom(struct emu_system *sys, const char *name) find_loom(struct system *sys, const char *id)
{ {
for (struct emu_loom *loom = sys->looms; loom; loom = loom->next) { for (struct loom *loom = sys->looms; loom; loom = loom->next) {
if (strcmp(loom->name, name) == 0) if (strcmp(loom->id, id) == 0)
return loom; return loom;
} }
return NULL; return NULL;
@ -191,14 +191,17 @@ set_loom_hostname(char host[PATH_MAX], const char loom_name[PATH_MAX])
host[i] = '\0'; host[i] = '\0';
} }
static struct emu_loom * static struct loom *
new_loom(const char *tracedir, const char *name) 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) if (loom == NULL)
die("calloc failed\n"); die("calloc failed\n");
if (loom_init_begin(loom, name) != 0)
re
if (snprintf(loom->name, PATH_MAX, "%s", name) >= PATH_MAX) if (snprintf(loom->name, PATH_MAX, "%s", name) >= PATH_MAX)
die("new_loom: name too long: %s\n", name); die("new_loom: name too long: %s\n", name);
@ -215,25 +218,35 @@ new_loom(const char *tracedir, const char *name)
return loom; return loom;
} }
static struct emu_loom * static struct loom *
create_loom(struct emu_system *sys, const char *tracedir, const char *relpath) create_loom(struct system *sys, const char *tracedir, const char *relpath)
{ {
char name[PATH_MAX]; char name[PATH_MAX];
if (snprintf(name, PATH_MAX, "%s", relpath) >= 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; return NULL;
} }
if (strtok(name, "/") == NULL) { if (strtok(name, "/") == NULL) {
err("create_looms: cannot find first '/': %s\n", err("cannot find first '/': %s", relpath);
relpath);
return NULL; return NULL;
} }
struct emu_loom *loom = find_loom(sys, name); struct loom *loom = find_loom(sys, name);
if (loom == NULL) { 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); DL_APPEND(sys->looms, loom);
sys->nlooms++; sys->nlooms++;
} }
@ -242,32 +255,31 @@ create_loom(struct emu_system *sys, const char *tracedir, const char *relpath)
} }
static int 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; const char *dir = trace->tracedir;
for (struct emu_stream *s = trace->streams; s ; s = s->next) { for (struct emu_stream *s = trace->streams; s ; s = s->next) {
if (!has_prefix(s->relpath, "loom")) { if (!loom_matches(s->relpath)) {
err("warning: ignoring unknown steam %s\n", err("warning: ignoring unknown stream %s", s->relpath);
s->relpath);
continue; continue;
} }
struct emu_loom *loom = create_loom(sys, dir, s->relpath); struct loom *loom = create_loom(sys, dir, s->relpath);
if (loom == NULL) { if (loom == NULL) {
err("create_lpt: create_loom failed\n"); err("create_loom failed");
return -1; return -1;
} }
struct emu_proc *proc = create_proc(loom, dir, s->relpath); struct proc *proc = create_proc(loom, dir, s->relpath);
if (proc == NULL) { if (proc == NULL) {
err("create_lpt: create_proc failed\n"); err("create_proc failed");
return -1; return -1;
} }
/* The thread sets the stream */ /* 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) { if (thread == NULL) {
err("create_lpt: create_thread failed\n"); err("create_thread failed");
return -1; return -1;
} }
} }
@ -276,53 +288,53 @@ create_lpt(struct emu_system *sys, struct emu_trace *trace)
} }
static int 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); return strcmp(a->name, b->name);
} }
static void static void
sort_proc(struct emu_proc *proc) sort_proc(struct proc *proc)
{ {
DL_SORT2(proc->threads, cmp_thread, lprev, lnext); DL_SORT2(proc->threads, cmp_thread, lprev, lnext);
} }
static int 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); return strcmp(a->name, b->name);
} }
static void static void
sort_loom(struct emu_loom *loom) sort_loom(struct loom *loom)
{ {
DL_SORT2(loom->procs, cmp_proc, lprev, lnext); 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); sort_proc(p);
} }
static int 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); return strcmp(a->name, b->name);
} }
static void static void
sort_lpt(struct emu_system *sys) sort_lpt(struct system *sys)
{ {
DL_SORT(sys->looms, cmp_loom); 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); sort_loom(l);
} }
static void 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 loom *l = sys->looms; l; l = l->next) {
for (struct emu_proc *p = l->procs; p; p = p->lnext) { for (struct proc *p = l->procs; p; p = p->lnext) {
for (struct emu_thread *t = p->threads; t; t = t->lnext) { for (struct thread *t = p->threads; t; t = t->lnext) {
DL_APPEND2(sys->threads, t, gprev, gnext); DL_APPEND2(sys->threads, t, gprev, gnext);
} }
DL_APPEND2(sys->procs, p, gprev, gnext); DL_APPEND2(sys->procs, p, gprev, gnext);
@ -333,9 +345,9 @@ init_global_lpt_lists(struct emu_system *sys)
} }
static void 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++) { for (size_t i = 0; i < l->ncpus; i++) {
struct cpu *cpu = &l->cpu[i]; struct cpu *cpu = &l->cpu[i];
DL_APPEND2(sys->cpus, cpu, prev, next); DL_APPEND2(sys->cpus, cpu, prev, next);
@ -347,22 +359,22 @@ init_global_cpus_list(struct emu_system *sys)
} }
static void static void
print_system(struct emu_system *sys) print_system(struct system *sys)
{ {
err("content of system:\n"); 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("%s\n", l->name);
err("- gindex %ld\n", l->gindex); err("- gindex %ld\n", l->gindex);
err("- path %s\n", l->path); err("- path %s\n", l->path);
err("- relpath %s\n", l->relpath); err("- relpath %s\n", l->relpath);
err("- processes:\n"); 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(" %s\n", p->name);
err(" - gindex %ld\n", p->gindex); err(" - gindex %ld\n", p->gindex);
err(" - path %s\n", p->path); err(" - path %s\n", p->path);
err(" - relpath %s\n", p->relpath); err(" - relpath %s\n", p->relpath);
err(" - threads:\n"); 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(" %s\n", t->name);
err(" - gindex %ld\n", t->gindex); err(" - gindex %ld\n", t->gindex);
err(" - path %s\n", t->path); err(" - path %s\n", t->path);
@ -387,7 +399,7 @@ print_system(struct emu_system *sys)
} }
static int 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); JSON_Object *meta = json_value_get_object(proc->meta);
if (meta == NULL) { if (meta == NULL) {
@ -458,7 +470,7 @@ check_proc_metadata(JSON_Value *pmeta, const char *path)
} }
static int static int
load_proc_metadata(struct emu_proc *proc) load_proc_metadata(struct proc *proc)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
if (snprintf(path, PATH_MAX, "%s/%s", proc->path, "metadata.json") >= 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 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) { if (load_proc_metadata(p) != 0) {
err("error loading metadata for %s\n", p->relpath); err("error loading metadata for %s\n", p->relpath);
return -1; return -1;
@ -521,27 +533,11 @@ has_cpus_array(JSON_Value *metadata)
} }
static int static int
add_new_cpu(struct emu_loom *loom, int i, int phyid, int ncpus) load_proc_cpus(struct proc *proc)
{
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)
{ {
JSON_Object *meta = json_value_get_object(proc->meta); JSON_Object *meta = json_value_get_object(proc->meta);
if (meta == NULL) { if (meta == NULL) {
err("load_proc_cpus: json_value_get_object() failed\n"); err("json_value_get_object() failed");
return -1; return -1;
} }
@ -549,69 +545,65 @@ load_proc_cpus(struct emu_proc *proc)
/* This process doesn't have the cpu list, but it should */ /* This process doesn't have the cpu list, but it should */
if (cpuarray == NULL) { if (cpuarray == NULL) {
err("load_proc_cpus: json_object_get_array() failed\n"); err("json_object_get_array() failed");
return -1; return -1;
} }
size_t ncpus = json_array_get_count(cpuarray); size_t ncpus = json_array_get_count(cpuarray);
if (ncpus == 0) { if (ncpus == 0) {
err("load_proc_cpus: the 'cpus' array is empty in metadata of %s\n", err("empty cpus array in metadata of %s", proc->id);
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));
return -1; return -1;
} }
struct loom *loom = proc->loom;
for (size_t i = 0; i < ncpus; i++) { for (size_t i = 0; i < ncpus; i++) {
JSON_Object *cpu = json_array_get_object(cpuarray, 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) { if (cpu == NULL) {
err("proc_load_cpus: json_array_get_object() failed for cpu\n"); err("calloc failed:");
return -1; return -1;
} }
int index = (int) json_object_get_number(cpu, "index"); cpu_init(cpu, i, phyid, 0);
int phyid = (int) json_object_get_number(cpu, "phyid"); if (loom_add_cpu(loom, cpu) != 0) {
err("loom_add_cpu() failed");
if (add_new_cpu(loom, index, phyid) != 0) {
err("proc_load_cpus: add_new_cpu() failed\n");
return -1; return -1;
} }
} }
loom_set_cpus(loom, cpus, ncpus);
return 0; return 0;
} }
static int static int
load_loom_cpus(struct emu_loom *loom) load_loom_cpus(struct loom *loom)
{ {
/* The process that contains the CPU list */ /* 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. /* Search for the cpu list in all processes.
* Only one should contain it. */ * 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)) if (!has_cpus_array(p->meta))
continue; continue;
if (proc_cpus != NULL) { 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, proc_cpus->relpath,
p->relpath); p->relpath);
return -1; return -1;
} }
if (load_proc_cpus(p) != 0) { if (load_proc_cpus(p) != 0) {
err("load_loom_cpus: load_proc_cpus failed: %s\n", err("load_proc_cpus failed: %s", p->id);
p->relpath);
return -1; return -1;
} }
@ -639,9 +631,9 @@ load_loom_cpus(struct emu_loom *loom)
/* Obtain CPUs in the metadata files and other data */ /* Obtain CPUs in the metadata files and other data */
static int 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) { if (load_loom_cpus(l) != 0) {
err("init_cpus: load_loom_cpus() failed\n"); err("init_cpus: load_loom_cpus() failed\n");
return -1; return -1;
@ -652,18 +644,18 @@ init_cpus(struct emu_system *sys)
} }
static void static void
init_global_indices(struct emu_system *sys) init_global_indices(struct system *sys)
{ {
size_t iloom = 0; 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++); loom_set_gindex(l, iloom++);
sys->nprocs = 0; 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++; p->gindex = sys->nprocs++;
sys->nthreads = 0; 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++; t->gindex = sys->nprocs++;
sys->ncpus = 0; sys->ncpus = 0;
@ -692,7 +684,7 @@ init_cpu_name(struct cpu *cpu)
} }
static int 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) { for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (init_cpu_name(cpu) != 0) if (init_cpu_name(cpu) != 0)
@ -703,9 +695,9 @@ init_cpu_names(struct emu_system *sys)
} }
static void 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); emu_stream_data_set(th->stream, th);
} }
@ -757,7 +749,7 @@ load_clock_offsets(struct clkoff *clkoff, struct emu_args *args)
} }
static int 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; size_t matches = 0;
@ -765,7 +757,7 @@ parse_clkoff_entry(struct emu_loom *looms, struct clkoff_entry *entry)
size_t offset = entry->median; size_t offset = entry->median;
const char *host = entry->name; const char *host = entry->name;
struct emu_loom *loom; struct loom *loom;
DL_FOREACH(looms, loom) { DL_FOREACH(looms, loom) {
/* Match the hostname exactly */ /* Match the hostname exactly */
if (strcmp(loom->hostname, host) != 0) if (strcmp(loom->hostname, host) != 0)
@ -791,7 +783,7 @@ parse_clkoff_entry(struct emu_loom *looms, struct clkoff_entry *entry)
} }
static int static int
init_offsets(struct emu_system *sys) init_offsets(struct system *sys)
{ {
struct clkoff *table = &sys->clkoff; struct clkoff *table = &sys->clkoff;
int n = clkoff_count(table); int n = clkoff_count(table);
@ -815,9 +807,9 @@ init_offsets(struct emu_system *sys)
} }
/* Set the stream clock offsets too */ /* Set the stream clock offsets too */
struct emu_thread *thread; struct thread *thread;
DL_FOREACH2(sys->threads, thread, gnext) { 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; int64_t offset = loom->clock_offset;
if (emu_stream_clkoff_set(thread->stream, offset) != 0) { if (emu_stream_clkoff_set(thread->stream, offset) != 0) {
err("init_offsets: cannot set clock offset\n"); err("init_offsets: cannot set clock offset\n");
@ -829,63 +821,70 @@ init_offsets(struct emu_system *sys)
} }
int 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; sys->args = args;
/* Parse the trace and create the looms, procs and threads */ /* Parse the trace and create the looms, procs and threads */
if (create_lpt(sys, trace) != 0) { if (create_lpt(sys, trace) != 0) {
err("emu_system_init: create system failed\n"); err("system_init: create system failed\n");
return -1; return -1;
} }
/* Ensure they are sorted so they are easier to read */
sort_lpt(sys);
/* Init global lists after sorting */ /* Create global lists and indices */
init_global_lpt_lists(sys);
/* 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 */ /* Setup names */
if (init_cpus(sys) != 0) {
err("emu_system_init: load_cpus() failed\n");
return -1;
}
init_global_cpus_list(sys);
/* Now that we have loaded all resources, populate the indices */ // /* Ensure they are sorted so they are easier to read */
init_global_indices(sys); // sort_lpt(sys);
//
/* Set CPU names like "CPU 1.34" */ // /* Init global lists after sorting */
if (init_cpu_names(sys) != 0) { // init_global_lpt_lists(sys);
err("emu_system_init: init_cpu_names() failed\n"); //
return -1; // /* Now load all process metadata and set attributes */
} // if (load_metadata(sys) != 0) {
// err("system_init: load_metadata() failed\n");
/* We need to retrieve the thread from the stream too */ // return -1;
link_streams_to_threads(sys); // }
//
/* Load the clock offsets table */ // /* From the metadata extract the CPUs too */
if (load_clock_offsets(&sys->clkoff, args) != 0) { // if (init_cpus(sys) != 0) {
err("emu_system_init: load_clock_offsets() failed\n"); // err("system_init: load_cpus() failed\n");
return -1; // return -1;
} // }
//
/* Set the offsets of the looms and streams */ // init_global_cpus_list(sys);
if (init_offsets(sys) != 0) { //
err("emu_system_init: init_offsets() failed\n"); // /* Now that we have loaded all resources, populate the indices */
return -1; // init_global_indices(sys);
} //
// /* Set CPU names like "CPU 1.34" */
/* Finaly dump the system */ // if (init_cpu_names(sys) != 0) {
print_system(sys); // 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; return 0;
} }

41
src/emu/system.h Normal file
View File

@ -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 <stddef.h>
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 */

View File

@ -19,3 +19,6 @@ unit_test(emu_trace.c)
unit_test(emu.c) unit_test(emu.c)
unit_test(clkoff.c) unit_test(clkoff.c)
unit_test(emu_stream.c) unit_test(emu_stream.c)
unit_test(loom.c)
unit_test(thread.c)
unit_test(proc.c)

98
test/unit/cpu.c Normal file
View File

@ -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;
}

134
test/unit/loom.c Normal file
View File

@ -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;
}

33
test/unit/proc.c Normal file
View File

@ -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;
}

8
test/unit/thread.c Normal file
View File

@ -0,0 +1,8 @@
#include "emu/thread.h"
#include "common.h"
int main(void)
{
return 0;
}