Add emu_system to parse the trace hierarchy

This commit is contained in:
Rodrigo Arias 2023-01-17 19:22:46 +01:00 committed by Rodrigo Arias Mallo
parent c6a5e3b34d
commit aafc3471cc
2 changed files with 504 additions and 0 deletions

315
src/emu/emu_system.c Normal file
View File

@ -0,0 +1,315 @@
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
* SPDX-License-Identifier: GPL-3.0-or-later */
#include "emu_system.h"
#include "utlist.h"
static int
has_prefix(const char *path, const char *prefix)
{
if (strncmp(path, prefix, strlen(prefix)) != 0)
return 0;
return 1;
}
static struct emu_thread *
new_thread(struct emu_proc *proc, const char *name, const char *relpath)
{
struct emu_thread *thread = calloc(1, sizeof(struct emu_thread));
if (thread == NULL)
die("calloc failed\n");
if (snprintf(thread->name, PATH_MAX, "%s", name) >= PATH_MAX)
die("new_thread: name too long: %s\n", name);
if (snprintf(thread->relpath, PATH_MAX, "%s", relpath) >= PATH_MAX)
die("new_proc: relative path too long: %s\n", relpath);
thread->proc = proc;
err("new thread '%s'\n", thread->name);
return thread;
}
static struct emu_thread *
find_thread(struct emu_proc *proc, const char *name)
{
for (struct emu_thread *t = proc->threads; t; t = t->lnext) {
if (strcmp(t->name, name) == 0)
return t;
}
return NULL;
}
static int
create_thread(struct emu_proc *proc, const char *relpath)
{
char name[PATH_MAX];
if (snprintf(name, PATH_MAX, "%s", relpath) >= PATH_MAX) {
err("create_thread: path too long: %s\n", relpath);
return -1;
}
if (strtok(name, "/") == NULL) {
err("missing first slash\n");
return -1;
}
if (strtok(NULL, "/") == NULL) {
err("missing second slash\n");
return -1;
}
char *threadname = strtok(NULL, "/");
if (threadname == NULL) {
err("missing thread name\n");
return -1;
}
if (!has_prefix(threadname, "thread")) {
err("warning: ignoring unknown thread stream %s\n",
relpath);
return 0;
}
struct emu_thread *thread = find_thread(proc, threadname);
if (thread == NULL) {
thread = new_thread(proc, threadname, relpath);
DL_APPEND2(proc->threads, thread, lprev, lnext);
proc->nthreads++;
}
return 0;
}
static struct emu_proc *
new_proc(struct emu_loom *loom, const char *name, const char *relpath)
{
struct emu_proc *proc = calloc(1, sizeof(struct emu_proc));
if (proc == NULL)
die("calloc failed\n");
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", relpath) >= PATH_MAX)
die("new_proc: relative path too long: %s\n", relpath);
proc->loom = loom;
err("new proc '%s'\n", proc->name);
return proc;
}
static struct emu_proc *
find_proc(struct emu_loom *loom, const char *name)
{
for (struct emu_proc *proc = loom->procs; proc; proc = proc->lnext) {
if (strcmp(proc->name, name) == 0)
return proc;
}
return NULL;
}
static int
create_proc(struct emu_loom *loom, const char *relpath)
{
char name[PATH_MAX];
if (snprintf(name, PATH_MAX, "%s", relpath) >= PATH_MAX) {
err("create_proc: path too long: %s\n", relpath);
return -1;
}
if (strtok(name, "/") == NULL) {
err("missing first slash\n");
return -1;
}
char *procname = strtok(NULL, "/");
if (procname == NULL) {
err("missing proc name\n");
return -1;
}
if (!has_prefix(procname, "proc")) {
err("warning: ignoring unknown proc stream %s\n",
relpath);
return 0;
}
struct emu_proc *proc = find_proc(loom, procname);
if (proc == NULL) {
proc = new_proc(loom, procname, relpath);
DL_APPEND2(loom->procs, proc, lprev, lnext);
loom->nprocs++;
}
return create_thread(proc, relpath);
}
static struct emu_loom *
find_loom(struct emu_system *sys, const char *name)
{
for (struct emu_loom *loom = sys->looms; loom; loom = loom->next) {
if (strcmp(loom->name, name) == 0)
return loom;
}
return NULL;
}
static struct emu_loom *
new_loom(const char *name, const char *relpath)
{
struct emu_loom *loom = calloc(1, sizeof(struct emu_loom));
if (loom == NULL)
die("calloc failed\n");
if (snprintf(loom->name, PATH_MAX, "%s", name) >= PATH_MAX)
die("new_loom: name too long: %s\n", name);
if (snprintf(loom->relpath, PATH_MAX, "%s", relpath) >= PATH_MAX)
die("new_loom: relative path too long: %s\n", relpath);
err("new loom '%s'\n", loom->name);
return loom;
}
static int
create_loom(struct emu_system *sys, 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);
return -1;
}
if (strtok(name, "/") == NULL) {
err("create_looms: cannot find first '/': %s\n",
relpath);
return -1;
}
struct emu_loom *loom = find_loom(sys, name);
if (loom == NULL) {
loom = new_loom(name, relpath);
DL_APPEND(sys->looms, loom);
sys->nlooms++;
}
return create_proc(loom, relpath);
}
static int
create_system(struct emu_system *sys, struct emu_trace *trace)
{
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);
continue;
}
if (create_loom(sys, s->relpath) != 0) {
err("create loom failed\n");
return -1;
}
}
return 0;
}
static int
cmp_thread(struct emu_thread *a, struct emu_thread *b)
{
return strcmp(a->name, b->name);
}
static void
sort_proc(struct emu_proc *proc)
{
DL_SORT2(proc->threads, cmp_thread, lprev, lnext);
}
static int
cmp_proc(struct emu_proc *a, struct emu_proc *b)
{
return strcmp(a->name, b->name);
}
static void
sort_loom(struct emu_loom *loom)
{
DL_SORT2(loom->procs, cmp_proc, lprev, lnext);
for (struct emu_proc *p = loom->procs; p; p = p->gnext)
sort_proc(p);
}
static int
cmp_loom(struct emu_loom *a, struct emu_loom *b)
{
return strcmp(a->name, b->name);
}
static void
sort_system(struct emu_system *sys)
{
DL_SORT(sys->looms, cmp_loom);
for (struct emu_loom *l = sys->looms; l; l = l->next)
sort_loom(l);
}
static void
populate_global_lists(struct emu_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) {
DL_APPEND2(sys->threads, t, gprev, gnext);
}
DL_APPEND2(sys->procs, p, gprev, gnext);
}
/* Looms are already in emu_system */
}
}
static void
print_system(struct emu_system *sys)
{
err("content of system:\n");
for (struct emu_loom *l = sys->looms; l; l = l->next) {
err("%s\n", l->name);
for (struct emu_proc *p = l->procs; p; p = p->lnext) {
err(" %s\n", p->name);
for (struct emu_thread *t = p->threads; t; t = t->lnext) {
err(" %s\n", t->name);
}
}
}
}
int
emu_system_load(struct emu_system *sys, struct emu_trace *trace)
{
if (create_system(sys, trace) != 0) {
err("emu_system_load: create system failed\n");
return -1;
}
sort_system(sys);
populate_global_lists(sys);
print_system(sys);
return 0;
}

