bugfix/improve/simplify view/time.c
This commit is contained in:
@@ -157,24 +157,24 @@ static void enb_main_gui(gui *g, event_handler *h, void *database)
|
|||||||
timeview = new_view_time(3600, 10, g, timeline_plot);
|
timeview = new_view_time(3600, 10, g, timeline_plot);
|
||||||
/* tick logging */
|
/* tick logging */
|
||||||
timelog = new_timelog(h, database, "ENB_DL_TICK");
|
timelog = new_timelog(h, database, "ENB_DL_TICK");
|
||||||
subview = new_subview_time(timeview, 0, FOREGROUND_COLOR);
|
subview = new_subview_time(timeview, 0, FOREGROUND_COLOR, 3600*1000);
|
||||||
logger_add_view(timelog, subview);
|
logger_add_view(timelog, subview);
|
||||||
/* DCI logging */
|
/* DCI logging */
|
||||||
timelog = new_timelog(h, database, "ENB_DLSCH_UE_DCI");
|
timelog = new_timelog(h, database, "ENB_DLSCH_UE_DCI");
|
||||||
subview = new_subview_time(timeview, 1, new_color(g, "#228"));
|
subview = new_subview_time(timeview, 1, new_color(g, "#228"), 3600*1000);
|
||||||
logger_add_view(timelog, subview);
|
logger_add_view(timelog, subview);
|
||||||
/* ACK */
|
/* ACK */
|
||||||
timelog = new_timelog(h, database, "ENB_DLSCH_UE_ACK");
|
timelog = new_timelog(h, database, "ENB_DLSCH_UE_ACK");
|
||||||
subview = new_subview_time(timeview, 2, new_color(g, "#282"));
|
subview = new_subview_time(timeview, 2, new_color(g, "#282"), 3600*1000);
|
||||||
logger_add_view(timelog, subview);
|
logger_add_view(timelog, subview);
|
||||||
/* NACK */
|
/* NACK */
|
||||||
timelog = new_timelog(h, database, "ENB_DLSCH_UE_NACK");
|
timelog = new_timelog(h, database, "ENB_DLSCH_UE_NACK");
|
||||||
subview = new_subview_time(timeview, 3, new_color(g, "#f22"));
|
subview = new_subview_time(timeview, 3, new_color(g, "#f22"), 3600*1000);
|
||||||
logger_add_view(timelog, subview);
|
logger_add_view(timelog, subview);
|
||||||
|
|
||||||
/* uplink UE DCIs */
|
/* uplink UE DCIs */
|
||||||
timelog = new_timelog(h, database, "ENB_UL_TICK");
|
timelog = new_timelog(h, database, "ENB_UL_TICK");
|
||||||
subview = new_subview_time(timeview, 4, FOREGROUND_COLOR);
|
subview = new_subview_time(timeview, 4, FOREGROUND_COLOR, 3600*1000);
|
||||||
logger_add_view(timelog, subview);
|
logger_add_view(timelog, subview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,35 +10,24 @@
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
struct plot {
|
struct plot {
|
||||||
long *nano;
|
struct timespec *tick;
|
||||||
int nanosize;
|
int ticksize;
|
||||||
int nanomaxsize;
|
int tickmaxsize;
|
||||||
|
int tickstart;
|
||||||
int line;
|
int line;
|
||||||
int color;
|
int color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tick {
|
|
||||||
struct plot *p; /* one plot per subview,
|
|
||||||
* so size is 'subcount'
|
|
||||||
* (see in struct time below)
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
struct time {
|
struct time {
|
||||||
view common;
|
view common;
|
||||||
gui *g;
|
gui *g;
|
||||||
widget *w;
|
widget *w;
|
||||||
float refresh_rate;
|
float refresh_rate;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
struct tick *t; /* t is a circular list
|
struct plot *p;
|
||||||
* a tick lasts one second
|
int psize;
|
||||||
*/
|
|
||||||
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 */
|
|
||||||
double pixel_length; /* unit: nanosecond (maximum 1 hour/pixel) */
|
double pixel_length; /* unit: nanosecond (maximum 1 hour/pixel) */
|
||||||
|
struct timespec latest_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: put that function somewhere else (utils.c) */
|
/* TODO: put that function somewhere else (utils.c) */
|
||||||
@@ -87,13 +76,33 @@ static int time_cmp(struct timespec a, struct timespec b)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int interval_empty(struct time *this, int sub,
|
||||||
|
struct timespec start, struct timespec end)
|
||||||
|
{
|
||||||
|
int a, b, mid;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (this->p[sub].ticksize == 0) return 1;
|
||||||
|
|
||||||
|
/* look for a tick larger than start and smaller than end */
|
||||||
|
a = 0;
|
||||||
|
b = this->p[sub].ticksize - 1;
|
||||||
|
while (b >= a) {
|
||||||
|
mid = (a+b) / 2;
|
||||||
|
i = (this->p[sub].tickstart + mid) % this->p[sub].ticksize;
|
||||||
|
if (time_cmp(this->p[sub].tick[i], start) < 0) a = mid + 1;
|
||||||
|
else if (time_cmp(this->p[sub].tick[i], end) > 0) b = mid - 1;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void *time_thread(void *_this)
|
static void *time_thread(void *_this)
|
||||||
{
|
{
|
||||||
struct time *this = _this;
|
struct time *this = _this;
|
||||||
int width;
|
int width;
|
||||||
int l;
|
int l;
|
||||||
int i;
|
int i;
|
||||||
int t;
|
|
||||||
struct timespec tstart;
|
struct timespec tstart;
|
||||||
struct timespec tnext;
|
struct timespec tnext;
|
||||||
struct plot *p;
|
struct plot *p;
|
||||||
@@ -105,7 +114,7 @@ static void *time_thread(void *_this)
|
|||||||
timeline_get_width(this->g, this->w, &width);
|
timeline_get_width(this->g, this->w, &width);
|
||||||
timeline_clear_silent(this->g, this->w);
|
timeline_clear_silent(this->g, this->w);
|
||||||
|
|
||||||
/* TODO: optimize/cleanup */
|
/* TODO: optimize? */
|
||||||
|
|
||||||
/* use rounded pixel_length */
|
/* use rounded pixel_length */
|
||||||
pixel_length = this->pixel_length;
|
pixel_length = this->pixel_length;
|
||||||
@@ -113,34 +122,14 @@ static void *time_thread(void *_this)
|
|||||||
tnext = time_add(this->latest_time,(struct timespec){tv_sec:0,tv_nsec:1});
|
tnext = time_add(this->latest_time,(struct timespec){tv_sec:0,tv_nsec:1});
|
||||||
tstart = time_sub(tnext, nano_to_time(pixel_length * width));
|
tstart = time_sub(tnext, nano_to_time(pixel_length * width));
|
||||||
|
|
||||||
for (l = 0; l < this->subcount; l++) {
|
for (l = 0; l < this->psize; l++) {
|
||||||
for (i = 0; i < width; i++) {
|
for (i = 0; i < width; i++) {
|
||||||
struct timespec tick_start, tick_end;
|
struct timespec tick_start, tick_end;
|
||||||
tick_start = time_add(tstart, nano_to_time(pixel_length * i));
|
tick_start = time_add(tstart, nano_to_time(pixel_length * i));
|
||||||
tick_end = time_add(tick_start, nano_to_time(pixel_length-1));
|
tick_end = time_add(tick_start, nano_to_time(pixel_length-1));
|
||||||
/* look for a nano between tick_start and tick_end */
|
if (interval_empty(this, l, tick_start, tick_end))
|
||||||
/* TODO: optimize */
|
continue;
|
||||||
for (t = 0; t < this->tsize; t++) {
|
p = &this->p[l];
|
||||||
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 */
|
/* TODO: only one call */
|
||||||
timeline_add_points_silent(this->g, this->w, p->line, p->color, &i, 1);
|
timeline_add_points_silent(this->g, this->w, p->line, p->color, &i, 1);
|
||||||
}
|
}
|
||||||
@@ -200,13 +189,11 @@ view *new_view_time(int number_of_seconds, float refresh_rate,
|
|||||||
ret->g = g;
|
ret->g = g;
|
||||||
ret->w = w;
|
ret->w = w;
|
||||||
|
|
||||||
ret->t = calloc(number_of_seconds, sizeof(struct tick));
|
ret->p = NULL;
|
||||||
if (ret->t == NULL) abort();
|
ret->psize = 0;
|
||||||
ret->tsize = number_of_seconds;
|
|
||||||
ret->tstart = 0;
|
/* default pixel length: 10ms */
|
||||||
ret->tstart_time = 0;
|
ret->pixel_length = 10 * 1000000;
|
||||||
ret->subcount = 0;
|
|
||||||
ret->pixel_length = 10 * 1000000; /* 10ms */
|
|
||||||
|
|
||||||
register_notifier(g, "scrollup", w, scroll, ret);
|
register_notifier(g, "scrollup", w, scroll, ret);
|
||||||
register_notifier(g, "scrolldown", w, scroll, ret);
|
register_notifier(g, "scrolldown", w, scroll, ret);
|
||||||
@@ -234,74 +221,26 @@ static void append(view *_this, struct timespec t)
|
|||||||
{
|
{
|
||||||
struct subtime *this = (struct subtime *)_this;
|
struct subtime *this = (struct subtime *)_this;
|
||||||
struct time *time = this->parent;
|
struct time *time = this->parent;
|
||||||
time_t start_time, end_time;
|
struct plot *p = &time->p[this->subview];
|
||||||
int i, l;
|
|
||||||
int tpos;
|
|
||||||
struct plot *p;
|
|
||||||
|
|
||||||
if (pthread_mutex_lock(&time->lock)) abort();
|
if (pthread_mutex_lock(&time->lock)) abort();
|
||||||
|
|
||||||
start_time = time->tstart_time;
|
if (p->ticksize < p->tickmaxsize) {
|
||||||
end_time = time->tstart_time + time->tsize - 1;
|
p->tick[p->ticksize] = t;
|
||||||
|
p->ticksize++;
|
||||||
/* useless test? */
|
} else {
|
||||||
if (t.tv_sec < start_time) abort();
|
p->tick[p->tickstart] = t;
|
||||||
|
p->tickstart = (p->tickstart + 1) % p->ticksize;
|
||||||
/* tick out of current window? if yes, move window */
|
|
||||||
/* if too far, free all */
|
|
||||||
if (t.tv_sec > end_time && t.tv_sec - end_time > 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;
|
if (time_cmp(time->latest_time, t) < 0)
|
||||||
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;
|
time->latest_time = t;
|
||||||
|
|
||||||
if (pthread_mutex_unlock(&time->lock)) abort();
|
if (pthread_mutex_unlock(&time->lock)) abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
view *new_subview_time(view *_time, int line, int color)
|
view *new_subview_time(view *_time, int line, int color, int size)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct time *time = (struct time *)_time;
|
struct time *time = (struct time *)_time;
|
||||||
struct subtime *ret = calloc(1, sizeof(struct subtime));
|
struct subtime *ret = calloc(1, sizeof(struct subtime));
|
||||||
if (ret == NULL) abort();
|
if (ret == NULL) abort();
|
||||||
@@ -313,20 +252,20 @@ view *new_subview_time(view *_time, int line, int color)
|
|||||||
ret->parent = time;
|
ret->parent = time;
|
||||||
ret->line = line;
|
ret->line = line;
|
||||||
ret->color = color;
|
ret->color = color;
|
||||||
ret->subview = time->subcount;
|
ret->subview = time->psize;
|
||||||
|
|
||||||
for (i = 0; i < time->tsize; i++) {
|
time->p = realloc(time->p,
|
||||||
time->t[i].p = realloc(time->t[i].p,
|
(time->psize + 1) * sizeof(struct plot));
|
||||||
(time->subcount + 1) * sizeof(struct plot));
|
if (time->p == NULL) abort();
|
||||||
if (time->t[i].p == NULL) abort();
|
time->p[time->psize].tick = calloc(size, sizeof(struct timespec));
|
||||||
time->t[i].p[time->subcount].nano = NULL;
|
if (time->p[time->psize].tick == NULL) abort();
|
||||||
time->t[i].p[time->subcount].nanosize = 0;
|
time->p[time->psize].ticksize = 0;
|
||||||
time->t[i].p[time->subcount].nanomaxsize = 0;
|
time->p[time->psize].tickmaxsize = size;
|
||||||
time->t[i].p[time->subcount].line = line;
|
time->p[time->psize].tickstart = 0;
|
||||||
time->t[i].p[time->subcount].color = color;
|
time->p[time->psize].line = line;
|
||||||
}
|
time->p[time->psize].color = color;
|
||||||
|
|
||||||
time->subcount++;
|
time->psize++;
|
||||||
|
|
||||||
if (pthread_mutex_unlock(&time->lock)) abort();
|
if (pthread_mutex_unlock(&time->lock)) abort();
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ view *new_view_tti(float refresh_rate, gui *g, widget *w,
|
|||||||
int color);
|
int color);
|
||||||
view *new_view_time(int number_of_seconds, float refresh_rate,
|
view *new_view_time(int number_of_seconds, float refresh_rate,
|
||||||
gui *g, widget *w);
|
gui *g, widget *w);
|
||||||
view *new_subview_time(view *time, int line, int color);
|
view *new_subview_time(view *time, int line, int color, int size);
|
||||||
|
|
||||||
#endif /* _VIEW_H_ */
|
#endif /* _VIEW_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user