]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
net_sched: gen_estimator: account for timer drifts
authorEric Dumazet <edumazet@google.com>
Fri, 2 Dec 2016 16:11:00 +0000 (08:11 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 3 Dec 2016 21:12:17 +0000 (16:12 -0500)
Under heavy stress, timer used in estimators tend to slowly be delayed
by a few jiffies, leading to inaccuracies.

Lets remember what was the last scheduled jiffies so that we get more
precise estimations, without having to add a multiply/divide in the loop
to account for the drifts.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/gen_estimator.c

index cad8e791f28e060adb8d774d7c2c5e375c0ffe8f..0993844faeeaefb221ea619fd9d796600b82fbb9 100644 (file)
@@ -78,8 +78,7 @@
 
 #define EST_MAX_INTERVAL       5
 
-struct gen_estimator
-{
+struct gen_estimator {
        struct list_head        list;
        struct gnet_stats_basic_packed  *bstats;
        struct gnet_stats_rate_est64    *rate_est;
@@ -96,8 +95,8 @@ struct gen_estimator
        struct rcu_head         head;
 };
 
-struct gen_estimator_head
-{
+struct gen_estimator_head {
+       unsigned long           next_jiffies;
        struct timer_list       timer;
        struct list_head        list;
 };
@@ -146,8 +145,15 @@ skip:
                        spin_unlock(e->stats_lock);
        }
 
-       if (!list_empty(&elist[idx].list))
-               mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx));
+       if (!list_empty(&elist[idx].list)) {
+               elist[idx].next_jiffies += ((HZ/4) << idx);
+
+               if (unlikely(time_after_eq(jiffies, elist[idx].next_jiffies))) {
+                       /* Ouch... timer was delayed. */
+                       elist[idx].next_jiffies = jiffies + 1;
+               }
+               mod_timer(&elist[idx].timer, elist[idx].next_jiffies);
+       }
        rcu_read_unlock();
 }
 
@@ -251,9 +257,10 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
                setup_timer(&elist[idx].timer, est_timer, idx);
        }
 
-       if (list_empty(&elist[idx].list))
-               mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx));
-
+       if (list_empty(&elist[idx].list)) {
+               elist[idx].next_jiffies = jiffies + ((HZ/4) << idx);
+               mod_timer(&elist[idx].timer, elist[idx].next_jiffies);
+       }
        list_add_rcu(&est->list, &elist[idx].list);
        gen_add_node(est);
        spin_unlock_bh(&est_tree_lock);