189
src/emu/emu_system.h Normal file
View File

@ -0,0 +1,189 @@
/* 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_trace.h"
#include "parson.h"
#include "ovni.h"
#include <stddef.h>
#define MAX_CPU_NAME 32
struct emu_cpu;
struct emu_thread;
struct emu_proc;
struct emu_loom;
struct emu_system;
enum emu_cpu_state {
CPU_ST_UNKNOWN,
CPU_ST_READY,
};
#define MAX_MODELS 256
struct model_ctx {
void *data[MAX_MODELS];
};
struct emu_cpu {
/* Logical index: 0 to ncpus - 1 */
int i;
/* Physical id: as reported by lscpu(1) */
int phyid;
/* Global index for all CPUs */
int gindex;
enum emu_cpu_state state;
/* The loom of the CPU */
struct emu_loom *loom;
size_t nthreads;
struct emu_thread *thread; /* List of threads assigned to this CPU */
size_t nrunning_threads;
struct emu_thread *th_running; /* One */
size_t nactive_threads;
struct emu_thread *th_active;
/* Is this a virtual CPU? */
int virtual;
/* Global list */
struct emu_cpu *next;
struct emu_cpu *prev;
struct model_ctx ctx;
};
/* 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 {
char name[PATH_MAX];
char relpath[PATH_MAX];
int tid;
int index; /* In loom */
int gindex; /* In emu */
/* The process associated with this thread */
struct emu_proc *proc;
enum emu_thread_state state;
int is_running;
int is_active;
/* 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 {
char name[PATH_MAX]; /* Proc directory name */
char relpath[PATH_MAX];
int pid;
int index;
int gindex;
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 {
char hostname[OVNI_MAX_HOSTNAME];
char name[PATH_MAX]; /* Loom directory name */
char relpath[PATH_MAX]; /* Relative to tracedir */
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 {
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 model_ctx ctx;
};
int emu_system_load(struct emu_system *system, struct emu_trace *trace);
int model_ctx_set(struct model_ctx *ctx, int model, void *data);
int model_ctx_get(struct model_ctx *ctx, int model, void *data);
#endif /* EMU_SYSTEM_H */