MINOR: freq_ctr: Add a function to get events excess over the current period
freq_ctr_overshoot_period() function may be used to retrieve the excess of events over the current period for a givent frequency counter, ignoring the history. It is a way compare the "current rate" (the number of events over the current period) to a given rate and estimate the excess of events. It may be used to safely add new events, especially at the begining of the current period for a frequency counter with large period. This way, it is possible to smoothly add events during the whole period without quickly consuming all the quota at the beginning of the period and waiting for the next one to be able to add new events.
This commit is contained in:
parent
dbbdb25f1c
commit
aa55640b8c
|
@ -29,6 +29,7 @@
|
|||
|
||||
/* exported functions from freq_ctr.c */
|
||||
ullong freq_ctr_total(const struct freq_ctr *ctr, uint period, int pend);
|
||||
int freq_ctr_overshoot_period(const struct freq_ctr *ctr, uint period, uint freq);
|
||||
|
||||
/* Update a frequency counter by <inc> incremental units. It is automatically
|
||||
* rotated if the period is over. It is important that it correctly initializes
|
||||
|
|
|
@ -96,6 +96,64 @@ ullong freq_ctr_total(const struct freq_ctr *ctr, uint period, int pend)
|
|||
return past * remain + (curr + pend) * period;
|
||||
}
|
||||
|
||||
/* Returns the excess of events (may be negative) over the current period for
|
||||
* target frequency <freq>. It returns 0 if the counter is in the future. The
|
||||
* result considers the position of the current time within the current period.
|
||||
*
|
||||
* The caller may safely add new events if result is negative or null.
|
||||
*/
|
||||
int freq_ctr_overshoot_period(const struct freq_ctr *ctr, uint period, uint freq)
|
||||
{
|
||||
uint curr, old_curr;
|
||||
uint tick, old_tick;
|
||||
int elapsed;
|
||||
|
||||
tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
|
||||
curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
|
||||
|
||||
while (1) {
|
||||
if (tick & 0x1) // change in progress
|
||||
goto redo0;
|
||||
|
||||
old_tick = tick;
|
||||
old_curr = curr;
|
||||
|
||||
/* now let's load the values a second time and make sure they
|
||||
* did not change, which will indicate it was a stable reading.
|
||||
*/
|
||||
|
||||
tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
|
||||
if (tick & 0x1) // change in progress
|
||||
goto redo0;
|
||||
|
||||
if (tick != old_tick)
|
||||
goto redo1;
|
||||
|
||||
curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
|
||||
if (curr != old_curr)
|
||||
goto redo2;
|
||||
|
||||
/* all values match between two loads, they're stable, let's
|
||||
* quit now.
|
||||
*/
|
||||
break;
|
||||
redo0:
|
||||
tick = HA_ATOMIC_LOAD(&ctr->curr_tick);
|
||||
redo1:
|
||||
curr = HA_ATOMIC_LOAD(&ctr->curr_ctr);
|
||||
redo2:
|
||||
__ha_cpu_relax();
|
||||
};
|
||||
|
||||
elapsed = HA_ATOMIC_LOAD(&global_now_ms) - tick;
|
||||
if (unlikely(elapsed < 0)) {
|
||||
/* The counter is in the future, there is no overshoot */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return curr - div64_32((uint64_t)elapsed * freq, period);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
|
|
Loading…
Reference in New Issue