diff --git a/include/haproxy/freq_ctr.h b/include/haproxy/freq_ctr.h index 879262539..e0ac70992 100644 --- a/include/haproxy/freq_ctr.h +++ b/include/haproxy/freq_ctr.h @@ -27,6 +27,8 @@ #include #include +/* exported functions from freq_ctr.c */ +ullong freq_ctr_total(struct freq_ctr_period *ctr, uint period, int pend); /* Update a frequency counter by incremental units. It is automatically * rotated if the period is over. It is important that it correctly initializes diff --git a/src/freq_ctr.c b/src/freq_ctr.c index 42fbc1cea..76a8ec1ce 100644 --- a/src/freq_ctr.c +++ b/src/freq_ctr.c @@ -274,6 +274,67 @@ unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int pe return freq; } +/* Returns the total number of events over the current + last period, including + * a number of already pending events . The average frequency will be + * obtained by dividing the output by . This is essentially made to + * ease implementation of higher-level read functions. + * + * As a special case, if pend < 0, it's assumed there are no pending + * events and a flapping correction must be applied at the end. This is used by + * read_freq_ctr_period() to avoid reporting ups and downs on low-frequency + * events when the past value is <= 1. + */ +ullong freq_ctr_total(struct freq_ctr_period *ctr, uint period, int pend) +{ + ullong curr, past; + uint curr_tick; + int remain; + + for (;; __ha_cpu_relax()) { + curr = ctr->curr_ctr; + past = ctr->prev_ctr; + curr_tick = ctr->curr_tick; + + /* now let's make sure the second loads retrieve the most + * up-to-date values. If no value changed after a load barrier, + * we're certain the values we got were stable. + */ + __ha_barrier_load(); + + if (curr_tick & 0x1) + continue; + + if (curr != ctr->curr_ctr) + continue; + + if (past != ctr->prev_ctr) + continue; + + if (curr_tick != ctr->curr_tick) + continue; + break; + }; + + remain = curr_tick + period - global_now_ms; + if (unlikely(remain < 0)) { + /* We're past the first period, check if we can still report a + * part of last period or if we're too far away. + */ + remain += period; + past = (remain >= 0) ? curr : 0; + curr = 0; + } + + if (pend < 0) { + /* enable flapping correction at very low rates */ + pend = 0; + if (!curr && past <= 1) + return past * period; + } + + /* compute the total number of confirmed events over the period */ + return past * remain + (curr + pend) * period; +} /* * Local variables: