Load CPUs in emu_system

This commit is contained in:
Rodrigo Arias 2023-01-19 18:07:53 +01:00 committed by Rodrigo Arias Mallo
parent fb06a3ec32
commit f4e8b0b8a8
2 changed files with 462 additions and 28 deletions

View File

@ -3,6 +3,7 @@
#include "emu_system.h" #include "emu_system.h"
#include "utlist.h" #include "utlist.h"
#include <errno.h>
static int static int
has_prefix(const char *path, const char *prefix) has_prefix(const char *path, const char *prefix)
@ -14,7 +15,7 @@ has_prefix(const char *path, const char *prefix)
} }
static struct emu_thread * static struct emu_thread *
new_thread(struct emu_proc *proc, const char *name, const char *relpath) new_thread(struct emu_proc *proc, const char *tracedir, const char *name, const char *relpath)
{ {
struct emu_thread *thread = calloc(1, sizeof(struct emu_thread)); struct emu_thread *thread = calloc(1, sizeof(struct emu_thread));
@ -24,8 +25,11 @@ new_thread(struct emu_proc *proc, const char *name, const char *relpath)
if (snprintf(thread->name, PATH_MAX, "%s", name) >= PATH_MAX) if (snprintf(thread->name, PATH_MAX, "%s", name) >= PATH_MAX)
die("new_thread: name too long: %s\n", name); die("new_thread: name too long: %s\n", name);
if (snprintf(thread->path, PATH_MAX, "%s/%s", tracedir, relpath) >= PATH_MAX)
die("new_thread: path too long: %s/%s\n", tracedir, relpath);
if (snprintf(thread->relpath, PATH_MAX, "%s", relpath) >= PATH_MAX) if (snprintf(thread->relpath, PATH_MAX, "%s", relpath) >= PATH_MAX)
die("new_proc: relative path too long: %s\n", relpath); die("new_thread: relative path too long: %s\n", relpath);
thread->proc = proc; thread->proc = proc;
@ -45,7 +49,7 @@ find_thread(struct emu_proc *proc, const char *name)
} }
static int static int
create_thread(struct emu_proc *proc, const char *relpath) create_thread(struct emu_proc *proc, 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) {
@ -78,7 +82,7 @@ create_thread(struct emu_proc *proc, const char *relpath)
struct emu_thread *thread = find_thread(proc, threadname); struct emu_thread *thread = find_thread(proc, threadname);
if (thread == NULL) { if (thread == NULL) {
thread = new_thread(proc, threadname, relpath); thread = new_thread(proc, tracedir, threadname, relpath);
DL_APPEND2(proc->threads, thread, lprev, lnext); DL_APPEND2(proc->threads, thread, lprev, lnext);
proc->nthreads++; proc->nthreads++;
} }
@ -87,7 +91,7 @@ create_thread(struct emu_proc *proc, const char *relpath)
} }
static struct emu_proc * static struct emu_proc *
new_proc(struct emu_loom *loom, const char *name, const char *relpath) new_proc(struct emu_loom *loom, const char *tracedir, const char *name)
{ {
struct emu_proc *proc = calloc(1, sizeof(struct emu_proc)); struct emu_proc *proc = calloc(1, sizeof(struct emu_proc));
@ -97,8 +101,11 @@ new_proc(struct emu_loom *loom, const char *name, const char *relpath)
if (snprintf(proc->name, PATH_MAX, "%s", name) >= PATH_MAX) if (snprintf(proc->name, PATH_MAX, "%s", name) >= PATH_MAX)
die("new_proc: name too long: %s\n", name); die("new_proc: name too long: %s\n", name);
if (snprintf(proc->relpath, PATH_MAX, "%s", relpath) >= PATH_MAX) if (snprintf(proc->relpath, PATH_MAX, "%s/%s", loom->name, proc->name) >= PATH_MAX)
die("new_proc: relative path too long: %s\n", relpath); 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->loom = loom; proc->loom = loom;
@ -118,7 +125,7 @@ find_proc(struct emu_loom *loom, const char *name)
} }
static int static int
create_proc(struct emu_loom *loom, const char *relpath) create_proc(struct emu_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) {
@ -146,12 +153,12 @@ create_proc(struct emu_loom *loom, const char *relpath)
struct emu_proc *proc = find_proc(loom, procname); struct emu_proc *proc = find_proc(loom, procname);
if (proc == NULL) { if (proc == NULL) {
proc = new_proc(loom, procname, relpath); proc = new_proc(loom, tracedir, procname);
DL_APPEND2(loom->procs, proc, lprev, lnext); DL_APPEND2(loom->procs, proc, lprev, lnext);
loom->nprocs++; loom->nprocs++;
} }
return create_thread(proc, relpath); return create_thread(proc, tracedir, relpath);
} }
static struct emu_loom * static struct emu_loom *
@ -165,7 +172,7 @@ find_loom(struct emu_system *sys, const char *name)
} }
static struct emu_loom * static struct emu_loom *
new_loom(const char *name, const char *relpath) new_loom(const char *tracedir, const char *name)
{ {
struct emu_loom *loom = calloc(1, sizeof(struct emu_loom)); struct emu_loom *loom = calloc(1, sizeof(struct emu_loom));
@ -175,8 +182,11 @@ new_loom(const char *name, const char *relpath)
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);
if (snprintf(loom->relpath, PATH_MAX, "%s", relpath) >= PATH_MAX) if (snprintf(loom->relpath, PATH_MAX, "%s", name) >= PATH_MAX)
die("new_loom: relative path too long: %s\n", relpath); die("new_loom: relative path too long: %s\n", name);
if (snprintf(loom->path, PATH_MAX, "%s/%s", tracedir, loom->relpath) >= PATH_MAX)
die("new_loom: path too long: %s/%s\n", tracedir, loom->relpath);
err("new loom '%s'\n", loom->name); err("new loom '%s'\n", loom->name);
@ -184,7 +194,7 @@ new_loom(const char *name, const char *relpath)
} }
static int static int
create_loom(struct emu_system *sys, const char *relpath) create_loom(struct emu_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) {
@ -201,12 +211,12 @@ create_loom(struct emu_system *sys, const char *relpath)
struct emu_loom *loom = find_loom(sys, name); struct emu_loom *loom = find_loom(sys, name);
if (loom == NULL) { if (loom == NULL) {
loom = new_loom(name, relpath); loom = new_loom(tracedir, name);
DL_APPEND(sys->looms, loom); DL_APPEND(sys->looms, loom);
sys->nlooms++; sys->nlooms++;
} }
return create_proc(loom, relpath); return create_proc(loom, tracedir, relpath);
} }
static int static int
@ -219,7 +229,7 @@ create_system(struct emu_system *sys, struct emu_trace *trace)
continue; continue;
} }
if (create_loom(sys, s->relpath) != 0) { if (create_loom(sys, trace->tracedir, s->relpath) != 0) {
err("create loom failed\n"); err("create loom failed\n");
return -1; return -1;
} }
@ -271,7 +281,7 @@ sort_system(struct emu_system *sys)
} }
static void static void
populate_global_lists(struct emu_system *sys) init_global_lpt_lists(struct emu_system *sys)
{ {
for (struct emu_loom *l = sys->looms; l; l = l->next) { 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_proc *p = l->procs; p; p = p->lnext) {
@ -280,7 +290,22 @@ populate_global_lists(struct emu_system *sys)
} }
DL_APPEND2(sys->procs, p, gprev, gnext); DL_APPEND2(sys->procs, p, gprev, gnext);
} }
/* Looms are already in emu_system */
/* Looms are already in sys->looms */
}
}
static void
init_global_cpus_list(struct emu_system *sys)
{
for (struct emu_loom *l = sys->looms; l; l = l->next) {
for (size_t i = 0; i < l->ncpus; i++) {
struct emu_cpu *cpu = &l->cpu[i];
DL_APPEND2(sys->cpus, cpu, prev, next);
}
/* Virtual CPU last */
DL_APPEND2(sys->cpus, &l->vcpu, prev, next);
} }
} }
@ -290,25 +315,426 @@ print_system(struct emu_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 emu_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("- 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 emu_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(" - 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 emu_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(" - path %s\n", t->path);
err(" - relpath %s\n", t->relpath);
} }
} }
err("- cpus:\n");
for (size_t i = 0; i < l->ncpus; i++) {
struct emu_cpu *cpu = &l->cpu[i];
err(" %s\n", cpu->name);
err(" - i %d\n", cpu->i);
err(" - phyid %d\n", cpu->phyid);
err(" - gindex %ld\n", cpu->gindex);
} }
struct emu_cpu *cpu = &l->vcpu;
err("- %s\n", cpu->name);
err(" - i %d\n", cpu->i);
err(" - phyid %d\n", cpu->phyid);
err(" - gindex %ld\n", cpu->gindex);
}
}
static int
load_proc_attributes(struct emu_proc *proc, const char *path)
{
JSON_Object *meta = json_value_get_object(proc->meta);
if (meta == NULL) {
err("load_proc_attributes: json_value_get_object() failed\n");
return -1;
}
JSON_Value *appid_val = json_object_get_value(meta, "app_id");
if (appid_val == NULL) {
err("load_proc_attributes: missing app_id in metadata %s\n", path);
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);
proc->loom->rank_enabled = 1;
} else {
proc->rank = -1;
}
return 0;
}
static int
check_proc_metadata(JSON_Value *pmeta, const char *path)
{
JSON_Object *meta = json_value_get_object(pmeta);
if (meta == NULL) {
err("check_proc_metadata: json_value_get_object() failed for %s\n",
path);
return -1;
}
JSON_Value *version_val = json_object_get_value(meta, "version");
if (version_val == NULL) {
err("check_proc_metadata: missing attribute \"version\" in %s\n",
path);
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);
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);
return -1;
}
return 0;
}
static int
load_proc_metadata(struct emu_proc *proc)
{
char path[PATH_MAX];
if (snprintf(path, PATH_MAX, "%s/%s", proc->path, "metadata.json") >= PATH_MAX) {
err("load_proc_metadata: path too large: %s/%s\n",
proc->path, "metadata.json");
return -1;
}
proc->meta = json_parse_file_with_comments(path);
if (proc->meta == NULL) {
err("load_proc_metadata: json_parse_file_with_comments(%s) failed\n",
path);
return -1;
}
if (check_proc_metadata(proc->meta, path) != 0) {
err("load_proc_metadata: invalid metadata\n");
return -1;
}
/* The appid is populated from the metadata */
if (load_proc_attributes(proc, path) != 0) {
err("load_proc_metadata: invalid attributes\n");
return -1;
}
return 0;
}
static int
load_metadata(struct emu_system *sys)
{
for (struct emu_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;
}
}
return 0;
}
static int
has_cpus_array(JSON_Value *metadata)
{
JSON_Object *meta = json_value_get_object(metadata);
if (meta == NULL) {
err("has_cpus: json_value_get_object() failed\n");
return -1;
}
/* Only check for the "cpus" key, if it has zero elements is an error
* that will be reported later */
JSON_Array *cpuarray = json_object_get_array(meta, "cpus");
if (cpuarray != NULL)
return 1;
return 0;
}
static int
add_new_cpu(struct emu_loom *loom, int i, int phyid)
{
struct emu_cpu *cpu = &loom->cpu[i];
if (i < 0 || i >= (int) loom->ncpus) {
err("add_new_cpu: new CPU i=%d out of bounds in %s\n",
i, loom->relpath);
return -1;
}
if (cpu->state != CPU_ST_UNKNOWN) {
die("add_new_cpu: new CPU i=%d in unexpected in %s\n",
i, loom->relpath);
return -1;
}
cpu->state = CPU_ST_READY;
cpu->i = i;
cpu->phyid = phyid;
cpu->loom = loom;
cpu->is_virtual = 0;
return 0;
}
static int
load_proc_cpus(struct emu_proc *proc)
{
JSON_Object *meta = json_value_get_object(proc->meta);
if (meta == NULL) {
err("load_proc_cpus: json_value_get_object() failed\n");
return -1;
}
JSON_Array *cpuarray = json_object_get_array(meta, "cpus");
/* This process doesn't have the cpu list, but it should */
if (cpuarray == NULL) {
err("load_proc_cpus: json_object_get_array() failed\n");
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;
loom->ncpus = ncpus;
loom->cpu = calloc(ncpus, sizeof(struct emu_cpu));
if (loom->cpu == NULL) {
err("load_proc_cpus: calloc failed: %s\n", strerror(errno));
return -1;
}
for (size_t i = 0; i < ncpus; i++) {
JSON_Object *cpu = json_array_get_object(cpuarray, i);
if (cpu == NULL) {
err("proc_load_cpus: json_array_get_object() failed for cpu\n");
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");
return -1;
}
}
return 0;
}
static int
init_virtual_cpu(struct emu_loom *loom)
{
struct emu_cpu *vcpu = &loom->vcpu;
if (vcpu->state != CPU_ST_UNKNOWN) {
err("init_virtual_cpu: unexpected virtual CPU state in %s\n",
loom->relpath);
return -1;
}
vcpu->state = CPU_ST_READY;
vcpu->i = -1;
vcpu->phyid = -1;
vcpu->loom = loom;
vcpu->is_virtual = 1;
return 0;
}
static int
load_loom_cpus(struct emu_loom *loom)
{
/* The process that contains the CPU list */
struct emu_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) {
if (!has_cpus_array(p->meta))
continue;
if (proc_cpus != NULL) {
err("load_loom_cpus: duplicated cpu list provided in '%s' and '%s'\n",
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);
return -1;
}
proc_cpus = p;
}
/* One of the process must have the list of CPUs */
if (proc_cpus == NULL) {
err("load_loom_cpus: no process contains a CPU list for %s\n",
loom->relpath);
return -1;
}
if (loom->ncpus == 0) {
err("load_loom_cpus: no CPUs found in loom %s\n",
loom->relpath);
return -1;
}
return 0;
}
/* Obtain CPUs in the metadata files and other data */
static int
init_cpus(struct emu_system *sys)
{
for (struct emu_loom *l = sys->looms; l; l = l->next) {
if (load_loom_cpus(l) != 0) {
err("init_cpus: load_loom_cpus() failed\n");
return -1;
}
if (init_virtual_cpu(l) != 0) {
err("init_cpus: init_virtual_cpu() failed\n");
return -1;
}
}
return 0;
}
static void
init_global_indices(struct emu_system *sys)
{
size_t iloom = 0;
for (struct emu_loom *l = sys->looms; l; l = l->next)
l->gindex = iloom++;
sys->nprocs = 0;
for (struct emu_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)
t->gindex = sys->nprocs++;
sys->ncpus = 0;
for (struct emu_cpu *c = sys->cpus; c; c = c->next)
c->gindex = sys->ncpus++;
}
static int
init_cpu_name(struct emu_cpu *cpu)
{
size_t i = cpu->loom->gindex;
size_t j = cpu->i;
int n = 0;
if (cpu->is_virtual)
n = snprintf(cpu->name, PATH_MAX, "vCPU %ld.*", i);
else
n = snprintf(cpu->name, PATH_MAX, "CPU %ld.%ld", i, j);
if (n >= PATH_MAX) {
err("init_cpu_name: cpu name too long\n");
return -1;
}
return 0;
}
static int
init_cpu_names(struct emu_system *sys)
{
for (struct emu_cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
if (init_cpu_name(cpu) != 0)
return -1;
}
return 0;
} }
int int
emu_system_load(struct emu_system *sys, struct emu_trace *trace) emu_system_load(struct emu_system *sys, struct emu_trace *trace)
{ {
/* Parse the emu_trace and create the looms, procs and threads */
if (create_system(sys, trace) != 0) { if (create_system(sys, trace) != 0) {
err("emu_system_load: create system failed\n"); err("emu_system_load: create system failed\n");
return -1; return -1;
} }
/* Ensure they are sorted so they are easier to read */
sort_system(sys); sort_system(sys);
populate_global_lists(sys);
/* Init global lists build after sorting */
init_global_lpt_lists(sys);
/* Now load all process metadata and set attributes */
if (load_metadata(sys) != 0) {
err("emu_system_load: load_metadata() failed\n");
return -1;
}
/* From the metadata extract the CPUs too */
if (init_cpus(sys) != 0) {
err("emu_system_load: 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);
if (init_cpu_names(sys) != 0) {
err("emu_system_load: init_cpu_names() failed\n");
return -1;
}
/* Finaly dump the system */
print_system(sys); print_system(sys);
return 0; return 0;

View File

@ -29,15 +29,15 @@ struct model_ctx {
}; };
struct emu_cpu { struct emu_cpu {
size_t gindex; /* In the system */
char name[PATH_MAX];
/* Logical index: 0 to ncpus - 1 */ /* Logical index: 0 to ncpus - 1 */
int i; int i;
/* Physical id: as reported by lscpu(1) */ /* Physical id: as reported by lscpu(1) */
int phyid; int phyid;
/* Global index for all CPUs */
int gindex;
enum emu_cpu_state state; enum emu_cpu_state state;
/* The loom of the CPU */ /* The loom of the CPU */
@ -52,8 +52,7 @@ struct emu_cpu {
size_t nactive_threads; size_t nactive_threads;
struct emu_thread *th_active; struct emu_thread *th_active;
/* Is this a virtual CPU? */ int is_virtual;
int virtual;
/* Global list */ /* Global list */
struct emu_cpu *next; struct emu_cpu *next;
@ -73,12 +72,14 @@ enum emu_thread_state {
}; };
struct emu_thread { struct emu_thread {
size_t gindex; /* In the system */
char name[PATH_MAX]; char name[PATH_MAX];
char path[PATH_MAX];
char relpath[PATH_MAX]; char relpath[PATH_MAX];
int tid; int tid;
int index; /* In loom */ int index; /* In loom */
int gindex; /* In emu */
/* The process associated with this thread */ /* The process associated with this thread */
struct emu_proc *proc; struct emu_proc *proc;
@ -107,12 +108,14 @@ struct emu_thread {
/* State of each emulated process */ /* State of each emulated process */
struct emu_proc { struct emu_proc {
size_t gindex;
char name[PATH_MAX]; /* Proc directory name */ char name[PATH_MAX]; /* Proc directory name */
char path[PATH_MAX];
char relpath[PATH_MAX]; char relpath[PATH_MAX];
int pid; int pid;
int index; int index;
int gindex;
int appid; int appid;
int rank; int rank;
@ -135,10 +138,14 @@ struct emu_proc {
}; };
struct emu_loom { struct emu_loom {
char hostname[OVNI_MAX_HOSTNAME]; size_t gindex;
char name[PATH_MAX]; /* Loom directory name */ char name[PATH_MAX]; /* Loom directory name */
char path[PATH_MAX];
char relpath[PATH_MAX]; /* Relative to tracedir */ char relpath[PATH_MAX]; /* Relative to tracedir */
char hostname[OVNI_MAX_HOSTNAME];
size_t max_ncpus; size_t max_ncpus;
size_t max_phyid; size_t max_phyid;
size_t ncpus; size_t ncpus;
@ -163,6 +170,7 @@ struct emu_loom {
}; };
struct emu_system { struct emu_system {
/* Total counters */
size_t nlooms; size_t nlooms;
size_t nthreads; size_t nthreads;
size_t nprocs; size_t nprocs;