From 0cf4738d702e7002895e8fc4edb96e5fe7fd8eae Mon Sep 17 00:00:00 2001 From: Cedric Roux <cedric.roux@eurecom.fr> Date: Fri, 13 May 2016 19:00:21 +0200 Subject: [PATCH] time view, not tested at all --- common/utils/T/tracer/view/Makefile | 2 +- common/utils/T/tracer/view/time.c | 297 ++++++++++++++++++++++++++++ common/utils/T/tracer/view/view.h | 3 + 3 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 common/utils/T/tracer/view/time.c diff --git a/common/utils/T/tracer/view/Makefile b/common/utils/T/tracer/view/Makefile index a922ec025d..51b5114a0e 100644 --- a/common/utils/T/tracer/view/Makefile +++ b/common/utils/T/tracer/view/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-Wall -g -pthread -I.. -OBJS=stdout.o textlist.o xy.o tti.o +OBJS=stdout.o textlist.o xy.o tti.o time.o view.a: $(OBJS) ar cr view.a $(OBJS) diff --git a/common/utils/T/tracer/view/time.c b/common/utils/T/tracer/view/time.c new file mode 100644 index 0000000000..417760f9d5 --- /dev/null +++ b/common/utils/T/tracer/view/time.c @@ -0,0 +1,297 @@ +#include "view.h" +#include "../utils.h" +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +/****************************************************************************/ +/* timeview */ +/****************************************************************************/ + +struct plot { + long *nano; + int nanosize; + int nanomaxsize; + int line; + int color; +}; + +struct tick { + struct plot *p; /* one plot per subview, + * so size is 'subcount' + * (see in struct time below) + */ +}; + +struct time { + view common; + gui *g; + widget *w; + float refresh_rate; + pthread_mutex_t lock; + struct tick *t; /* t is a circular list + * a tick lasts one second + */ + int tsize; /* size of t */ + int tstart; /* starting index in t */ + time_t tstart_time; /* timestamp (in seconds) of starting in t */ + int subcount; /* number of subviews */ + struct timespec latest_time; /* time of latest received tick */ + int64_t pixel_length; /* unit: nanosecond (maximum 1 hour/pixel) */ +}; + +/* TODO: put that function somewhere else (utils.c) */ +static struct timespec time_add(struct timespec a, struct timespec b) +{ + struct timespec ret; + ret.tv_sec = a.tv_sec + b.tv_sec; + ret.tv_nsec = a.tv_nsec + b.tv_nsec; + if (ret.tv_nsec > 1000000000) { + ret.tv_sec++; + ret.tv_nsec -= 1000000000; + } + return ret; +} + +/* TODO: put that function somewhere else (utils.c) */ +static struct timespec time_sub(struct timespec a, struct timespec b) +{ + struct timespec ret; + if (a.tv_nsec < b.tv_nsec) { + ret.tv_nsec = (int64_t)a.tv_nsec - (int64_t)b.tv_nsec + 1000000000; + ret.tv_sec = a.tv_sec - b.tv_sec - 1; + } else { + ret.tv_nsec = a.tv_nsec - b.tv_nsec; + ret.tv_sec = a.tv_sec - b.tv_sec; + } + return ret; +} + +/* TODO: put that function somewhere else (utils.c) */ +static struct timespec nano_to_time(int64_t n) +{ + struct timespec ret; + ret.tv_sec = n / 1000000000; + ret.tv_nsec = n % 1000000000; + return ret; +} + +/* TODO: put that function somewhere else (utils.c) */ +static int time_cmp(struct timespec a, struct timespec b) +{ + if (a.tv_sec < b.tv_sec) return -1; + if (a.tv_sec > b.tv_sec) return 1; + if (a.tv_nsec < b.tv_nsec) return -1; + if (a.tv_nsec > b.tv_nsec) return 1; + return 0; +} + +static void *time_thread(void *_this) +{ + struct time *this = _this; + int width; + int l; + int i; + int t; + struct timespec tstart; + struct timespec tnext; + struct plot *p; + + while (1) { + if (pthread_mutex_lock(&this->lock)) abort(); + + timeline_get_width(this->g, this->w, &width); + + /* TODO: optimize/cleanup */ + + tnext = time_add(this->latest_time,(struct timespec){tv_sec:0,tv_nsec:1}); + tstart = time_sub(tnext, nano_to_time(this->pixel_length * width)); + + for (l = 0; l < this->subcount; l++) { + for (i = 0; i < width; i++) { + struct timespec tick_start, tick_end; + tick_start = time_add(tstart, nano_to_time(this->pixel_length * i)); + tick_end = time_add(tick_start, nano_to_time(this->pixel_length-1)); + /* if tick is before start, do nothing */ + if (time_cmp(tick_end, + (struct timespec){tv_sec:this->tstart_time,tv_nsec:0}) < 0) + continue; + /* if tick after end, do nothing */ + if (time_cmp(tick_start, + time_add((struct timespec){tv_sec:this->tstart_time,tv_nsec:0}, + nano_to_time(this->pixel_length * width))) >= 0) + continue; + /* look for a nano between tick_start and tick_end */ + /* TODO: optimize */ + for (t = 0; t < this->tsize; t++) { + int n; + time_t current_second = this->tstart_time + t; + time_t next_second = current_second + 1; + struct timespec current_time = + (struct timespec){tv_sec:current_second,tv_nsec:0}; + struct timespec next_time = + (struct timespec){tv_sec:next_second,tv_nsec:0}; + if (time_cmp(tick_end, current_time) < 0) continue; + if (time_cmp(tick_start, next_time) >= 0) continue; + p = &this->t[(this->tstart + t) % this->tsize].p[l]; + for (n = 0; n < p->nanosize; n++) { + struct timespec nano = + (struct timespec){tv_sec:current_second,tv_nsec:p->nano[n]}; + if (time_cmp(tick_start, nano) <= 0 && + time_cmp(nano, tick_end) < 0) + goto gotit; + } + } + continue; +gotit: + /* TODO: only one call */ + timeline_add_points(this->g, this->w, p->line, p->color, &i, 1); + } + } + + if (pthread_mutex_unlock(&this->lock)) abort(); + sleepms(1000 / this->refresh_rate); + } + + return 0; +} + +view *new_view_time(int number_of_seconds, float refresh_rate, + gui *g, widget *w) +{ + struct time *ret = calloc(1, sizeof(struct time)); + if (ret == NULL) abort(); + + ret->refresh_rate = refresh_rate; + ret->g = g; + ret->w = w; + + ret->t = calloc(number_of_seconds, sizeof(struct tick)); + if (ret->t == NULL) abort(); + ret->tsize = number_of_seconds; + ret->tstart = 0; + ret->tstart_time = 0; + ret->subcount = 0; + ret->pixel_length = 10 * 1000000; /* 10ms */ + + if (pthread_mutex_init(&ret->lock, NULL)) abort(); + + new_thread(time_thread, ret); + + return (view *)ret; +} + +/****************************************************************************/ +/* subtimeview */ +/****************************************************************************/ + +struct subtime { + view common; + struct time *parent; + int line; + int color; + int subview; +}; + +static void append(view *_this, struct timespec t) +{ + struct subtime *this = (struct subtime *)_this; + struct time *time = this->parent; + time_t start_time, end_time; + int i, l; + int tpos; + struct plot *p; + + if (pthread_mutex_lock(&time->lock)) abort(); + + start_time = time->tstart_time; + end_time = time->tstart_time + time->tsize - 1; + + /* useless test? */ + if (t.tv_sec < start_time) abort(); + + /* tick out of current window? if yes, move window */ + /* if too far, free all */ + if (end_time - t.tv_sec > time->tsize) { + for (l = 0; l < time->tsize; l++) + for (i = 0; i < time->subcount; i++) { + free(time->t[l].p[i].nano); + time->t[l].p[i].nano = NULL; + time->t[l].p[i].nanosize = 0; + time->t[l].p[i].nanomaxsize = 0; + } + time->tstart = 0; + time->tstart_time = t.tv_sec - (time->tsize-1); + start_time = time->tstart_time; + end_time = time->tstart_time + time->tsize - 1; + } + while (t.tv_sec > end_time) { + for (i = 0; i < time->subcount; i++) { + free(time->t[time->tstart].p[i].nano); + time->t[time->tstart].p[i].nano = NULL; + time->t[time->tstart].p[i].nanosize = 0; + time->t[time->tstart].p[i].nanomaxsize = 0; + } + time->tstart = (time->tstart+1) % time->tsize; + time->tstart_time++; + start_time++; + end_time++; + } + + tpos = (time->tstart + (t.tv_sec - time->tstart_time)) % time->tsize; + p = &time->t[tpos].p[this->subview]; + + /* can we get a new event with <= time than last in list? */ + if (p->nanosize != 0 && t.tv_nsec <= p->nano[p->nanosize-1]) + { printf("%s:%d: possible?\n", __FILE__, __LINE__); abort(); } + + if (p->nanosize == p->nanomaxsize) { + p->nanomaxsize += 4096; + p->nano = realloc(p->nano, p->nanomaxsize * sizeof(long)); + if (p->nano == NULL) abort(); + } + + p->nano[p->nanosize] = t.tv_nsec; + p->nanosize++; + + if (time->latest_time.tv_sec < t.tv_sec || + (time->latest_time.tv_sec == t.tv_sec && + time->latest_time.tv_nsec < t.tv_nsec)) + time->latest_time = t; + + if (pthread_mutex_unlock(&time->lock)) abort(); +} + +view *new_subview_time(view *_time, int line, int color) +{ + int i; + struct time *time = (struct time *)_time; + struct subtime *ret = calloc(1, sizeof(struct subtime)); + if (ret == NULL) abort(); + + ret->common.append = (void (*)(view *, ...))append; + + if (pthread_mutex_lock(&time->lock)) abort(); + + ret->parent = time; + ret->line = line; + ret->color = color; + ret->subview = time->subcount; + + for (i = 0; i < time->tsize; i++) { + time->t[i].p = realloc(time->t[i].p, + (time->subcount + 1) * sizeof(struct plot)); + if (time->t[i].p == NULL) abort(); + time->t[i].p[time->subcount].nano = NULL; + time->t[i].p[time->subcount].nanosize = 0; + time->t[i].p[time->subcount].nanomaxsize = 0; + time->t[i].p[time->subcount].line = line; + time->t[i].p[time->subcount].color = color; + } + + time->subcount++; + + if (pthread_mutex_unlock(&time->lock)) abort(); + + return (view *)ret; +} diff --git a/common/utils/T/tracer/view/view.h b/common/utils/T/tracer/view/view.h index 529e598d09..8d8036721c 100644 --- a/common/utils/T/tracer/view/view.h +++ b/common/utils/T/tracer/view/view.h @@ -17,5 +17,8 @@ view *new_view_xy(int length, float refresh_rate, gui *g, widget *w, int color); view *new_view_tti(float refresh_rate, gui *g, widget *w, int color); +view *new_view_time(int number_of_seconds, float refresh_rate, + gui *g, widget *w); +view *new_subview_time(view *time, int line, int color); #endif /* _VIEW_H_ */ -- GitLab