Single header and move lib functions to libovni

This commit is contained in:
Rodrigo Arias 2021-07-24 10:53:41 +02:00
parent f8e4c0a0a4
commit cfc4eb7527
8 changed files with 739 additions and 729 deletions

View File

@ -1,12 +1,17 @@
CFLAGS=-fPIC CFLAGS=-fPIC
# Debug CFLAGS
#CFLAGS+=-fsanitize=address #CFLAGS+=-fsanitize=address
#LDFLAGS+=-fsanitize=address #LDFLAGS+=-fsanitize=address
#CFLAGS+=-g -O0 #CFLAGS+=-g -O0
# Performance CFLAGS
CFLAGS+=-O3 CFLAGS+=-O3
CFLAGS+=-fstack-protector-explicit CFLAGS+=-fstack-protector-explicit
CFLAGS+=-flto
BIN=dump libovni.a prvth test_speed BIN=dump libovni.a test_speed ovni2prv
#BIN=dump libovni.a prvth test_speed emu
all: $(BIN) all: $(BIN)
@ -17,5 +22,9 @@ dump: ovni.o dump.o
test_speed: test_speed.c ovni.o test_speed: test_speed.c ovni.o
emu: emu.c ovni.o
ovni2prv: ovni2prv.c ovni.o
clean: clean:
rm -f *.o $(BIN) rm -f *.o $(BIN)

116
def.h
View File

@ -1,121 +1,5 @@
#ifndef OVNI_DEF_H #ifndef OVNI_DEF_H
#define OVNI_DEF_H #define OVNI_DEF_H
#define MAX_CPU 256
#define MAX_PROC 32
#define MAX_THR 32
#define MAX_LOOM 4
#define TRACEDIR "ovni"
#define MAX_EV (16*1024) /* 16 kev per thread */
//#define MAX_EV (16) /* 16 ev per thread */
/* ----------------------- common ------------------------ */
enum thread_state {
ST_THREAD_UNINIT = 0,
ST_THREAD_INIT = 1
};
struct __attribute__((__packed__)) event {
uint64_t clock;
uint8_t fsm;
uint8_t event;
uint16_t a;
uint16_t b;
};
/* ----------------------- runtime ------------------------ */
/* State of each thread on runtime */
struct rthread {
/* Current cpu the thread is running on. Set to -1 if unbounded or
* unknown */
int cpu;
/* Current thread id */
pid_t tid;
/* Clock value of the events being emitted */
uint64_t clockvalue;
/* Stream trace file descriptor */
int streamfd;
int ready;
/* Buffer to write events */
int nevents;
struct event events[MAX_EV];
};
/* State of each process on runtime */
struct rproc {
/* Path of the process tracedir */
char dir[PATH_MAX];
int proc;
int loom;
int ncpus;
clockid_t clockid;
char procdir[PATH_MAX];
int ready;
};
/* ----------------------- emulated ------------------------ */
/* State of each thread on post-process */
struct ethread {
/* Emulated thread tid */
pid_t tid;
/* Stream file */
FILE *f;
/* Thread stream */
struct stream *stream;
};
/* State of each process on post-process */
struct eproc {
/* Monotonic counter for process index */
/* TODO: Use pid? */
int proc;
/* Path of the process tracedir */
char dir[PATH_MAX];
/* Threads */
size_t nthreads;
struct ethread thread[MAX_THR];
};
/* ----------------------- trace ------------------------ */
/* State of each loom on post-process */
struct loom {
size_t nprocs;
struct eproc proc[MAX_PROC];
};
struct stream {
FILE *f;
int tid;
int thread;
int proc;
int loom;
int loaded;
int active;
struct event last;
uint64_t lastclock;
};
struct trace {
int nlooms;
struct loom loom[MAX_LOOM];
int nstreams;
struct stream *stream;
};
#endif /* OVNI_DEF_H */ #endif /* OVNI_DEF_H */

271
dump.c
View File

