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
../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)

View File

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

View File

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

View File

@ -6,9 +6,10 @@
struct cpu;
#include "loom.h"
#include "thread.h"
#include "chan.h"
#include "uthash.h"
#include <linux/limits.h>
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 */

View File

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

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"
void
loom_init(struct loom *loom)
#include <string.h>
#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)
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;
}
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 <stdint.h>
#include <linux/limits.h>
#include <sys/types.h>
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 */

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)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu_system.h"
#include "proc.h"
#include "utlist.h"
#include "path.h"
#include <errno.h>
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;
}

View File

@ -6,32 +6,24 @@
struct proc;
#include "loom.h"
#include "thread.h"
#include "parson.h"
#include <stddef.h>
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 */

View File

@ -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 <errno.h>
@ -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);
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("proc_load_cpus: json_array_get_object() failed for cpu\n");
err("calloc failed:");
return -1;
}
int index = (int) json_object_get_number(cpu, "index");
int phyid = (int) json_object_get_number(cpu, "phyid");
if (add_new_cpu(loom, index, phyid) != 0) {
err("proc_load_cpus: add_new_cpu() failed\n");
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;
}

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(clkoff.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;
}