mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
more improvements to make statistic subsystem extensible
This commit is contained in:
parent
b23484550f
commit
735f08f551
3 changed files with 124 additions and 78 deletions
|
@ -23,20 +23,24 @@ struct sample;
|
|||
struct path;
|
||||
struct node;
|
||||
|
||||
struct stats {
|
||||
struct {
|
||||
uintmax_t invalid; /**< Counter for invalid messages */
|
||||
uintmax_t skipped; /**< Counter for skipped messages due to hooks */
|
||||
uintmax_t dropped; /**< Counter for dropped messages due to reordering */
|
||||
} counter;
|
||||
enum stats_id {
|
||||
STATS_INVALID, /**< Counter for invalid messages */
|
||||
STATS_SKIPPED, /**< Counter for skipped messages due to hooks */
|
||||
STATS_DROPPED, /**< Counter for dropped messages due to reordering */
|
||||
STATS_GAP_SEQUENCE, /**< Histogram of sequence number displacement of received messages */
|
||||
STATS_GAP_SAMPLE, /**< Histogram for inter message timestamps (as sent by remote) */
|
||||
STATS_GAP_RECEIVED, /**< Histogram for inter message arrival time (as seen by this instance) */
|
||||
STATS_OWD, /**< Histogram for one-way-delay (OWD) of received messages */
|
||||
STATS_COUNT /**< Just here to have an updated number of statistics */
|
||||
};
|
||||
|
||||
struct stats_delta {
|
||||
double vals[STATS_COUNT];
|
||||
};
|
||||
|
||||
struct stats {
|
||||
struct hist histograms[STATS_COUNT];
|
||||
|
||||
struct {
|
||||
struct hist owd; /**< Histogram for one-way-delay (OWD) of received messages */
|
||||
struct hist gap_msg; /**< Histogram for inter message timestamps (as sent by remote) */
|
||||
struct hist gap_recv; /**< Histogram for inter message arrival time (as seen by this instance) */
|
||||
struct hist gap_seq; /**< Histogram of sequence number displacement of received messages */
|
||||
} histogram;
|
||||
|
||||
struct sample *last;
|
||||
};
|
||||
|
||||
|
@ -44,8 +48,14 @@ int stats_init(struct stats *s);
|
|||
|
||||
void stats_destroy(struct stats *s);
|
||||
|
||||
void stats_update(struct stats *s, enum stats_id id, double val);
|
||||
|
||||
int stats_commit(struct stats *s, struct stats_delta *d);
|
||||
|
||||
void stats_collect(struct stats *s, struct sample *smps[], size_t cnt);
|
||||
|
||||
void stats_decollect(struct stats *s, struct sample *smps[], size_t cnt);
|
||||
|
||||
#ifdef WITH_JANSSON
|
||||
json_t * stats_json(struct stats *s);
|
||||
#endif
|
||||
|
@ -56,7 +66,7 @@ void stats_print_header();
|
|||
|
||||
void stats_print_periodic(struct stats *s, struct path *p);
|
||||
|
||||
void stats_print(struct stats *s);
|
||||
void stats_print(struct stats *s, int details);
|
||||
|
||||
void stats_send(struct stats *s, struct node *n);
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ int hook_drop(struct hook *h, int when, struct hook_info *j)
|
|||
if (h->prev) {
|
||||
dist = h->last->sequence - (int32_t) h->prev->sequence;
|
||||
if (dist <= 0) {
|
||||
j->path->stats->counter.dropped++;
|
||||
stats_update(j->path->stats, STATS_DROPPED, dist);
|
||||
warn("Dropped sample: dist = %d, i = %d", dist, i);
|
||||
}
|
||||
else {
|
||||
|
|
162
lib/stats.c
162
lib/stats.c
|
@ -13,38 +13,81 @@
|
|||
#include "sample.h"
|
||||
#include "log.h"
|
||||
|
||||
static struct stats_desc {
|
||||
const char *name;
|
||||
const char *unit;
|
||||
const char *desc;
|
||||
struct {
|
||||
double min;
|
||||
double max;
|
||||
double resolution;
|
||||
} hist;
|
||||
} stats_table[] = {
|
||||
{ "invalid", "", "invalid messages", {0, 0, -1, }},
|
||||
{ "skipped", "", "skipped messages by hooks", {0, 0, -1, }},
|
||||
{ "dropped", "", "dropped messages because of reordering", {0, 0, -1, }},
|
||||
{ "gap_sequence", "", "sequence number displacement of received messages", {-10, 10, 20, }},
|
||||
{ "gap_sample", "", "inter message timestamps (as sent by remote)", {90e-3, 110e-3, 1e-3, }},
|
||||
{ "gap_received", "", "Histogram for inter message arrival time (as seen by this instance)", {90e-3, 110e-3, 1e-3, }},
|
||||
{ "owd", "s", "Histogram for one-way-delay (OWD) of received messages", {0, 1, 100e-3, }}
|
||||
};
|
||||
|
||||
int stats_init(struct stats *s)
|
||||
{
|
||||
/** @todo Allow configurable bounds for histograms */
|
||||
hist_create(&s->histogram.owd, 0, 1, 100e-3);
|
||||
hist_create(&s->histogram.gap_msg, 90e-3, 110e-3, 1e-3);
|
||||
hist_create(&s->histogram.gap_recv, 90e-3, 110e-3, 1e-3);
|
||||
hist_create(&s->histogram.gap_seq, -HIST_SEQ, +HIST_SEQ, 1);
|
||||
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
struct stats_desc *desc = &stats_table[i];
|
||||
hist_create(&s->histograms[i], desc->hist.min, desc->hist.max, desc->hist.resolution);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stats_destroy(struct stats *s)
|
||||
{
|
||||
hist_destroy(&s->histogram.owd);
|
||||
hist_destroy(&s->histogram.gap_msg);
|
||||
hist_destroy(&s->histogram.gap_recv);
|
||||
hist_destroy(&s->histogram.gap_seq);
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
hist_destroy(&s->histograms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void stats_update(struct stats *s, enum stats_id id, double val)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
hist_put(&s->histograms[id], val);
|
||||
}
|
||||
|
||||
#if 0
|
||||
int stats_delta(struct stats_delta *d, struct sample *s, struct sample *p)
|
||||
{
|
||||
d->histogram.owd = time_delta(&smps[i]->ts.origin, &smps[i]->ts.received);
|
||||
d->histogram.gap = time_delta(&s->last->ts.origin, &smps[i]->ts.origin);
|
||||
d->histogram.gap_seq = s->sequence - (int32_t) p->sequence;
|
||||
d->histogram.gap_recv = time_delta(&s->last->ts.received, &smps[i]->ts.received);
|
||||
|
||||
d->counter.dropped = d->histogram.gap_seq <= 0 ? 1 : 0;
|
||||
d->counter.invalid = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int stats_commit(struct stats *s, struct stats_delta *d)
|
||||
{
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
hist_put(&s->histograms[i], d->vals[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stats_collect(struct stats *s, struct sample *smps[], size_t cnt)
|
||||
{
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (s->last) {
|
||||
int gap_seq = smps[i]->sequence - (int32_t) s->last->sequence;
|
||||
double owd = time_delta(&smps[i]->ts.origin, &smps[i]->ts.received);
|
||||
double gap = time_delta(&s->last->ts.origin, &smps[i]->ts.origin);
|
||||
double gap_recv = time_delta(&s->last->ts.received, &smps[i]->ts.received);
|
||||
|
||||
hist_put(&s->histogram.owd, owd);
|
||||
hist_put(&s->histogram.gap_msg, gap);
|
||||
hist_put(&s->histogram.gap_seq, gap_seq);
|
||||
hist_put(&s->histogram.gap_recv, gap_recv);
|
||||
// struct stats_delta d;
|
||||
// stats_get_delta(&d, smps[i], s->last);
|
||||
// stats_commit(s, &d);
|
||||
}
|
||||
|
||||
if (i == 0 && s->last)
|
||||
|
@ -59,30 +102,25 @@ void stats_collect(struct stats *s, struct sample *smps[], size_t cnt)
|
|||
#ifdef WITH_JANSSON
|
||||
json_t * stats_json(struct stats *s)
|
||||
{
|
||||
return json_pack("{ s: { s: i, s: i, s: i }, s: { s: o, s: o, s: o } }",
|
||||
"counter",
|
||||
"dropped", s->counter.dropped,
|
||||
"invalid", s->counter.invalid,
|
||||
"skipped", s->counter.skipped,
|
||||
"histogram",
|
||||
"owd", hist_json(&s->histogram.owd),
|
||||
"gap_msg", hist_json(&s->histogram.gap_msg),
|
||||
"gap_recv",hist_json(&s->histogram.gap_recv),
|
||||
"gap_seq", hist_json(&s->histogram.gap_seq)
|
||||
);
|
||||
json_t *obj = json_object();
|
||||
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
struct stats_desc *desc = &stats_table[i];
|
||||
|
||||
json_t *stats = hist_json(&s->histograms[i]);
|
||||
|
||||
json_object_set(obj, desc->name, stats);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
void stats_reset(struct stats *s)
|
||||
{
|
||||
s->counter.invalid =
|
||||
s->counter.skipped =
|
||||
s->counter.dropped = 0;
|
||||
|
||||
hist_reset(&s->histogram.owd);
|
||||
hist_reset(&s->histogram.gap_seq);
|
||||
hist_reset(&s->histogram.gap_msg);
|
||||
hist_reset(&s->histogram.gap_recv);
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
hist_reset(&s->histograms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void stats_print_header()
|
||||
|
@ -101,41 +139,39 @@ void stats_print_header()
|
|||
|
||||
void stats_print_periodic(struct stats *s, struct path *p)
|
||||
{
|
||||
stats("%-40.40s|%10s|%10s|%10ju|%10ju|%10ju|", path_name(p), "", "",
|
||||
s->counter.dropped, s->counter.skipped, s->counter.invalid);
|
||||
stats("%-40.40s|%10f|%10f|%10ju|%10ju|%10ju|", path_name(p),
|
||||
s->histograms[STATS_OWD].last,
|
||||
1.0 / s->histograms[STATS_GAP_SAMPLE].last,
|
||||
s->histograms[STATS_DROPPED].total,
|
||||
s->histograms[STATS_SKIPPED].total,
|
||||
s->histograms[STATS_INVALID].total
|
||||
);
|
||||
}
|
||||
|
||||
void stats_print(struct stats *s)
|
||||
void stats_print(struct stats *s, int details)
|
||||
{
|
||||
stats("Dropped samples: %ju", s->counter.dropped);
|
||||
stats("Skipped samples: %ju", s->counter.skipped);
|
||||
stats("Invalid samples: %ju", s->counter.invalid);
|
||||
|
||||
stats("One-way delay:");
|
||||
hist_print(&s->histogram.owd);
|
||||
|
||||
stats("Inter-message arrival time:");
|
||||
hist_print(&s->histogram.gap_recv);
|
||||
|
||||
stats("Inter-message ts gap:");
|
||||
hist_print(&s->histogram.gap_msg);
|
||||
|
||||
stats("Inter-message sequence number gaps:");
|
||||
hist_print(&s->histogram.gap_seq);
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
struct stats_desc *desc = &stats_table[i];
|
||||
|
||||
stats("%s: %s", desc->name, desc->desc);
|
||||
hist_print(&s->histograms[i], details);
|
||||
}
|
||||
}
|
||||
|
||||
void stats_send(struct stats *s, struct node *n)
|
||||
{
|
||||
char buf[SAMPLE_LEN(16)];
|
||||
char buf[SAMPLE_LEN(STATS_COUNT * 5)];
|
||||
struct sample *smp = (struct sample *) buf;
|
||||
|
||||
int i = 0;
|
||||
smp->data[i++].f = s->counter.invalid; /**< Use integer here? */
|
||||
smp->data[i++].f = s->counter.skipped;
|
||||
smp->data[i++].f = s->counter.dropped;
|
||||
smp->data[i++].f = s->histogram.owd.last,
|
||||
smp->data[i++].f = 1.0 / s->histogram.gap_msg.last;
|
||||
smp->data[i++].f = 1.0 / s->histogram.gap_recv.last;
|
||||
|
||||
for (int j = 0; j < STATS_COUNT; j++) {
|
||||
smp->data[i++].f = s->histograms[j].last;
|
||||
smp->data[i++].f = s->histograms[j].highest;
|
||||
smp->data[i++].f = s->histograms[j].lowest;
|
||||
smp->data[i++].f = hist_mean(&s->histograms[j]);
|
||||
smp->data[i++].f = hist_var(&s->histograms[j]);
|
||||
}
|
||||
smp->length = i;
|
||||
|
||||
node_write(n, &smp, 1); /* Send single message with statistics to destination node */
|
||||
|
|
Loading…
Add table
Reference in a new issue