@ -8,238 +8,76 @@
#include <stdatomic.h> #include <stdatomic.h>
#include <dirent.h> #include <dirent.h>
#include "def.h" #include "ovni.h"
int load_proc(struct eproc *proc, char *procdir) #define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define dbg(...) fprintf(stderr, __VA_ARGS__);
#else
#define dbg(...)
#endif
#define err(...) fprintf(stderr, __VA_ARGS__);
static void
hexdump(uint8_t *buf, size_t size)
{ {
struct dirent *dirent; int i, j;
DIR *dir;
char path[PATH_MAX];
char *p;
struct ethread *thread;
if((dir = opendir(procdir)) == NULL) //printf("writing %ld bytes in cpu=%d\n", size, rthread.cpu);
for(i=0; i<size; i+=16)
{ {
fprintf(stderr, "opendir %s failed: %s\n", for(j=0; j<16 && i+j < size; j++)
procdir, strerror(errno));
return -1;
}
while((dirent = readdir(dir)) != NULL)
{ {
if(dirent->d_name[0] != 't') fprintf(stderr, "%02x ", buf[i+j]);
continue;
p = strchr(dirent->d_name, '.');
if(p == NULL)
continue;
p++;
if(*p == '\0')
{
fprintf(stderr, "bad thread stream file: %s\n",
dirent->d_name);
return -1;
} }
fprintf(stderr, "\n");
thread = &proc->thread[proc->nthreads++];
thread->tid = atoi(p);
sprintf(path, "%s/%s", procdir, dirent->d_name);
thread->f = fopen(path, "r");
if(thread->f == NULL)
{
fprintf(stderr, "fopen %s failed: %s\n",
path, strerror(errno));
return -1;
} }
}
closedir(dir);
return 0;
} }
int load_loom(struct loom *loom, char *loomdir) void emit(struct ovni_stream *stream, struct ovni_ev *ev)
{
int proc;
char path[PATH_MAX];
struct stat st;
for(proc=0; proc<MAX_PROC; proc++)
{
sprintf(path, "%s/proc.%d", loomdir, proc);
if(stat(path, &st) != 0)
{
/* No more proc.N directories */
if(errno == ENOENT)
break;
fprintf(stderr, "cannot stat %s: %s\n", path,
strerror(errno));
return -1;
}
if(!S_ISDIR(st.st_mode))
{
fprintf(stderr, "not a dir %s\n", path);
return -1;
}
if(load_proc(&loom->proc[proc], path))
return -1;
}
loom->nprocs = proc;
return 0;
}
int load_trace(struct trace *trace, char *tracedir)
{
int loom, nlooms;
char path[PATH_MAX];
/* TODO: For now only one loom */
nlooms = 1;
loom = 0;
sprintf(path, "%s/loom.%d", tracedir, loom);
if(load_loom(&trace->loom[loom], path))
return -1;
trace->nlooms = nlooms;
return 0;
}
/* Populates the streams in a single array */
int load_streams(struct trace *trace)
{
int i, j, k, s;
struct loom *loom;
struct eproc *proc;
struct ethread *thread;
struct stream *stream;
trace->nstreams = 0;
for(i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
trace->nstreams++;
}
}
}
trace->stream = calloc(trace->nstreams, sizeof(struct stream));
if(trace->stream == NULL)
{
perror("calloc");
return -1;
}
fprintf(stderr, "loaded %d streams\n", trace->nstreams);
for(s=0, i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
thread = &proc->thread[k];
stream = &trace->stream[s++];
stream->f = thread->f;
stream->tid = thread->tid;
stream->proc = j;
stream->loom = i;
stream->active = 1;
stream->lastclock = 0;
}
}
}
return 0;
}
int load_first_event(struct trace *trace)
{
int i;
struct stream *stream;
struct event *ev;
for(i=0; i<trace->nstreams; i++)
{
stream = &trace->stream[i];
ev = &stream->last;
if(fread(ev, sizeof(*ev), 1, stream->f) != 1)
{
fprintf(stderr, "failed to read and event\n");
return -1;
}
fprintf(stderr, "ev clock %u\n", ev->clock);
}
return 0;
}
void emit(struct stream *stream, struct event *ev)
{ {
int64_t delta; int64_t delta;
uint64_t clock;
int i, payloadsize;
delta = ev->clock - stream->lastclock; //printf("sizeof(*ev) = %d\n", sizeof(*ev));
//hexdump((uint8_t *) ev, sizeof(*ev));
printf("%d.%d.%d %c %c % 6u % 6u % 20lu % 15ld\n", clock = ovni_ev_get_clock(ev);
delta = clock - stream->lastclock;
printf("%d.%d.%d %c %c %c % 20lu % 15ld ",
stream->loom, stream->proc, stream->tid, stream->loom, stream->proc, stream->tid,
ev->fsm, ev->event, ev->a, ev->b, ev->clock, delta); ev->model, ev->class, ev->value, clock, delta);
stream->lastclock = ev->clock; payloadsize = ovni_payload_size(ev);
} for(i=0; i<payloadsize; i++)
void load_next_event(struct stream *stream)
{
int i;
size_t n;
struct event *ev;
if(!stream->active)
return;
ev = &stream->last;
if((n = fread(ev, sizeof(*ev), 1, stream->f)) != 1)
{ {
//fprintf(stderr, "failed to read an event, n=%ld\n", n); printf("%d ", ev->payload.payload_u8[i]);
stream->active = 0;
return;
} }
printf("\n");
stream->active = 1; stream->lastclock = clock;
} }
void dump_events(struct trace *trace)
void dump_events(struct ovni_trace *trace)
{ {
int i, f; int i, f;
uint64_t minclock, lastclock; uint64_t minclock, lastclock;
struct event *ev; struct ovni_ev *ev;
struct stream *stream; struct ovni_stream *stream;
/* Load events */ /* Load events */
for(i=0; i<trace->nstreams; i++) for(i=0; i<trace->nstreams; i++)
{ {
stream = &trace->stream[i]; stream = &trace->stream[i];
load_next_event(stream); ovni_load_next_event(stream);
} }
lastclock = 0; lastclock = 0;
@ -258,10 +96,10 @@ void dump_events(struct trace *trace)
continue; continue;
ev = &stream->last; ev = &stream->last;
if(f < 0 || ev->clock < minclock) if(f < 0 || ovni_ev_get_clock(ev) < minclock)
{ {
f = i; f = i;
minclock = ev->clock; minclock = ovni_ev_get_clock(ev);
} }
} }
@ -272,19 +110,19 @@ void dump_events(struct trace *trace)
stream = &trace->stream[f]; stream = &trace->stream[f];
if(lastclock > stream->last.clock) if(lastclock > ovni_ev_get_clock(&stream->last))
{ {
fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n", fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n",
lastclock, stream->last.clock); lastclock, ovni_ev_get_clock(&stream->last));
} }
/* Emit current event */ /* Emit current event */
emit(stream, &stream->last); emit(stream, &stream->last);
lastclock = stream->last.clock; lastclock = ovni_ev_get_clock(&stream->last);
/* Read the next one */ /* Read the next one */
load_next_event(stream); ovni_load_next_event(stream);
/* Unset the index */ /* Unset the index */
f = -1; f = -1;
@ -293,15 +131,10 @@ void dump_events(struct trace *trace)
} }
} }
void free_streams(struct trace *trace)
{
free(trace->stream);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
char *tracedir; char *tracedir;
struct trace trace; struct ovni_trace trace;
if(argc != 2) if(argc != 2)
{ {
@ -311,15 +144,15 @@ int main(int argc, char *argv[])
tracedir = argv[1]; tracedir = argv[1];
if(load_trace(&trace, tracedir)) if(ovni_load_trace(&trace, tracedir))
return 1; return 1;
if(load_streams(&trace)) if(ovni_load_streams(&trace))
return 1; return 1;
dump_events(&trace); dump_events(&trace);
free_streams(&trace); ovni_free_streams(&trace);
return 0; return 0;
} }

400
ovni.c
View File

@ -14,18 +14,29 @@
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h>
#include "ovni.h" #include "ovni.h"
#include "def.h"
#define ENABLE_DEBUG
#ifdef ENABLE_DEBUG
#define dbg(...) fprintf(stderr, __VA_ARGS__);
#else
#define dbg(...)
#endif
#define err(...) fprintf(stderr, __VA_ARGS__);
//#define ENABLE_SLOW_CHECKS //#define ENABLE_SLOW_CHECKS
//#define USE_RDTSC
/* Data per process */ /* Data per process */
struct rproc rproc = {0}; struct ovni_rproc rproc = {0};
/* Data per thread */ /* Data per thread */
_Thread_local struct rthread rthread = {0}; _Thread_local struct ovni_rthread rthread = {0};
static int static int
create_trace_dirs(char *tracedir, int loom, int proc) create_trace_dirs(char *tracedir, int loom, int proc)
@ -102,7 +113,7 @@ ovni_proc_init(int loom, int proc)
/* By default we use the monotonic clock */ /* By default we use the monotonic clock */
rproc.clockid = CLOCK_MONOTONIC; rproc.clockid = CLOCK_MONOTONIC;
if(create_trace_dirs(TRACEDIR, loom, proc)) if(create_trace_dirs(OVNI_TRACEDIR, loom, proc))
abort(); abort();
rproc.ready = 1; rproc.ready = 1;
@ -135,7 +146,14 @@ ovni_thread_init(pid_t tid)
rthread.tid = tid; rthread.tid = tid;
rthread.cpu = -666; rthread.cpu = -666;
rthread.nevents = 0; rthread.evlen = 0;
rthread.evbuf = malloc(OVNI_MAX_EV_BUF);
if(rthread.evbuf == NULL)
{
perror("malloc");
abort();
}
if(create_trace_stream(tid)) if(create_trace_stream(tid))
abort(); abort();
@ -145,6 +163,13 @@ ovni_thread_init(pid_t tid)
return 0; return 0;
} }
int
ovni_thread_free()
{
assert(rthread.ready);
free(rthread.evbuf);
}
int int
ovni_thread_isready() ovni_thread_isready()
{ {
@ -157,25 +182,48 @@ ovni_cpu_set(int cpu)
rthread.cpu = cpu; rthread.cpu = cpu;
} }
/* Sets the current time so that all subsequent events have the new static inline
* timestamp */ uint64_t rdtsc(void)
void {
ovni_clock_update() uint32_t lo, hi;
// RDTSC copies contents of 64-bit TSC into EDX:EAX
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t) hi << 32 | lo;
}
uint64_t
ovni_get_clock()
{ {
struct timespec tp; struct timespec tp;
uint64_t ns = 1000LL * 1000LL * 1000LL; uint64_t ns = 1000LL * 1000LL * 1000LL;
uint64_t raw; uint64_t raw;
int ret; int ret;
#ifdef USE_RDTSC
raw = rdtsc();
#else
ret = clock_gettime(rproc.clockid, &tp); ret = clock_gettime(rproc.clockid, &tp);
#ifdef ENABLE_SLOW_CHECKS #ifdef ENABLE_SLOW_CHECKS
if(ret) abort(); if(ret) abort();
#endif #endif /* ENABLE_SLOW_CHECKS */
raw = tp.tv_sec * ns + tp.tv_nsec; raw = tp.tv_sec * ns + tp.tv_nsec;
//raw = raw >> 6;
rthread.clockvalue = (uint64_t) raw; rthread.clockvalue = (uint64_t) raw;
#endif /* USE_RDTSC */
return raw;
}
/* Sets the current time so that all subsequent events have the new
* timestamp */
void
ovni_clock_update()
{
rthread.clockvalue = ovni_get_clock();
} }
static void static void
@ -217,61 +265,329 @@ ovni_write(uint8_t *buf, size_t size)
return 0; return 0;
} }
static int
flush_evbuf()
{
int ret;
assert(rthread.ready);
assert(rproc.ready);
ret = ovni_write(rthread.evbuf, rthread.evlen);
rthread.evlen = 0;
return ret;
}
static void
ovni_ev_set_clock(struct ovni_ev *ev)
{
ev->clock_lo = (uint32_t) (rthread.clockvalue & 0xffffffff);
ev->clock_hi = (uint16_t) ((rthread.clockvalue >> 32) & 0xffff);
}
uint64_t
ovni_ev_get_clock(struct ovni_ev *ev)
{
uint64_t clock;
clock = ((uint64_t) ev->clock_hi) << 32 | ((uint64_t) ev->clock_lo);
return clock;
}
void
ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv)
{
ev->model = mcv[0];
ev->class = mcv[1];
ev->value = mcv[2];
}
int int
ovni_thread_flush() ovni_payload_size(struct ovni_ev *ev)
{
return ev->flags & 0x0f;
}
void
ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size)
{
/* Ensure we have room */
assert(ovni_payload_size(ev) + size < 16);
ev->flags = ev->flags & 0xf0 | size & 0x0f;
}
int
ovni_ev_size(struct ovni_ev *ev)
{
return sizeof(*ev) - sizeof(ev->payload) +
ovni_payload_size(ev);
}
static void
ovni_ev_add(struct ovni_ev *ev)
{
int size;
ovni_ev_set_clock(ev);
size = ovni_ev_size(ev);
memcpy(&rthread.evbuf[rthread.evlen], ev, size);
rthread.evlen += size;
}
void
ovni_ev(struct ovni_ev *ev)
{
ovni_ev_set_clock(ev);
ovni_ev_add(ev);
}
int
ovni_flush()
{ {
int ret = 0; int ret = 0;
struct event pre={0}, post={0}; struct ovni_ev pre={0}, post={0};
assert(rthread.ready); assert(rthread.ready);
assert(rproc.ready); assert(rproc.ready);
ovni_clock_update(); ovni_clock_update();
pre.clock = rthread.clockvalue; ovni_ev_set_clock(&pre);
pre.fsm = 'F'; ovni_ev_set_mcv(&pre, "OF[");
pre.event = '[';
ret = ovni_write((uint8_t *) rthread.events, rthread.nevents * sizeof(struct event)); ret = flush_evbuf();
rthread.nevents = 0;
ovni_clock_update(); ovni_clock_update();
post.clock = rthread.clockvalue; ovni_ev_set_clock(&post);
post.fsm = 'F'; ovni_ev_set_mcv(&post, "OF]");
post.event = ']';
/* Also emit the two flush events */ /* Add the two flush events */
memcpy(&rthread.events[rthread.nevents++], &pre, sizeof(struct event));; ovni_ev_add(&pre);
memcpy(&rthread.events[rthread.nevents++], &post, sizeof(struct event));; ovni_ev_add(&post);
return ret; return ret;
} }
static int
load_proc(struct ovni_eproc *proc, char *procdir)
{
struct dirent *dirent;
DIR *dir;
char path[PATH_MAX];
char *p;
struct ovni_ethread *thread;
if((dir = opendir(procdir)) == NULL)
{
fprintf(stderr, "opendir %s failed: %s\n",
procdir, strerror(errno));
return -1;
}
while((dirent = readdir(dir)) != NULL)
{
if(dirent->d_name[0] != 't')
continue;
p = strchr(dirent->d_name, '.');
if(p == NULL)
continue;
p++;
if(*p == '\0')
{
fprintf(stderr, "bad thread stream file: %s\n",
dirent->d_name);
return -1;
}
thread = &proc->thread[proc->nthreads++];
thread->tid = atoi(p);
sprintf(path, "%s/%s", procdir, dirent->d_name);
thread->f = fopen(path, "r");
if(thread->f == NULL)
{
fprintf(stderr, "fopen %s failed: %s\n",
path, strerror(errno));
return -1;
}
}
closedir(dir);
return 0;
}
static int static int
ovni_ev(uint8_t fsm, uint8_t event, uint16_t a, uint16_t b) load_loom(struct ovni_loom *loom, char *loomdir)
{ {
struct event *ev; int proc;
int ret = 0; char path[PATH_MAX];
struct stat st;
ev = &rthread.events[rthread.nevents++]; for(proc=0; proc<OVNI_MAX_PROC; proc++)
{
sprintf(path, "%s/proc.%d", loomdir, proc);
ev->clock = rthread.clockvalue; if(stat(path, &st) != 0)
ev->fsm = fsm; {
ev->event = event; /* No more proc.N directories */
ev->a = a; if(errno == ENOENT)
ev->b = b; break;
/* Flush */ fprintf(stderr, "cannot stat %s: %s\n", path,
if(rthread.nevents >= MAX_EV) strerror(errno));
ret = ovni_thread_flush(); return -1;
}
return ret; if(!S_ISDIR(st.st_mode))
{
fprintf(stderr, "not a dir %s\n", path);
return -1;
}
if(load_proc(&loom->proc[proc], path))
return -1;
}
loom->nprocs = proc;
return 0;
} }
int int
ovni_thread_ev(uint8_t fsm, uint8_t event, uint16_t a, uint16_t b) ovni_load_trace(struct ovni_trace *trace, char *tracedir)
{ {
assert(rthread.ready); int loom, nlooms;
assert(rproc.ready); char path[PATH_MAX];
return ovni_ev(fsm, event, a, b);
/* TODO: For now only one loom */
nlooms = 1;
loom = 0;
sprintf(path, "%s/loom.%d", tracedir, loom);
if(load_loom(&trace->loom[loom], path))
return -1;
trace->nlooms = nlooms;
return 0;
} }
/* Populates the streams in a single array */
int
ovni_load_streams(struct ovni_trace *trace)
{
int i, j, k, s;
struct ovni_loom *loom;
struct ovni_eproc *proc;
struct ovni_ethread *thread;
struct ovni_stream *stream;
trace->nstreams = 0;
for(i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
trace->nstreams++;
}
}
}
trace->stream = calloc(trace->nstreams, sizeof(struct ovni_stream));
if(trace->stream == NULL)
{
perror("calloc");
return -1;
}
fprintf(stderr, "loaded %d streams\n", trace->nstreams);
for(s=0, i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
thread = &proc->thread[k];
stream = &trace->stream[s++];
stream->f = thread->f;
stream->tid = thread->tid;
stream->thread = k;
stream->proc = j;
stream->loom = i;
stream->active = 1;
stream->lastclock = 0;
}
}
}
return 0;
}
void
ovni_free_streams(struct ovni_trace *trace)
{
free(trace->stream);
}
void
ovni_load_next_event(struct ovni_stream *stream)
{
int i;
size_t n, size;
struct ovni_ev *ev;
uint8_t flags;
if(!stream->active)
return;
ev = &stream->last;
if((n = fread(&ev->flags, sizeof(ev->flags), 1, stream->f)) != 1)
{
dbg("stream is empty\n");
stream->active = 0;
return;
}
//dbg("flags = %d\n", ev->flags);
size = ovni_ev_size(ev) - sizeof(ev->flags);
//dbg("ev size = %d\n", size);
/* Clean payload from previous event */
memset(&ev->payload, 0, sizeof(ev->payload));
if((n = fread(((uint8_t *) ev) + sizeof(ev->flags), 1, size, stream->f)) != size)
{
err("warning: garbage found at the end of the stream\n");
stream->active = 0;
return;
}
//dbg("loaded next event:\n");
//hexdump((uint8_t *) ev, ovni_ev_size(ev));
//dbg("---------\n");
stream->active = 1;
}

