0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 15:41:54 +00:00

Stats min/max settle time by using settle timer

This commit is contained in:
Vojtech Vilimek 2022-07-26 14:54:22 +02:00
parent 84a7cb1c60
commit 0f8e23100e
5 changed files with 129 additions and 145 deletions

View File

@ -476,7 +476,7 @@
INST(FI_COUNTER, 0, 1) { INST(FI_COUNTER, 0, 1) {
SYMBOL; SYMBOL;
NEVER_CONSTANT; NEVER_CONSTANT;
RESULT(T_INT, i, get_stats_sum(sym)); RESULT(T_INT, i, get_stats_counter(sym));
} }
INST(FI_CONSTANT, 0, 1) { INST(FI_CONSTANT, 0, 1) {

View File

@ -43,7 +43,7 @@
#include "filter/filter.h" #include "filter/filter.h"
#include "filter/f-inst.h" #include "filter/f-inst.h"
#include "filter/data.h" #include "filter/data.h"
#include "proto/stats/stats.h" /* provides function get_stats_sum used in f-inst.c */ #include "proto/stats/stats.h" /* provides function get_stats_counter() used in f-inst.c */
/* Exception bits */ /* Exception bits */

View File

@ -37,24 +37,21 @@ stats_channel_opt_list:
| '{' stats_opts '}' | '{' stats_opts '}'
; ;
stats_opt:
channel_max_gen: type symbol '=' term {
MAX GENERATION expr { struct f_val val;
if ($3 > 254) cf_error("Max generation must be in range 0..254, got %u", $3); if (f_eval(f_linearize($4), &val) > F_RETURN) cf_error("Runtime error");
STATS_CC->max_generation = $3; if (val.type != $1) cf_error("The expresion does not match defined type");
} /* cf_define_symbol($2, SYM_VARIABLE | $1, val )*/
}
| MIN SETTLE TIME expr_us { STATS_CC->min_settle_time = $4; }
| MAX SETTLE TIME expr_us { STATS_CC->max_settle_time = $4; }
; ;
stats_settle:
SETTLE TIME time {
STATS_CC->settle = $3 S_;
}
stats_opts: stats_opts:
/* empty */ /* empty */
| stats_opts channel_item ';' | stats_opts channel_item ';'
| stats_opts channel_max_gen ';' | stats_opts stats_opt ';'
| stats_opts stats_settle ';'
; ;
stats_proto_channel: stats_channel_start stats_channel_opt_list channel_end ; stats_proto_channel: stats_channel_start stats_channel_opt_list channel_end ;
@ -62,8 +59,8 @@ stats_proto_channel: stats_channel_start stats_channel_opt_list channel_end ;
stats_channel_start: net_type symbol stats_channel_start: net_type symbol
{ {
this_channel = channel_config_get(&channel_stats, $2->name, $1, this_proto); this_channel = channel_config_get(&channel_stats, $2->name, $1, this_proto);
STATS_CC->max_generation = 16; STATS_CC->min_settle_time = 1 S_;
STATS_CC->settle = 5 S_; STATS_CC->max_settle_time = 20 S_;
$2 = cf_define_symbol($2, SYM_COUNTER, ch_config, this_channel); $2 = cf_define_symbol($2, SYM_COUNTER, ch_config, this_channel);
} }

View File

@ -26,9 +26,7 @@
#include "stats.h" #include "stats.h"
#define COUNTER 255 static void stats_settle_timer(struct settle_timer *st);
static void stats_kick_timer(struct stats_channel *c);
static void static void
stats_rt_notify(struct proto *P UNUSED, struct channel *src_ch, const net_addr *n UNUSED, rte *new, const rte *old) stats_rt_notify(struct proto *P UNUSED, struct channel *src_ch, const net_addr *n UNUSED, rte *new, const rte *old)
@ -36,60 +34,54 @@ stats_rt_notify(struct proto *P UNUSED, struct channel *src_ch, const net_addr *
struct stats_channel *ch = (void *) src_ch; struct stats_channel *ch = (void *) src_ch;
int changed = 0; int changed = 0;
if (old) if (new && old)
/* count of exported routes stays the same */
log(L_INFO "nothing happen - no change of counter");
else if (!old)
{ {
ch->counters[old->generation]--; log(L_INFO "increasing _counter");
if (old->generation <= ch->max_generation) ch->_counter++;
{ changed = 1;
changed = 1; if (ch->_counter > 100)
ch->counters[COUNTER]--; log(L_INFO "underflow?");
} }
} else if (!new)
{
if (new) log(L_INFO "decreasing _counter");
{ ch->_counter--;
ch->counters[new->generation]++; changed = 1;
if (new->generation <= ch->max_generation) if (ch->_counter > 100)
{ log(L_INFO "underflow? - ");
changed = 1; }
ch->counters[COUNTER]++; else /* shouldn't happen */
} {
log(L_INFO "BUG is here !!!");
bug("Both pointers *new and *old in rt_notify are NULL");
} }
log(L_INFO "stats channel %s: preparing to kick the timer %d", src_ch->name,
changed);
if (changed) if (changed)
{ {
log(L_INFO "stats: timer kicked with time %u", ch->settle); settle_timer_changed(ch->settle_timer);
stats_kick_timer((struct stats_channel *) ch); kick_settle_timer(ch->settle_timer);
} }
} }
static void static void
stats_reload_routes(struct channel *C UNUSED) stats_reload_routes(struct channel *C)
{ {
/* Route reload on one channel is just refeed on the other */ // TODO
//channel_request_feeding(p->c); struct stats_channel *c = (void *) C;
}
static void c->_counter = c->counter = 0;
stats_configure_channels(struct proto *P, struct proto_config *CF) channel_request_feeding(C);
{
struct channel_config *cc;
WALK_LIST(cc, CF->channels)
{
struct channel *c = NULL;
proto_configure_channel(P, &c, cc);
struct stats_channel *sc = (void *) c;
struct stats_channel_config *scc = (void *) cc;
sc->max_generation = scc->max_generation;
sc->settle = scc->settle;
}
} }
static struct proto * static struct proto *
stats_init(struct proto_config *CF) stats_init(struct proto_config *CF)
{ {
log(L_INFO "stats_init() ");
struct proto *P = proto_new(CF); struct proto *P = proto_new(CF);
struct stats_proto *p = (void *) P; struct stats_proto *p = (void *) P;
@ -98,14 +90,31 @@ stats_init(struct proto_config *CF)
p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS; p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
stats_configure_channels(P, CF);
return P; return P;
} }
static int static struct settle_timer_class stats_settle_class = {
stats_start(struct proto *P UNUSED) .action = stats_settle_timer,
.kick = NULL,
};
static void
stats_configure_channels(struct proto *P, struct proto_config *CF)
{ {
log(L_INFO "stats_configure_channels()");
struct channel_config *cc;
WALK_LIST(cc, CF->channels)
{
struct channel *c = proto_find_channel_by_name(P, cc->name);
proto_configure_channel(P, &c, cc);
}
}
static int
stats_start(struct proto *P)
{
log(L_INFO "stats_start() ");
stats_configure_channels(P, P->cf);
return PS_UP; return PS_UP;
} }
@ -131,18 +140,16 @@ stats_reconfigure(struct proto *P, struct proto_config *CF)
struct stats_channel *sc = (void *) c; struct stats_channel *sc = (void *) c;
struct stats_channel_config *scc = (void *) cc; struct stats_channel_config *scc = (void *) cc;
sc->max_generation = scc->max_generation; sc->settle_timer->min_settle_time = &(scc->min_settle_time);
sc->settle = scc->settle; sc->settle_timer->max_settle_time = &(scc->max_settle_time);
/* recalculate sum */ if (sc->counter != sc->_counter)
sc->counters[COUNTER] = 0; {
for (u8 i = 0; i <= sc->max_generation; i++) sc->counter = sc->_counter;
sc->counters[COUNTER] += sc->counters[i];
sc->sum = sc->counters[COUNTER]; /* notify all hooked filters */
// TODO here
/* notify all hooked filters */ }
// TODO here
c->stale = 0; c->stale = 0;
} }
@ -161,44 +168,19 @@ stats_show_proto_info(struct proto *P)
{ {
struct stats_proto *p = (void *) P; struct stats_proto *p = (void *) P;
/* indexes of non-zero counters */
u32 *arr = mb_alloc(p->p.pool, 256 * sizeof(u32));
struct stats_channel *sc; struct stats_channel *sc;
WALK_LIST(sc, p->p.channels) WALK_LIST(sc, p->p.channels)
{ {
for (uint i = 0; i < 256; i++)
{
arr[i] = 0;
}
u8 len = 0;
for (u8 i = 0; i < sc->max_generation; i++)
if (sc->counters[i])
{
arr[len] = i;
len++;
}
cli_msg(-1006, " Channel %s", sc->c.name); cli_msg(-1006, " Channel %s", sc->c.name);
cli_msg(-1006, " Max generation: %3u", sc->max_generation);
// FIXME : actual or visible to filters ? AND TIME below in the comment
cli_msg(-1006, " Exports: %10u (currently: %10u)", cli_msg(-1006, " Exports: %10u (currently: %10u)",
sc->sum, sc->counter,
sc->counters[COUNTER]); sc->_counter);
cli_msg(-1006, " Settle time: %7u s", sc->settle / 1000000 ); if (!P->disabled)
cli_msg(-1006, " Counter exported"); {
cli_msg(-1006, " Settle time: %4u s", (*(sc->settle_timer->min_settle_time)) TO_S);
for (u8 i = 0; i < len; i++) cli_msg(-1006, " Settle time: %4u s", (*(sc->settle_timer->max_settle_time)) TO_S);
cli_msg(-1006, " %3u: %10u ", arr[i], sc->counters[arr[i]]); }
if (!len)
cli_msg(-1006, " <all zeroes>");
cli_msg(-1006, "");
} }
mb_free(arr);
} }
void void
@ -212,43 +194,41 @@ stats_update_debug(struct proto *P)
} }
static void static void
stats_timer(timer *t) stats_settle_timer(struct settle_timer *st)
{ {
log(L_INFO "timer executing update"); timer *t = (void *) st;
struct stats_channel *c = (struct stats_channel *) t->data; struct stats_channel *c = t->data;
log(L_INFO "stats_settle_timer() _counter: %u, counter: %u",
c->_counter, c->counter);
/* update the sum correct counter data */ /* update only if real change happen */
c->sum = c->counters[COUNTER]; if (c->counter != c->_counter)
{
/* notify all filters to reevaluate them */ c->counter = c->_counter;
// TODO here /* do update here */
// WALK_LIST(s, subscribers)
} // { ... }
}
static void
stats_kick_timer(struct stats_channel *c)
{
/* if set to zero execute immediately */
if (!c->settle)
stats_timer(c->timer);
if (!tm_active(c->timer))
tm_start(c->timer, c->settle);
} }
static int static int
stats_channel_start(struct channel *C) stats_channel_start(struct channel *C)
{ {
struct stats_channel *c = (void *) C; struct stats_channel *c = (void *) C;
struct stats_channel_config *cc = (void *) C->config;
struct stats_proto *p = (void *) C->proto; struct stats_proto *p = (void *) C->proto;
c->pool = p->p.pool; c->pool = p->p.pool;
c->timer = tm_new_init(c->pool, stats_timer, (void *) c, 0, 0); if (!c->settle_timer)
c->settle_timer = stm_new_timer(
c->pool, (void *) c, &stats_settle_class);
c->counters = mb_allocz(c->pool, 256 * sizeof(u32)); c->settle_timer->min_settle_time = &(cc->min_settle_time);
c->sum = 0; c->settle_timer->max_settle_time = &(cc->max_settle_time);
c->_counter = 0;
c->counter = 0;
return 0; return 0;
} }
@ -256,16 +236,19 @@ stats_channel_start(struct channel *C)
static void static void
stats_channel_shutdown(struct channel *C) stats_channel_shutdown(struct channel *C)
{ {
log(L_INFO "stats_channel_shutdown()");
struct stats_channel *c = (void *) C; struct stats_channel *c = (void *) C;
mb_free(c->counters); tm_stop((timer *) c->settle_timer);
/* FIXME freed automatically by the resource pool ? c->settle_timer->min_settle_time = NULL;
rfree(c->timer); c->settle_timer->max_settle_time = NULL;
*/
c->max_generation = 0; mb_free(c->settle_timer);
c->counters = NULL; c->settle_timer = NULL;
c->_counter = 0;
c->counter = 0;
c->pool = NULL; c->pool = NULL;
} }

