Add loom and proc
This commit is contained in:
		
							parent
							
								
									f5db3a9814
								
							
						
					
					
						commit
						12bfd3fe26
					
				| @ -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) | ||||
|  | ||||
| @ -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, ...) | ||||
|  | ||||
| @ -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 * | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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 */ | ||||
							
								
								
									
										168
									
								
								src/emu/loom.c
									
									
									
									
									
								
							
							
						
						
									
										168
									
								
								src/emu/loom.c
									
									
									
									
									
								
							| @ -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) | ||||
| 			return proc; | ||||
| 	} | ||||
| 	return NULL; | ||||
| 	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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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
									
								
							
							
						
						
									
										144
									
								
								src/emu/metadata.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										12
									
								
								src/emu/metadata.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										15
									
								
								src/emu/path.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										9
									
								
								src/emu/path.h
									
									
									
									
									
										Normal 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 */ | ||||
							
								
								
									
										161
									
								
								src/emu/proc.c
									
									
									
									
									
								
							
							
						
						
									
										161
									
								
								src/emu/proc.c
									
									
									
									
									
								
							| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
| 		if (cpu == NULL) { | ||||
| 			err("proc_load_cpus: json_array_get_object() failed for cpu\n"); | ||||
| 		JSON_Object *jcpu = json_array_get_object(cpuarray, i); | ||||
| 		if (jcpu == NULL) { | ||||
| 			err("json_array_get_object() failed for cpu"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		int index = (int) json_object_get_number(cpu, "index"); | ||||
| 		int phyid = (int) json_object_get_number(cpu, "phyid"); | ||||
| 		/* Cast from double */ | ||||
| 		int index = (int) json_object_get_number(jcpu, "index"); | ||||
| 		int phyid = (int) json_object_get_number(jcpu, "phyid"); | ||||
| 
 | ||||
| 		if (add_new_cpu(loom, index, phyid) != 0) { | ||||
| 			err("proc_load_cpus: add_new_cpu() failed\n"); | ||||
| 		struct cpu *cpu = calloc(1, sizeof(struct cpu)); | ||||
| 		if (cpu == NULL) { | ||||
| 			err("calloc failed:"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 
 | ||||
| 		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
									
								
							
							
						
						
									
										41
									
								
								src/emu/system.h
									
									
									
									
									
										Normal 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 */ | ||||
| @ -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
									
								
							
							
						
						
									
										98
									
								
								test/unit/cpu.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										134
									
								
								test/unit/loom.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										33
									
								
								test/unit/proc.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										8
									
								
								test/unit/thread.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| #include "emu/thread.h" | ||||
| #include "common.h" | ||||
| 
 | ||||
| 
 | ||||
| int main(void) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user