198
ovni.h
View File

@ -1,22 +1,196 @@
#ifndef OVNI_H #ifndef OVNI_H
#define OVNI_H #define OVNI_H
int #include <stdint.h>
ovni_proc_init(int loom, int proc); #include <stdlib.h>
#include <string.h>
#include <linux/limits.h>
int #include "ovni.h"
ovni_thread_init(pid_t tid);
int #define OVNI_MAX_CPU 256
ovni_thread_isready(); #define OVNI_MAX_PROC 32
#define OVNI_MAX_THR 32
#define OVNI_MAX_LOOM 4
#define OVNI_TRACEDIR "ovni"
void /* Reserved buffer for event allocation */
ovni_clock_update(); #define OVNI_MAX_EV_BUF (16 * 1024LL * 1024LL * 1024LL)
int /* ----------------------- common ------------------------ */
ovni_thread_ev(uint8_t fsm, uint8_t event, uint16_t a, uint16_t b);
int struct __attribute__((__packed__)) ovni_ev {
ovni_thread_flush(); /* first 4 bits reserved, last 4 for payload size */
uint8_t flags;
uint8_t model;
uint8_t class;
uint8_t value;
uint16_t clock_hi;
uint32_t clock_lo;
union {
uint8_t payload_u8[16];
uint16_t payload_u16[8];
uint32_t payload_u32[4];
uint64_t payload_u64[2];
} payload;
};
/* ----------------------- runtime ------------------------ */
/* State of each thread on runtime */
struct ovni_rthread {
/* Current cpu the thread is running on. Set to -1 if unbounded or
* unknown */
int cpu;
/* Current thread id */
pid_t tid;
/* Clock value of the events being emitted */
uint64_t clockvalue;
/* Stream trace file descriptor */
int streamfd;
int ready;
/* The number of bytes filled with events */
size_t evlen;
/* Buffer to write events */
uint8_t *evbuf;
};
/* State of each process on runtime */
struct ovni_rproc {
/* Path of the process tracedir */
char dir[PATH_MAX];
int proc;
int loom;
int ncpus;
clockid_t clockid;
char procdir[PATH_MAX];
int ready;
};
/* ----------------------- emulated ------------------------ */
struct ovni_cpu;
/* State of each thread on post-process */
struct ovni_ethread {
/* Emulated thread tid */
pid_t tid;
/* Stream file */
FILE *f;
/* Thread stream */
struct ovni_stream *stream;
/* Current cpu */
struct ovni_cpu *cpu;
};
/* State of each process on post-process */
struct ovni_eproc {
/* Monotonic counter for process index */
/* TODO: Use pid? */
int proc;
/* Path of the process tracedir */
char dir[PATH_MAX];
/* Threads */
size_t nthreads;
struct ovni_ethread thread[OVNI_MAX_THR];
};
/* ----------------------- trace ------------------------ */
/* State of each loom on post-process */
struct ovni_loom {
size_t nprocs;
struct ovni_eproc proc[OVNI_MAX_PROC];
};
struct ovni_stream {
FILE *f;
int tid;
int thread;
int proc;
int loom;
int loaded;
int active;
struct ovni_ev last;
uint64_t lastclock;
};
struct ovni_trace {
int nlooms;
struct ovni_loom loom[OVNI_MAX_LOOM];
int nstreams;
struct ovni_stream *stream;
};
struct ovni_cpu {
/* The thread the cpu is currently running */
struct ovni_ethread *thread;
};
struct ovni_evhead {
struct ovni_stream *stream;
struct ovni_loom *loom;
struct ovni_eproc *proc;
struct ovni_ethread *thread;
};
struct ovni_emulator {
struct ovni_trace trace;
struct ovni_cpu cpu[OVNI_MAX_CPU];
struct ovni_evhead head;
uint64_t lastclock;
};
int ovni_proc_init(int loom, int proc);
int ovni_thread_init(pid_t tid);
int ovni_thread_isready();
void ovni_clock_update();
void ovni_ev_set_mcv(struct ovni_ev *ev, char *mcv);
uint64_t ovni_ev_get_clock(struct ovni_ev *ev);
void ovni_payload_add(struct ovni_ev *ev, uint8_t *buf, int size);
int ovni_ev_size(struct ovni_ev *ev);
int ovni_payload_size(struct ovni_ev *ev);
/* Set the current clock in the event and queue it */
void ovni_ev(struct ovni_ev *ev);
int ovni_flush();
int ovni_load_trace(struct ovni_trace *trace, char *tracedir);
int ovni_load_streams(struct ovni_trace *trace);
void ovni_free_streams(struct ovni_trace *trace);
void ovni_load_next_event(struct ovni_stream *stream);
#endif /* OVNI_H */ #endif /* OVNI_H */