View File

@ -9,6 +9,7 @@
#ifndef _BIRD_STATS_H_ #ifndef _BIRD_STATS_H_
#define _BIRD_STATS_H_ #define _BIRD_STATS_H_
#include "lib/timer.h"
struct stats_channel; struct stats_channel;
@ -24,25 +25,28 @@ struct stats_proto {
struct stats_channel { struct stats_channel {
struct channel c; struct channel c;
pool *pool; pool *pool; /* copy of procotol pool */
u8 max_generation; u32 _counter; /* internal counter */
u32 *counters; u32 counter; /* publicly accessible counter */
u32 sum; struct settle_timer *settle_timer;
timer *timer;
btime settle;
}; };
struct stats_channel_config { struct stats_channel_config {
struct channel_config c; struct channel_config c;
u8 max_generation; btime min_settle_time; /* wait before notifying filters */
btime settle; btime max_settle_time;
}; };
/*
* get_stats_counter() - extract last notified counter
* for specific stats channel if it runs
*
*/
static inline int static inline int
get_stats_sum(struct symbol *sym) get_stats_counter(struct symbol *sym)
{ {
if (sym->ch_config->channel) if (sym->ch_config->channel)
return (int) ((struct stats_channel *) sym->ch_config->channel)->sum; return (int) ((struct stats_channel *) sym->ch_config->channel)->counter;
else else
return 0; return 0;
} }