2021-07-28 11:56:35 +02:00
|
|
|
#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 <assert.h>
|
2021-08-03 19:56:31 +02:00
|
|
|
#include <unistd.h>
|
2021-07-28 11:56:35 +02:00
|
|
|
|
|
|
|
#include "ovni.h"
|
|
|
|
#include "ovni_trace.h"
|
|
|
|
#include "emu.h"
|
2021-08-03 18:42:56 +02:00
|
|
|
#include "prv.h"
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
/* Obtains the corrected clock of the given event */
|
|
|
|
int64_t
|
|
|
|
evclock(struct ovni_stream *stream, struct ovni_ev *ev)
|
|
|
|
{
|
|
|
|
return (int64_t) ovni_ev_get_clock(ev) + stream->clock_offset;
|
|
|
|
}
|
|
|
|
|
2021-07-28 11:56:35 +02:00
|
|
|
static void
|
|
|
|
emit_ev(struct ovni_stream *stream, struct ovni_ev *ev)
|
|
|
|
{
|
|
|
|
int64_t delta;
|
|
|
|
uint64_t clock;
|
|
|
|
int i, payloadsize;
|
|
|
|
|
|
|
|
//dbg("sizeof(*ev) = %d\n", sizeof(*ev));
|
|
|
|
//hexdump((uint8_t *) ev, sizeof(*ev));
|
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
clock = evclock(stream, ev);
|
2021-07-28 11:56:35 +02:00
|
|
|
|
|
|
|
delta = clock - stream->lastclock;
|
|
|
|
|
|
|
|
dbg("%d.%d.%d %c %c %c % 20lu % 15ld ",
|
|
|
|
stream->loom, stream->proc, stream->tid,
|
2021-07-30 20:08:40 +02:00
|
|
|
ev->header.model, ev->header.class, ev->header.value, clock, delta);
|
2021-07-28 11:56:35 +02:00
|
|
|
|
|
|
|
payloadsize = ovni_payload_size(ev);
|
|
|
|
for(i=0; i<payloadsize; i++)
|
|
|
|
{
|
|
|
|
dbg("%d ", ev->payload.u8[i]);
|
|
|
|
}
|
|
|
|
dbg("\n");
|
|
|
|
|
|
|
|
stream->lastclock = clock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emu_emit(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
emit_ev(emu->cur_stream, emu->cur_ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ovni_ethread *
|
|
|
|
find_thread(struct ovni_eproc *proc, pid_t tid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct ovni_ethread *thread;
|
|
|
|
|
|
|
|
for(i=0; i<proc->nthreads; i++)
|
|
|
|
{
|
|
|
|
thread = &proc->thread[i];
|
|
|
|
if(thread->tid == tid)
|
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-07-28 19:12:20 +02:00
|
|
|
hook_pre(struct ovni_emu *emu)
|
2021-07-28 11:56:35 +02:00
|
|
|
{
|
|
|
|
//emu_emit(emu);
|
|
|
|
|
2021-07-30 20:08:40 +02:00
|
|
|
switch(emu->cur_ev->header.model)
|
2021-07-28 11:56:35 +02:00
|
|
|
{
|
2021-07-28 19:12:20 +02:00
|
|
|
case 'O': hook_pre_ovni(emu); break;
|
2021-07-29 17:46:25 +02:00
|
|
|
case 'V': hook_pre_nosv(emu); break;
|
2021-07-28 19:12:20 +02:00
|
|
|
default:
|
|
|
|
//dbg("unknown model %c\n", emu->cur_ev->model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-07-30 21:37:25 +02:00
|
|
|
hook_emit(struct ovni_emu *emu)
|
2021-07-28 19:12:20 +02:00
|
|
|
{
|
|
|
|
//emu_emit(emu);
|
|
|
|
|
2021-07-30 20:08:40 +02:00
|
|
|
switch(emu->cur_ev->header.model)
|
2021-07-28 19:12:20 +02:00
|
|
|
{
|
2021-07-30 21:37:25 +02:00
|
|
|
case 'O': hook_emit_ovni(emu); break;
|
|
|
|
case 'V': hook_emit_nosv(emu); break;
|
2021-07-28 19:12:20 +02:00
|
|
|
default:
|
|
|
|
//dbg("unknown model %c\n", emu->cur_ev->model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
hook_post(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
//emu_emit(emu);
|
|
|
|
|
2021-07-30 20:08:40 +02:00
|
|
|
switch(emu->cur_ev->header.model)
|
2021-07-28 19:12:20 +02:00
|
|
|
{
|
|
|
|
case 'O': hook_post_ovni(emu); break;
|
2021-07-28 11:56:35 +02:00
|
|
|
default:
|
|
|
|
//dbg("unknown model %c\n", emu->cur_ev->model);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_current(struct ovni_emu *emu, struct ovni_stream *stream)
|
|
|
|
{
|
|
|
|
emu->cur_stream = stream;
|
2021-07-30 20:08:40 +02:00
|
|
|
emu->cur_ev = stream->cur_ev;
|
2021-07-28 11:56:35 +02:00
|
|
|
emu->cur_loom = &emu->trace.loom[stream->loom];
|
|
|
|
emu->cur_proc = &emu->cur_loom->proc[stream->proc];
|
|
|
|
emu->cur_thread = &emu->cur_proc->thread[stream->thread];
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
next_event(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
int i, f;
|
|
|
|
uint64_t minclock;
|
|
|
|
struct ovni_ev *ev;
|
|
|
|
struct ovni_stream *stream;
|
|
|
|
struct ovni_trace *trace;
|
2021-08-03 19:56:31 +02:00
|
|
|
|
|
|
|
static int done_first = 0;
|
2021-07-28 11:56:35 +02:00
|
|
|
|
|
|
|
trace = &emu->trace;
|
|
|
|
|
|
|
|
f = -1;
|
|
|
|
minclock = 0;
|
|
|
|
|
|
|
|
/* TODO: use a heap */
|
|
|
|
|
|
|
|
/* Select next event based on the clock */
|
|
|
|
for(i=0; i<trace->nstreams; i++)
|
|
|
|
{
|
|
|
|
stream = &trace->stream[i];
|
|
|
|
|
|
|
|
if(!stream->active)
|
|
|
|
continue;
|
|
|
|
|
2021-07-30 20:08:40 +02:00
|
|
|
ev = stream->cur_ev;
|
2021-08-03 19:56:31 +02:00
|
|
|
if(f < 0 || evclock(stream, ev) < minclock)
|
2021-07-28 11:56:35 +02:00
|
|
|
{
|
|
|
|
f = i;
|
2021-08-03 19:56:31 +02:00
|
|
|
minclock = evclock(stream, ev);
|
2021-07-28 11:56:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* We have a valid stream with a new event */
|
|
|
|
stream = &trace->stream[f];
|
|
|
|
|
|
|
|
set_current(emu, stream);
|
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
if(emu->lastclock > evclock(stream, stream->cur_ev))
|
2021-07-28 11:56:35 +02:00
|
|
|
{
|
|
|
|
fprintf(stdout, "warning: backwards jump in time %lu -> %lu\n",
|
2021-08-03 19:56:31 +02:00
|
|
|
emu->lastclock, evclock(stream, stream->cur_ev));
|
2021-07-28 11:56:35 +02:00
|
|
|
}
|
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
emu->lastclock = evclock(stream, stream->cur_ev);
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
if(!done_first)
|
|
|
|
{
|
|
|
|
done_first = 1;
|
|
|
|
emu->firstclock = emu->lastclock;
|
|
|
|
}
|
2021-07-29 17:46:25 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
emu->delta_time = emu->lastclock - emu->firstclock;
|
2021-07-29 17:46:25 +02:00
|
|
|
|
2021-07-28 11:56:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
emulate(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct ovni_ev ev;
|
|
|
|
struct ovni_stream *stream;
|
|
|
|
struct ovni_trace *trace;
|
|
|
|
|
|
|
|
/* Load events */
|
|
|
|
trace = &emu->trace;
|
|
|
|
for(i=0; i<trace->nstreams; i++)
|
|
|
|
{
|
|
|
|
stream = &trace->stream[i];
|
|
|
|
ovni_load_next_event(stream);
|
|
|
|
}
|
|
|
|
|
2021-08-03 17:48:37 +02:00
|
|
|
|
2021-07-28 11:56:35 +02:00
|
|
|
emu->lastclock = 0;
|
|
|
|
|
|
|
|
/* Then process all events */
|
|
|
|
while(next_event(emu) == 0)
|
|
|
|
{
|
|
|
|
//fprintf(stdout, "step %i\n", i);
|
2021-07-28 19:12:20 +02:00
|
|
|
hook_pre(emu);
|
2021-07-30 21:37:25 +02:00
|
|
|
hook_emit(emu);
|
2021-07-28 19:12:20 +02:00
|
|
|
hook_post(emu);
|
2021-07-28 11:56:35 +02:00
|
|
|
|
|
|
|
/* Read the next event */
|
|
|
|
ovni_load_next_event(emu->cur_stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ovni_ethread *
|
|
|
|
emu_get_thread(struct ovni_emu *emu, int tid)
|
|
|
|
{
|
|
|
|
int i, j, k;
|
|
|
|
struct ovni_loom *loom;
|
|
|
|
struct ovni_eproc *proc;
|
|
|
|
struct ovni_ethread *thread;
|
|
|
|
|
|
|
|
for(i=0; i<emu->trace.nlooms; i++)
|
|
|
|
{
|
|
|
|
loom = &emu->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];
|
|
|
|
if(thread->tid == tid)
|
|
|
|
{
|
|
|
|
/* Only same process threads can
|
|
|
|
* change the affinity to each
|
|
|
|
* others */
|
|
|
|
assert(emu->cur_proc == proc);
|
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return thread;
|
|
|
|
}
|
|
|
|
|
2021-08-03 17:48:37 +02:00
|
|
|
static void
|
|
|
|
add_new_cpu(struct ovni_emu *emu, struct ovni_loom *loom, int i, int phyid)
|
|
|
|
{
|
|
|
|
/* The logical id must match our index */
|
|
|
|
assert(i == loom->ncpus);
|
|
|
|
|
|
|
|
assert(loom->cpu[i].state == CPU_ST_UNKNOWN);
|
|
|
|
|
|
|
|
loom->cpu[loom->ncpus].state = CPU_ST_READY;
|
|
|
|
loom->cpu[loom->ncpus].i = i;
|
|
|
|
loom->cpu[loom->ncpus].phyid = phyid;
|
|
|
|
loom->cpu[loom->ncpus].gindex = emu->total_cpus++;
|
|
|
|
|
|
|
|
dbg("new cpu %d at phyid=%d\n", i, phyid);
|
|
|
|
|
|
|
|
loom->ncpus++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
proc_load_cpus(struct ovni_emu *emu, struct ovni_loom *loom, struct ovni_eproc *proc)
|
|
|
|
{
|
|
|
|
JSON_Array *cpuarray;
|
|
|
|
JSON_Object *cpu;
|
|
|
|
JSON_Object *meta;
|
|
|
|
int i, index, phyid;
|
|
|
|
|
|
|
|
meta = json_value_get_object(proc->meta);
|
|
|
|
|
|
|
|
assert(meta);
|
|
|
|
|
|
|
|
cpuarray = json_object_get_array(meta, "cpus");
|
|
|
|
|
|
|
|
/* This process doesn't have the cpu list */
|
|
|
|
if(cpuarray == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
assert(loom->ncpus == 0);
|
|
|
|
|
|
|
|
for(i = 0; i < json_array_get_count(cpuarray); i++)
|
|
|
|
{
|
|
|
|
cpu = json_array_get_object(cpuarray, i);
|
|
|
|
|
|
|
|
index = (int) json_object_get_number(cpu, "index");
|
|
|
|
phyid = (int) json_object_get_number(cpu, "phyid");
|
|
|
|
|
|
|
|
add_new_cpu(emu, loom, index, phyid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Obtain CPUs in the metadata files and other data */
|
|
|
|
static int
|
|
|
|
load_metadata(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
int i, j, k, s;
|
|
|
|
struct ovni_loom *loom;
|
|
|
|
struct ovni_eproc *proc;
|
|
|
|
struct ovni_ethread *thread;
|
|
|
|
struct ovni_stream *stream;
|
|
|
|
struct ovni_trace *trace;
|
|
|
|
|
|
|
|
trace = &emu->trace;
|
|
|
|
|
|
|
|
for(i=0; i<trace->nlooms; i++)
|
|
|
|
{
|
|
|
|
loom = &trace->loom[i];
|
|
|
|
for(j=0; j<loom->nprocs; j++)
|
|
|
|
{
|
|
|
|
proc = &loom->proc[j];
|
|
|
|
|
|
|
|
proc_load_cpus(emu, loom, proc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* One of the process must have the list of CPUs */
|
|
|
|
/* FIXME: The CPU list should be at the loom dir */
|
|
|
|
assert(loom->ncpus > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
destroy_metadata(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
int i, j, k, s;
|
|
|
|
struct ovni_loom *loom;
|
|
|
|
struct ovni_eproc *proc;
|
|
|
|
struct ovni_ethread *thread;
|
|
|
|
struct ovni_stream *stream;
|
|
|
|
struct ovni_trace *trace;
|
|
|
|
|
|
|
|
trace = &emu->trace;
|
|
|
|
|
|
|
|
for(i=0; i<trace->nlooms; i++)
|
|
|
|
{
|
|
|
|
loom = &trace->loom[i];
|
|
|
|
for(j=0; j<loom->nprocs; j++)
|
|
|
|
{
|
|
|
|
proc = &loom->proc[j];
|
|
|
|
|
|
|
|
assert(proc->meta);
|
|
|
|
json_value_free(proc->meta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2021-07-30 21:37:25 +02:00
|
|
|
|
2021-08-03 18:42:56 +02:00
|
|
|
static void
|
|
|
|
open_prvs(struct ovni_emu *emu, char *tracedir)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
|
|
|
|
sprintf(path, "%s/%s", tracedir, "thread.prv");
|
|
|
|
|
|
|
|
emu->prv_thread = fopen(path, "w");
|
|
|
|
|
|
|
|
if(emu->prv_thread == NULL)
|
|
|
|
abort();
|
|
|
|
|
|
|
|
sprintf(path, "%s/%s", tracedir, "cpu.prv");
|
|
|
|
|
|
|
|
emu->prv_cpu = fopen(path, "w");
|
|
|
|
|
|
|
|
if(emu->prv_cpu == NULL)
|
|
|
|
abort();
|
|
|
|
|
|
|
|
prv_header(emu->prv_thread, emu->trace.nstreams);
|
|
|
|
prv_header(emu->prv_cpu, emu->total_cpus + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
close_prvs(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
fclose(emu->prv_thread);
|
|
|
|
fclose(emu->prv_cpu);
|
|
|
|
}
|
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
static void
|
|
|
|
usage(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
err("Usage: emu [-c offsetfile] tracedir\n");
|
|
|
|
err("\n");
|
|
|
|
err("Options:\n");
|
|
|
|
err(" -c offsetfile Use the given offset file to correct\n");
|
|
|
|
err(" the clocks among nodes. It can be\n");
|
|
|
|
err(" generated by the ovnisync program\n");
|
|
|
|
err("\n");
|
|
|
|
err(" tracedir The output trace dir generated by ovni.\n");
|
|
|
|
err("\n");
|
|
|
|
err("The output PRV files are placed in the tracedir directory.\n");
|
|
|
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2021-07-30 21:37:25 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
static void
|
|
|
|
parse_args(struct ovni_emu *emu, int argc, char *argv[])
|
2021-07-28 11:56:35 +02:00
|
|
|
{
|
2021-08-03 19:56:31 +02:00
|
|
|
int opt;
|
|
|
|
|
|
|
|
while((opt = getopt(argc, argv, "c:")) != -1)
|
|
|
|
{
|
|
|
|
switch(opt)
|
|
|
|
{
|
|
|
|
case 'c':
|
|
|
|
emu->clock_offset_file = optarg;
|
|
|
|
break;
|
|
|
|
default: /* '?' */
|
|
|
|
usage(argc, argv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(optind >= argc)
|
|
|
|
{
|
|
|
|
err("missing tracedir\n");
|
|
|
|
usage(argc, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
emu->tracedir = argv[optind];
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ovni_loom *
|
|
|
|
find_loom_by_hostname(struct ovni_emu *emu, char *host)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct ovni_loom *loom;
|
|
|
|
|
|
|
|
for(i=0; i<emu->trace.nlooms; i++)
|
|
|
|
{
|
|
|
|
loom = &emu->trace.loom[i];
|
|
|
|
|
|
|
|
if(strcmp(loom->hostname, host) == 0)
|
|
|
|
return loom;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
load_clock_offsets(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
char buf[1024];
|
|
|
|
int i, rank;
|
|
|
|
double offset, std;
|
|
|
|
char host[HOST_NAME_MAX];
|
|
|
|
struct ovni_loom *loom;
|
|
|
|
struct ovni_trace *trace;
|
|
|
|
struct ovni_stream *stream;
|
|
|
|
|
|
|
|
f = fopen(emu->clock_offset_file, "r");
|
|
|
|
|
|
|
|
if(f == NULL)
|
|
|
|
{
|
|
|
|
perror("fopen clock offset file failed\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ignore header line */
|
|
|
|
fgets(buf, 1024, f);
|
|
|
|
|
|
|
|
while(fscanf(f, "%d %s %lf %lf", &rank, host, &offset, &std) == 4)
|
|
|
|
{
|
|
|
|
loom = find_loom_by_hostname(emu, host);
|
|
|
|
|
|
|
|
if(loom == NULL)
|
|
|
|
{
|
|
|
|
err("No loom has hostname %s\n", host);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(loom->clock_offset != 0)
|
|
|
|
{
|
|
|
|
err("warning: loom at host %s already has a clock offset\n",
|
|
|
|
host);
|
|
|
|
}
|
|
|
|
|
|
|
|
loom->clock_offset = (int64_t) offset;
|
|
|
|
}
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
/* Then populate the stream offsets */
|
|
|
|
|
|
|
|
trace = &emu->trace;
|
|
|
|
|
|
|
|
for(i=0; i<trace->nstreams; i++)
|
2021-07-28 11:56:35 +02:00
|
|
|
{
|
2021-08-03 19:56:31 +02:00
|
|
|
stream = &trace->stream[i];
|
|
|
|
loom = &trace->loom[stream->loom];
|
|
|
|
stream->clock_offset = loom->clock_offset;
|
2021-07-28 11:56:35 +02:00
|
|
|
}
|
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
fclose(f);
|
|
|
|
}
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
static void
|
|
|
|
emu_init(struct ovni_emu *emu, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
memset(emu, 0, sizeof(emu));
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
parse_args(emu, argc, argv);
|
|
|
|
|
|
|
|
if(ovni_load_trace(&emu->trace, emu->tracedir))
|
2021-08-03 17:48:37 +02:00
|
|
|
abort();
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
if(ovni_load_streams(&emu->trace))
|
2021-08-03 17:48:37 +02:00
|
|
|
abort();
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
if(load_metadata(emu) != 0)
|
2021-08-03 17:48:37 +02:00
|
|
|
abort();
|
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
if(emu->clock_offset_file != NULL)
|
|
|
|
load_clock_offsets(emu);
|
2021-08-03 17:48:37 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
open_prvs(emu, emu->tracedir);
|
|
|
|
}
|
2021-07-29 17:46:25 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
static void
|
|
|
|
emu_destroy(struct ovni_emu *emu)
|
|
|
|
{
|
|
|
|
close_prvs(emu);
|
|
|
|
destroy_metadata(emu);
|
|
|
|
ovni_free_streams(&emu->trace);
|
|
|
|
}
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct ovni_emu emu;
|
2021-08-03 18:42:56 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
emu_init(&emu, argc, argv);
|
2021-08-03 17:48:37 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
emulate(&emu);
|
2021-07-28 11:56:35 +02:00
|
|
|
|
2021-08-03 19:56:31 +02:00
|
|
|
emu_destroy(&emu);
|
2021-08-03 17:48:37 +02:00
|
|
|
|
2021-07-28 11:56:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|