126
ovni2prv.c Normal file
View File

@ -0,0 +1,126 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <linux/limits.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdatomic.h>
#include <dirent.h>
#include "ovni.h"
void emit(struct ovni_stream *stream, struct ovni_ev *ev)
{
static uint64_t firstclock = 0;
int64_t delta;
int task;
if(firstclock == 0)
firstclock = ovni_ev_get_clock(ev);
delta = ovni_ev_get_clock(ev) - firstclock;
//#Paraver (19/01/38 at 03:14):00000000000000000000_ns:0:1:1(00000000000000000008:1)
//2:0:1:1:7:1540663:6400010:1
//2:0:1:1:7:1540663:6400015:1
//2:0:1:1:7:1540663:6400017:0
//2:0:1:1:7:1542091:6400010:1
//2:0:1:1:7:1542091:6400015:1
//2:0:1:1:7:1542091:6400025:1
//2:0:1:1:7:1542091:6400017:0
printf("2:0:1:1:%d:%ld:%d:%d\n", stream->thread+1, delta, ev->class, ev->value);
}
void dump_events(struct ovni_trace *trace)
{
int i, f;
uint64_t minclock, lastclock;
struct ovni_ev *ev;
struct ovni_stream *stream;
/* Load events */
for(i=0; i<trace->nstreams; i++)
{
stream = &trace->stream[i];
ovni_load_next_event(stream);
}
lastclock = 0;
while(1)
{
f = -1;
minclock = 0;
/* Select next event based on the clock */
for(i=0; i<trace->nstreams; i++)
{
stream = &trace->stream[i];
if(!stream->active)
continue;
ev = &stream->last;
if(f < 0 || ovni_ev_get_clock(ev) < minclock)
{
f = i;
minclock = ovni_ev_get_clock(ev);
}
}
//fprintf(stderr, "f=%d minclock=%u\n", f, minclock);
if(f < 0)
break;
stream = &trace->stream[f];
if(lastclock >= ovni_ev_get_clock(&stream->last))
{
fprintf(stderr, "warning: backwards jump in time\n");
}
/* Emit current event */
emit(stream, &stream->last);
lastclock = ovni_ev_get_clock(&stream->last);
/* Read the next one */
ovni_load_next_event(stream);
/* Unset the index */
f = -1;
minclock = 0;
}
}
int main(int argc, char *argv[])
{
char *tracedir;
struct ovni_trace trace;
if(argc != 2)
{
fprintf(stderr, "missing tracedir\n");
exit(EXIT_FAILURE);
}
tracedir = argv[1];
if(ovni_load_trace(&trace, tracedir))
return 1;
if(ovni_load_streams(&trace))
return 1;
printf("#Paraver (19/01/38 at 03:14):00000000000000000000_ns:0:1:1(%d:1)\n", trace.nstreams);
dump_events(&trace);
ovni_free_streams(&trace);
return 0;
}

