Add emu_system to parse the trace hierarchy
This commit is contained in:
parent
c6a5e3b34d
commit
aafc3471cc
315
src/emu/emu_system.c
Normal file
315
src/emu/emu_system.c
Normal 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
189
src/emu/emu_system.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user