limiter: introduce hierarchy, always show current rate

This commit is contained in:
Thomas Schoebel-Theuer 2012-09-24 11:49:29 +02:00 committed by Thomas Schoebel-Theuer
parent 84ca56f6b1
commit 09e7732342
2 changed files with 43 additions and 26 deletions

View File

@ -7,36 +7,49 @@
int mars_limit(struct mars_limiter *lim, int amount)
{
int res = 0;
int delay = 0;
unsigned long long now;
now = cpu_clock(raw_smp_processor_id());
if (lim->lim_max_rate > 0 && likely(lim->lim_stamp)) {
long long elapsed = now - lim->lim_stamp;
long long rate;
/* Races are possible, but taken into account.
* There is no real harm from rarely lost updates.
*/
lim->lim_accu += amount;
rate = (long long)lim->lim_accu * LIMITER_TIME_RESOLUTION / elapsed;
if (rate > lim->lim_max_rate) {
res = 1001 - lim->lim_max_rate * 1000 / rate;
/* Compute the maximum delay along the path
* down to the root of the hierarchy tree.
*/
while (lim != NULL) {
if (likely(lim->lim_stamp)) {
long long elapsed = now - lim->lim_stamp;
int rate;
/* Races are possible, but taken into account.
* There is no real harm from rarely lost updates.
*/
lim->lim_accu += amount;
rate = (long long)lim->lim_accu * LIMITER_TIME_RESOLUTION / elapsed;
lim->lim_rate = rate;
// limit exceeded?
if (lim->lim_max_rate > 0 && rate > lim->lim_max_rate) {
int this_delay = 1001 - lim->lim_max_rate * 1000 / rate;
// compute maximum
if (!delay || this_delay > delay)
delay = this_delay;
}
elapsed -= LIMITER_TIME_RESOLUTION * 2;
if (elapsed > LIMITER_TIME_RESOLUTION) {
lim->lim_stamp += elapsed;
if (lim->lim_accu > 0) {
lim->lim_accu -= (long long)lim->lim_max_rate * elapsed / LIMITER_TIME_RESOLUTION;
}
}
} else {
lim->lim_accu = amount;
lim->lim_stamp = now;
lim->lim_rate = 0;
}
elapsed -= LIMITER_TIME_RESOLUTION * 2;
if (elapsed > LIMITER_TIME_RESOLUTION) {
lim->lim_stamp += elapsed;
if (lim->lim_accu > 0)
lim->lim_accu -= (long long)lim->lim_max_rate * elapsed / LIMITER_TIME_RESOLUTION;
}
} else {
lim->lim_accu = amount;
lim->lim_stamp = now;
lim = lim->lim_father;
}
return res;
return delay;
}
EXPORT_SYMBOL_GPL(mars_limit);

View File

@ -9,11 +9,15 @@
#define LIMITER_TIME_RESOLUTION NSEC_PER_SEC
struct mars_limiter {
/* hierarchy tree */
struct mars_limiter *lim_father;
/* tunables */
int lim_max_rate;
/* readable */
int lim_rate;
unsigned long long lim_stamp;
/* internal */
int lim_accu;
unsigned long long lim_stamp;
};
extern int mars_limit(struct mars_limiter *lim, int amount);