336
prvth.c
View File

@ -1,336 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <linux/limits.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdatomic.h>
#include <dirent.h>
#include "def.h"
int load_proc(struct eproc *proc, char *procdir)
{
struct dirent *dirent;
DIR *dir;
char path[PATH_MAX];
char *p;
struct ethread *thread;
if((dir = opendir(procdir)) == NULL)
{
fprintf(stderr, "opendir %s failed: %s\n",
procdir, strerror(errno));
return -1;
}
while((dirent = readdir(dir)) != NULL)
{
if(dirent->d_name[0] != 't')
continue;
p = strchr(dirent->d_name, '.');
if(p == NULL)
continue;
p++;
if(*p == '\0')
{
fprintf(stderr, "bad thread stream file: %s\n",
dirent->d_name);
return -1;
}
thread = &proc->thread[proc->nthreads++];
thread->tid = atoi(p);
sprintf(path, "%s/%s", procdir, dirent->d_name);
thread->f = fopen(path, "r");
if(thread->f == NULL)
{
fprintf(stderr, "fopen %s failed: %s\n",
path, strerror(errno));
return -1;
}
}
closedir(dir);
return 0;
}
int load_loom(struct loom *loom, char *loomdir)
{
int proc;
char path[PATH_MAX];
struct stat st;
for(proc=0; proc<MAX_PROC; proc++)
{
sprintf(path, "%s/proc.%d", loomdir, proc);
if(stat(path, &st) != 0)
{
/* No more proc.N directories */
if(errno == ENOENT)
break;
fprintf(stderr, "cannot stat %s: %s\n", path,
strerror(errno));
return -1;
}
if(!S_ISDIR(st.st_mode))
{
fprintf(stderr, "not a dir %s\n", path);
return -1;
}
if(load_proc(&loom->proc[proc], path))
return -1;
}
loom->nprocs = proc;
return 0;
}
int load_trace(struct trace *trace, char *tracedir)
{
int loom, nlooms;
char path[PATH_MAX];
/* TODO: For now only one loom */
nlooms = 1;
loom = 0;
sprintf(path, "%s/loom.%d", tracedir, loom);
if(load_loom(&trace->loom[loom], path))
return -1;
trace->nlooms = nlooms;
return 0;
}
/* Populates the streams in a single array */
int load_streams(struct trace *trace)
{
int i, j, k, s;
struct loom *loom;
struct eproc *proc;
struct ethread *thread;
struct stream *stream;
trace->nstreams = 0;
for(i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
trace->nstreams++;
}
}
}
trace->stream = calloc(trace->nstreams, sizeof(struct stream));
if(trace->stream == NULL)
{
perror("calloc");
return -1;
}
fprintf(stderr, "loaded %d streams\n", trace->nstreams);
for(s=0, i=0; i<trace->nlooms; i++)
{
loom = &trace->loom[i];
for(j=0; j<loom->nprocs; j++)
{
proc = &loom->proc[j];
for(k=0; k<proc->nthreads; k++)
{
thread = &proc->thread[k];
stream = &trace->stream[s++];
stream->f = thread->f;
stream->tid = thread->tid;
stream->thread = k;
stream->proc = j;
stream->loom = i;
stream->active = 1;
}
}
}
return 0;
}
int load_first_event(struct trace *trace)
{
int i;
struct stream *stream;
struct event *ev;
for(i=0; i<trace->nstreams; i++)
{
stream = &trace->stream[i];
ev = &stream->last;
if(fread(ev, sizeof(*ev), 1, stream->f) != 1)
{
fprintf(stderr, "failed to read and event\n");
return -1;
}
fprintf(stderr, "ev clock %u\n", ev->clock);
}
return 0;
}
void emit(struct stream *stream, struct event *ev)
{
static uint64_t firstclock = 0;
int64_t delta;
int task;
if(firstclock == 0)
firstclock = ev->clock;
delta = ev->clock - firstclock;
//#Paraver (19/01/38 at 03:14):00000000000000000000_ns:0:1:1(00000000000000000008:1)
//2:0:1:1:7:1540663:6400010:1
//2:0:1:1:7:1540663:6400015:1
//2:0:1:1:7:1540663:6400017:0
//2:0:1:1:7:1542091:6400010:1
//2:0:1:1:7:1542091:6400015:1
//2:0:1:1:7:1542091:6400025:1
//2:0:1:1:7:1542091:6400017:0
printf("2:0:1:1:%d:%ld:%d:%d\n", stream->thread+1, delta, ev->fsm, ev->event);
}
void load_next_event(struct stream *stream)
{
int i;
size_t n;
struct event *ev;
if(!stream->active)
return;
ev = &stream->last;
if((n = fread(ev, sizeof(*ev), 1, stream->f)) != 1)
{
//fprintf(stderr, "failed to read an event, n=%ld\n", n);
stream->active = 0;
return;
}
stream->active = 1;
}
void dump_events(struct trace *trace)
{
int i, f;
uint64_t minclock, lastclock;
struct event *ev;
struct stream *stream;
/* Load events */
for(i=0; i<trace->nstreams; i++)
{
stream = &trace->stream[i];
load_next_event(stream);
}
lastclock = 0;
while(1)
{
f = -1;
minclock = 0;
/* Select next event based on the clock */
for(i=0; i<trace->nstreams; i++)
{
stream = &trace->stream[i];
if(!stream->active)
continue;
ev = &stream->last;
if(f < 0 || ev->clock < minclock)
{
f = i;
minclock = ev->clock;
}
}
//fprintf(stderr, "f=%d minclock=%u\n", f, minclock);
if(f < 0)
break;
stream = &trace->stream[f];
if(lastclock >= stream->last.clock)
{
fprintf(stderr, "warning: backwards jump in time\n");
}
/* Emit current event */
emit(stream, &stream->last);
lastclock = stream->last.clock;
/* Read the next one */
load_next_event(stream);
/* Unset the index */
f = -1;
minclock = 0;
}
}
void free_streams(struct trace *trace)
{
free(trace->stream);
}
int main(int argc, char *argv[])
{
char *tracedir;
struct trace trace;
if(argc != 2)
{
fprintf(stderr, "missing tracedir\n");
exit(EXIT_FAILURE);
}
tracedir = argv[1];
if(load_trace(&trace, tracedir))
return 1;
if(load_streams(&trace))
return 1;
printf("#Paraver (19/01/38 at 03:14):00000000000000000000_ns:0:1:1(%d:1)\n", trace.nstreams);
dump_events(&trace);
free_streams(&trace);
return 0;
}

View File

@ -2,25 +2,29 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <linux/limits.h>
#include "ovni.h" #include "ovni.h"
#define N 1000 #define N 100000
int main() int main()
{ {
struct ovni_ev ev = {0};
int i; int i;
ovni_proc_init(0, 0); ovni_proc_init(0, 0);
ovni_thread_init(1); ovni_thread_init(1);
ovni_ev_set_mcv(&ev, "OB.");
for(i=0; i<N; i++) for(i=0; i<N; i++)
{ {
ovni_clock_update(); ovni_clock_update();
ovni_thread_ev('B', '.', 0, 0); ovni_ev(&ev);
} }
ovni_thread_flush(); ovni_flush();
return 0; return 0;
} }