mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
added warmup phase to histogram for better selection of min/max (closes #12)
This commit is contained in:
parent
49054eef9f
commit
c711f0f1bc
6 changed files with 57 additions and 60 deletions
|
@ -47,6 +47,8 @@ struct hist {
|
|||
int length; /**< The number of buckets in #data. */
|
||||
|
||||
hist_cnt_t total; /**< Total number of counted values. */
|
||||
hist_cnt_t warmup; /**< Number of values which are used during warmup phase. */
|
||||
|
||||
hist_cnt_t higher; /**< The number of values which are higher than #high. */
|
||||
hist_cnt_t lower; /**< The number of values which are lower than #low. */
|
||||
|
||||
|
@ -56,7 +58,7 @@ struct hist {
|
|||
};
|
||||
|
||||
/** Initialize struct hist with supplied values and allocate memory for buckets. */
|
||||
int hist_init(struct hist *h, double start, double end, double resolution);
|
||||
int hist_init(struct hist *h, int buckets, hist_cnt_t warmup);
|
||||
|
||||
/** Free the dynamically allocated memory. */
|
||||
int hist_destroy(struct hist *h);
|
||||
|
|
|
@ -66,7 +66,7 @@ struct stats {
|
|||
struct stats_delta *delta;
|
||||
};
|
||||
|
||||
int stats_init(struct stats *s);
|
||||
int stats_init(struct stats *s, int buckets, int warmup);
|
||||
|
||||
void stats_destroy(struct stats *s);
|
||||
|
||||
|
|
44
lib/hist.c
44
lib/hist.c
|
@ -34,20 +34,12 @@
|
|||
#define VAL(h, i) ((h)->low + (i) * (h)->resolution)
|
||||
#define INDEX(h, v) round((v - (h)->low) / (h)->resolution)
|
||||
|
||||
int hist_init(struct hist *h, double low, double high, double resolution)
|
||||
int hist_init(struct hist *h, int buckets, hist_cnt_t warmup)
|
||||
{
|
||||
h->low = low;
|
||||
h->high = high;
|
||||
h->resolution = resolution;
|
||||
h->length = buckets;
|
||||
h->warmup = warmup;
|
||||
|
||||
if (resolution > 0) {
|
||||
h->length = (high - low) / resolution;
|
||||
h->data = alloc(h->length * sizeof(hist_cnt_t));
|
||||
}
|
||||
else {
|
||||
h->length = 0;
|
||||
h->data = NULL;
|
||||
}
|
||||
h->data = buckets ? alloc(h->length * sizeof(hist_cnt_t)) : NULL;
|
||||
|
||||
hist_reset(h);
|
||||
|
||||
|
@ -66,8 +58,6 @@ int hist_destroy(struct hist *h)
|
|||
|
||||
void hist_put(struct hist *h, double value)
|
||||
{
|
||||
int idx = INDEX(h, value);
|
||||
|
||||
h->last = value;
|
||||
|
||||
/* Update min/max */
|
||||
|
@ -76,13 +66,25 @@ void hist_put(struct hist *h, double value)
|
|||
if (value < h->lowest)
|
||||
h->lowest = value;
|
||||
|
||||
/* Check bounds and increment */
|
||||
if (idx >= h->length)
|
||||
h->higher++;
|
||||
else if (idx < 0)
|
||||
h->lower++;
|
||||
else if (h->data != NULL)
|
||||
h->data[idx]++;
|
||||
if (h->total < h->warmup) {
|
||||
|
||||
}
|
||||
else if (h->total == h->warmup) {
|
||||
h->low = hist_mean(h) - 3 * hist_stddev(h);
|
||||
h->high = hist_mean(h) + 3 * hist_stddev(h);
|
||||
h->resolution = (h->high - h->low) / h->length;
|
||||
}
|
||||
else {
|
||||
int idx = INDEX(h, value);
|
||||
|
||||
/* Check bounds and increment */
|
||||
if (idx >= h->length)
|
||||
h->higher++;
|
||||
else if (idx < 0)
|
||||
h->lower++;
|
||||
else if (h->data != NULL)
|
||||
h->data[idx]++;
|
||||
}
|
||||
|
||||
h->total++;
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ struct stats_collect {
|
|||
|
||||
enum stats_format format;
|
||||
int verbose;
|
||||
int warmup;
|
||||
int buckets;
|
||||
|
||||
FILE *output;
|
||||
const char *uri;
|
||||
|
@ -43,8 +45,6 @@ static int stats_collect_init(struct hook *h)
|
|||
{
|
||||
struct stats_collect *p = h->_vd;
|
||||
|
||||
stats_init(&p->stats);
|
||||
|
||||
/* Register statistic object to path.
|
||||
*
|
||||
* This allows the path code to update statistics. */
|
||||
|
@ -54,6 +54,8 @@ static int stats_collect_init(struct hook *h)
|
|||
/* Set default values */
|
||||
p->format = STATS_FORMAT_HUMAN;
|
||||
p->verbose = 0;
|
||||
p->warmup = 500;
|
||||
p->buckets = 20;
|
||||
p->uri = NULL;
|
||||
p->output = stdout;
|
||||
|
||||
|
@ -73,6 +75,8 @@ static int stats_collect_start(struct hook *h)
|
|||
{
|
||||
struct stats_collect *p = h->_vd;
|
||||
|
||||
stats_init(&p->stats, p->buckets, p->warmup);
|
||||
|
||||
if (p->uri) {
|
||||
p->output = fopen(p->uri, "w+");
|
||||
if (!p->output)
|
||||
|
@ -129,6 +133,8 @@ static int stats_collect_parse(struct hook *h, config_setting_t *cfg)
|
|||
}
|
||||
|
||||
config_setting_lookup_int(cfg, "verbose", &p->verbose);
|
||||
config_setting_lookup_int(cfg, "warmup", &p->warmup);
|
||||
config_setting_lookup_int(cfg, "buckets", &p->buckets);
|
||||
config_setting_lookup_string(cfg, "output", &p->uri);
|
||||
|
||||
return 0;
|
||||
|
@ -164,4 +170,4 @@ static struct plugin p = {
|
|||
|
||||
REGISTER_PLUGIN(&p)
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
|
27
lib/stats.c
27
lib/stats.c
|
@ -33,26 +33,19 @@ static struct stats_desc {
|
|||
const char *name;
|
||||
const char *unit;
|
||||
const char *desc;
|
||||
struct {
|
||||
double min;
|
||||
double max;
|
||||
double resolution;
|
||||
} hist;
|
||||
int hist_buckets;
|
||||
} stats_table[] = {
|
||||
{ "skipped", "samples", "skipped samples by hooks", {0, 0, -1, }},
|
||||
{ "reorderd", "samples", "reordered samples", {0, 20, 1, }},
|
||||
{ "gap_sequence", "samples", "sequence number displacement of received messages", {-10, 10, 20, }},
|
||||
{ "gap_sample", "seconds", "inter message timestamps (as sent by remote)", {90e-3, 110e-3, 1e-3, }},
|
||||
{ "gap_received", "seconds", "Histogram for inter message arrival time (as seen by this instance)", {90e-3, 110e-3, 1e-3, }},
|
||||
{ "owd", "seconds", "Histogram for one-way-delay (OWD) of received messages", {0, 1, 100e-3, }}
|
||||
{ "skipped", "samples", "skipped samples by hooks", 25 },
|
||||
{ "reorderd", "samples", "reordered samples", 25 },
|
||||
{ "gap_sample", "seconds", "inter message timestamps (as sent by remote)", 25 },
|
||||
{ "gap_received", "seconds", "Histogram for inter message arrival time (as seen by this instance)", 25 },
|
||||
{ "owd", "seconds", "Histogram for one-way-delay (OWD) of received messages", 25 }
|
||||
};
|
||||
|
||||
int stats_init(struct stats *s)
|
||||
int stats_init(struct stats *s, int buckets, int warmup)
|
||||
{
|
||||
for (int i = 0; i < STATS_COUNT; i++) {
|
||||
struct stats_desc *desc = &stats_table[i];
|
||||
hist_init(&s->histograms[i], desc->hist.min, desc->hist.max, desc->hist.resolution);
|
||||
}
|
||||
for (int i = 0; i < STATS_COUNT; i++)
|
||||
hist_init(&s->histograms[i], buckets, warmup);
|
||||
|
||||
s->delta = alloc(sizeof(struct stats_delta));
|
||||
|
||||
|
@ -245,4 +238,4 @@ enum stats_id stats_lookup_id(const char *name)
|
|||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@ static struct node *node;
|
|||
static int running = 1; /**< Initiate shutdown if zero */
|
||||
static int count = -1; /**< Amount of messages which should be sent (default: -1 for unlimited) */
|
||||
|
||||
static hist_cnt_t hist_warmup;
|
||||
static int hist_buckets;
|
||||
|
||||
/** File descriptor for Matlab results.
|
||||
* This allows you to write Matlab results in a seperate log file:
|
||||
*
|
||||
|
@ -50,11 +53,6 @@ static int count = -1; /**< Amount of messages which should be sent (default:
|
|||
*/
|
||||
static int fd = STDOUT_FILENO;
|
||||
|
||||
/* Histogram */
|
||||
static double low = 0; /**< Lowest value in histogram. */
|
||||
static double high = 2e-4; /**< Highest value in histogram. */
|
||||
static double res = 1e-5; /**< Histogram resolution. */
|
||||
|
||||
#define CLOCK_ID CLOCK_MONOTONIC
|
||||
|
||||
/* Prototypes */
|
||||
|
@ -73,9 +71,8 @@ void usage()
|
|||
printf(" OPTIONS is one or more of the following options:\n");
|
||||
printf(" -c CNT send CNT messages\n");
|
||||
printf(" -f FD use file descriptor FD for result output instead of stdout\n");
|
||||
printf(" -l LOW smallest value for histogram\n");
|
||||
printf(" -H HIGH largest value for histogram\n");
|
||||
printf(" -r RES bucket resolution for histogram\n");
|
||||
printf(" -b BKTS number of buckets for histogram\n");
|
||||
printf(" -w WMUP duration of histogram warmup phase\n");
|
||||
printf(" -h show this usage information\n");
|
||||
printf("\n");
|
||||
|
||||
|
@ -86,7 +83,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
/* Parse Arguments */
|
||||
char c, *endptr;
|
||||
while ((c = getopt (argc, argv, "l:hH:r:f:c:")) != -1) {
|
||||
while ((c = getopt (argc, argv, "w:h:r:f:c:b:")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
count = strtoul(optarg, &endptr, 10);
|
||||
|
@ -94,14 +91,11 @@ int main(int argc, char *argv[])
|
|||
case 'f':
|
||||
fd = strtoul(optarg, &endptr, 10);
|
||||
goto check;
|
||||
case 'l':
|
||||
low = strtod(optarg, &endptr);
|
||||
case 'w':
|
||||
hist_warmup = strtoul(optarg, &endptr, 10);
|
||||
goto check;
|
||||
case 'H':
|
||||
high = strtod(optarg, &endptr);
|
||||
goto check;
|
||||
case 'r':
|
||||
res = strtod(optarg, &endptr);
|
||||
case 'b':
|
||||
hist_buckets = strtoul(optarg, &endptr, 10);
|
||||
goto check;
|
||||
case 'h':
|
||||
case '?':
|
||||
|
@ -157,7 +151,7 @@ void test_rtt() {
|
|||
struct sample *smp_send = alloc(SAMPLE_LEN(2));
|
||||
struct sample *smp_recv = alloc(SAMPLE_LEN(2));
|
||||
|
||||
hist_init(&hist, low, high, res);
|
||||
hist_init(&hist, 20, 100);
|
||||
|
||||
/* Print header */
|
||||
fprintf(stdout, "%17s%5s%10s%10s%10s%10s%10s\n", "timestamp", "seq", "rtt", "min", "max", "mean", "stddev");
|
||||
|
|
Loading…
Add table
Reference in a new issue