summaryrefslogtreecommitdiff
path: root/net/sched/sch_generic.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-06-07 00:56:19 +0400
committerDavid S. Miller <davem@davemloft.net>2013-06-12 09:39:47 +0400
commit130d3d68b52097c7ae081109f700b02776adcb9c (patch)
tree08b3ab56be1de543a9c3e7cd1d9ff532221bda14 /net/sched/sch_generic.c
parent45203a3b380cee28f570475c0d28c169f908c209 (diff)
downloadlinux-130d3d68b52097c7ae081109f700b02776adcb9c.tar.xz
net_sched: psched_ratecfg_precompute() improvements
Before allowing 64bits bytes rates, refactor psched_ratecfg_precompute() to get better comments and increased accuracy. rate_bps field is renamed to rate_bytes_ps, as we only have to worry about bytes per second. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Ben Greear <greearb@candelatech.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r--net/sched/sch_generic.c44
1 files changed, 20 insertions, 24 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 20224086cc28..4626cef4b76e 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -901,37 +901,33 @@ void dev_shutdown(struct net_device *dev)
void psched_ratecfg_precompute(struct psched_ratecfg *r,
const struct tc_ratespec *conf)
{
- u64 factor;
- u64 mult;
- int shift;
-
memset(r, 0, sizeof(*r));
r->overhead = conf->overhead;
- r->rate_bps = (u64)conf->rate << 3;
+ r->rate_bytes_ps = conf->rate;
r->mult = 1;
/*
- * Calibrate mult, shift so that token counting is accurate
- * for smallest packet size (64 bytes). Token (time in ns) is
- * computed as (bytes * 8) * NSEC_PER_SEC / rate_bps. It will
- * work as long as the smallest packet transfer time can be
- * accurately represented in nanosec.
+ * The deal here is to replace a divide by a reciprocal one
+ * in fast path (a reciprocal divide is a multiply and a shift)
+ *
+ * Normal formula would be :
+ * time_in_ns = (NSEC_PER_SEC * len) / rate_bps
+ *
+ * We compute mult/shift to use instead :
+ * time_in_ns = (len * mult) >> shift;
+ *
+ * We try to get the highest possible mult value for accuracy,
+ * but have to make sure no overflows will ever happen.
*/
- if (r->rate_bps > 0) {
- /*
- * Higher shift gives better accuracy. Find the largest
- * shift such that mult fits in 32 bits.
- */
- for (shift = 0; shift < 16; shift++) {
- r->shift = shift;
- factor = 8LLU * NSEC_PER_SEC * (1 << r->shift);
- mult = div64_u64(factor, r->rate_bps);
- if (mult > UINT_MAX)
+ if (r->rate_bytes_ps > 0) {
+ u64 factor = NSEC_PER_SEC;
+
+ for (;;) {
+ r->mult = div64_u64(factor, r->rate_bytes_ps);
+ if (r->mult & (1U << 31) || factor & (1ULL << 63))
break;
+ factor <<= 1;
+ r->shift++;
}
-
- r->shift = shift - 1;
- factor = 8LLU * NSEC_PER_SEC * (1 << r->shift);
- r->mult = div64_u64(factor, r->rate_bps);
}
}
EXPORT_SYMBOL(psched_ratecfg_precompute);