814aebc61da5ea66282e077360ba721d2ca637bb
[openwrt.git] / target / linux / generic / patches-3.3 / 045-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch
1 From 6ff272c9ad65eda219cd975b9da2dbc31cc812ee Mon Sep 17 00:00:00 2001
2 From: Eric Dumazet <eric.dumazet@gmail.com>
3 Date: Sat, 12 May 2012 21:23:23 +0000
4 Subject: [PATCH 46/50] codel: use u16 field instead of 31bits for
5  rec_inv_sqrt
6
7 David pointed out gcc might generate poor code with 31bit fields.
8
9 Using u16 is more than enough and permits a better code output.
10
11 Also make the code intent more readable using constants, fixed point arithmetic
12 not being trivial for everybody.
13
14 Suggested-by: David Miller <davem@davemloft.net>
15 Signed-off-by: Eric Dumazet <edumazet@google.com>
16 Signed-off-by: David S. Miller <davem@davemloft.net>
17 ---
18  include/net/codel.h |   25 +++++++++++++++----------
19  1 file changed, 15 insertions(+), 10 deletions(-)
20
21 --- a/include/net/codel.h
22 +++ b/include/net/codel.h
23 @@ -133,13 +133,17 @@ struct codel_params {
24  struct codel_vars {
25         u32             count;
26         u32             lastcount;
27 -       bool            dropping:1;
28 -       u32             rec_inv_sqrt:31;
29 +       bool            dropping;
30 +       u16             rec_inv_sqrt;
31         codel_time_t    first_above_time;
32         codel_time_t    drop_next;
33         codel_time_t    ldelay;
34  };
35  
36 +#define REC_INV_SQRT_BITS (8 * sizeof(u16)) /* or sizeof_in_bits(rec_inv_sqrt) */
37 +/* needed shift to get a Q0.32 number from rec_inv_sqrt */
38 +#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
39 +
40  /**
41   * struct codel_stats - contains codel shared variables and stats
42   * @maxpacket: largest packet we've seen so far
43 @@ -173,17 +177,18 @@ static void codel_stats_init(struct code
44   * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots
45   * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2)
46   *
47 - * Here, invsqrt is a fixed point number (< 1.0), 31bit mantissa)
48 + * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32
49   */
50  static void codel_Newton_step(struct codel_vars *vars)
51  {
52 -       u32 invsqrt = vars->rec_inv_sqrt;
53 -       u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 31;
54 -       u64 val = (3LL << 31) - ((u64)vars->count * invsqrt2);
55 +       u32 invsqrt = ((u32)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT;
56 +       u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 32;
57 +       u64 val = (3LL << 32) - ((u64)vars->count * invsqrt2);
58  
59 -       val = (val * invsqrt) >> 32;
60 +       val >>= 2; /* avoid overflow in following multiply */
61 +       val = (val * invsqrt) >> (32 - 2 + 1);
62  
63 -       vars->rec_inv_sqrt = val;
64 +       vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT;
65  }
66  
67  /*
68 @@ -195,7 +200,7 @@ static codel_time_t codel_control_law(co
69                                       codel_time_t interval,
70                                       u32 rec_inv_sqrt)
71  {
72 -       return t + reciprocal_divide(interval, rec_inv_sqrt << 1);
73 +       return t + reciprocal_divide(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
74  }
75  
76  
77 @@ -326,7 +331,7 @@ static struct sk_buff *codel_dequeue(str
78                         codel_Newton_step(vars);
79                 } else {
80                         vars->count = 1;
81 -                       vars->rec_inv_sqrt = 0x7fffffff;
82 +                       vars->rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT;
83                 }
84                 vars->lastcount = vars->count;
85                 vars->drop_next = codel_control_law(now, params->interval,