Single header and move lib functions to libovni
This commit is contained in:
parent
f8e4c0a0a4
commit
cfc4eb7527
11
Makefile
11
Makefile
@ -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
116
def.h
@ -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
271
dump.c
@ -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')
|
|
||||||
continue;
|
|
||||||
p = strchr(dirent->d_name, '.');
|
|
||||||
if(p == NULL)
|
|
||||||
continue;
|
|
||||||
p++;
|
|
||||||
if(*p == '\0')
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "bad thread stream file: %s\n",
|
fprintf(stderr, "%02x ", buf[i+j]);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
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
400
ovni.c
@ -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
198
ovni.h
@ -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
126
ovni2prv.c
Normal 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
336
prvth.c
@ -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;
|
|
||||||
}
|
|
10
test_speed.c
10
test_speed.c
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user