[MINOR] freq_ctr: add new types and functions for periods different from 1s

Some freq counters will have to work on periods different from 1 second.
The original freq counters rely on the period to be exactly one second.
The new ones (freq_ctr_period) let the user define the period in ticks,
and all computations are operated over that period. When reading a value,
it indicates the amount of events over that period too.
This commit is contained in:
Willy Tarreau 2010-06-20 07:15:43 +02:00
parent f0d9eecc52
commit 2970b0bedf
3 changed files with 151 additions and 20 deletions

View File

@ -56,6 +56,41 @@ static inline void update_freq_ctr(struct freq_ctr *ctr, unsigned int inc)
/* Note: later we may want to propagate the update to other counters */
}
/* Rotate a frequency counter when current period is over. Must not be called
* during a valid period. It is important that it correctly initializes a null
* area. This one works on frequency counters which have a period different
* from one second.
*/
static inline void rotate_freq_ctr_period(struct freq_ctr_period *ctr,
unsigned int period)
{
ctr->prev_ctr = ctr->curr_ctr;
ctr->curr_tick += period;
if (likely(now_ms - ctr->curr_tick >= period)) {
/* we missed at least two periods */
ctr->prev_ctr = 0;
ctr->curr_tick = now_ms;
}
ctr->curr_ctr = 0; /* leave it at the end to help gcc optimize it away */
}
/* Update a frequency counter by <inc> incremental units. It is automatically
* rotated if the period is over. It is important that it correctly initializes
* a null area. This one works on frequency counters which have a period
* different from one second.
*/
static inline void update_freq_ctr_period(struct freq_ctr_period *ctr,
unsigned int period, unsigned int inc)
{
if (likely(now_ms - ctr->curr_tick < period)) {
ctr->curr_ctr += inc;
return;
}
rotate_freq_ctr_period(ctr, period);
ctr->curr_ctr = inc;
/* Note: later we may want to propagate the update to other counters */
}
/* Read a frequency counter taking history into account for missing time in
* current period.
*/
@ -75,6 +110,11 @@ unsigned int freq_ctr_remain(struct freq_ctr *ctr, unsigned int freq, unsigned i
*/
unsigned int next_event_delay(struct freq_ctr *ctr, unsigned int freq, unsigned int pend);
/* process freq counters over configurable periods */
unsigned int read_freq_ctr_period(struct freq_ctr_period *ctr, unsigned int period);
unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int period,
unsigned int freq, unsigned int pend);
#endif /* _PROTO_FREQ_CTR_H */
/*

View File

@ -1,35 +1,50 @@
/*
include/types/freq_ctr.h
This file contains structure declarations for frequency counters.
Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, version 2.1
exclusively.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
* include/types/freq_ctr.h
* This file contains structure declarations for frequency counters.
*
* Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _TYPES_FREQ_CTR_H
#define _TYPES_FREQ_CTR_H
#include <common/config.h>
/* The implicit freq_ctr counter counts a rate of events per second. It is the
* preferred form to count rates over a one-second period, because it does not
* involve any divide.
*/
struct freq_ctr {
unsigned int curr_sec; /* start date of current period (seconds from now.tv_sec) */
unsigned int curr_ctr; /* cumulated value for current period */
unsigned int prev_ctr; /* value for last period */
};
/* The generic freq_ctr_period counter counts a rate of events per period, where
* the period has to be known by the user. The period is measured in ticks and
* must be at least 2 ticks long. This form is slightly more CPU intensive than
* the per-second form.
*/
struct freq_ctr_period {
unsigned int curr_tick; /* start date of current period (wrapping ticks) */
unsigned int curr_ctr; /* cumulated value for current period */
unsigned int prev_ctr; /* value for last period */
};
#endif /* _TYPES_FREQ_CTR_H */
/*

View File

@ -1,7 +1,7 @@
/*
* Event rate calculation functions.
*
* Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
* Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -110,6 +110,82 @@ unsigned int next_event_delay(struct freq_ctr *ctr, unsigned int freq, unsigned
return MAX(wait, 1);
}
/* Reads a frequency counter taking history into account for missing time in
* current period. The period has to be passed in number of ticks and must
* match the one used to feed the counter. The counter value is reported for
* current date (now_ms). The return value has the same precision as one input
* data sample, so low rates over the period will be inaccurate but still
* appropriate for max checking. One trick we use for low values is to specially
* handle the case where the rate is between 0 and 1 in order to avoid flapping
* while waiting for the next event.
*
* For immediate limit checking, it's recommended to use freq_ctr_period_remain()
* instead which does not have the flapping correction, so that even frequencies
* as low as one event/period are properly handled.
*
* For measures over a 1-second period, it's better to use the implicit functions
* above.
*/
unsigned int read_freq_ctr_period(struct freq_ctr_period *ctr, unsigned int period)
{
unsigned int curr, past;
unsigned int remain;
curr = ctr->curr_ctr;
past = ctr->prev_ctr;
remain = ctr->curr_tick + period - now_ms;
if (unlikely((int)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;
if ((int)remain < 0)
return 0;
past = curr;
curr = 0;
}
if (past <= 1 && !curr)
return past; /* very low rate, avoid flapping */
curr += div64_32((unsigned long long)past * remain, period);
return curr;
}
/* Returns the number of remaining events that can occur on this freq counter
* while respecting <freq> events per period, and taking into account that
* <pend> events are already known to be pending. Returns 0 if limit was reached.
*/
unsigned int freq_ctr_remain_period(struct freq_ctr_period *ctr, unsigned int period,
unsigned int freq, unsigned int pend)
{
unsigned int curr, past;
unsigned int remain;
curr = ctr->curr_ctr;
past = ctr->prev_ctr;
remain = ctr->curr_tick + period - now_ms;
if (likely((int)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.
*/
past = curr;
curr = 0;
remain += period;
if ((int)remain < 0)
past = 0;
}
if (likely(past))
curr += div64_32((unsigned long long)past * remain, period);
curr += pend;
freq -= curr;
if ((int)freq < 0)
freq = 0;
return freq;
}
/*
* Local variables: