]> Pileus Git - ~andy/linux/blobdiff - net/sched/sch_htb.c
htb: reorder struct htb_class fields for performance
[~andy/linux] / net / sched / sch_htb.c
index 79b1876b6cd260fac7d150ceeaa7a5a647266a56..7954e73d118ac6857a33ab1a49da4160acdae3f4 100644 (file)
@@ -65,6 +65,10 @@ static int htb_hysteresis __read_mostly = 0; /* whether to use mode hysteresis f
 module_param    (htb_hysteresis, int, 0640);
 MODULE_PARM_DESC(htb_hysteresis, "Hysteresis mode, less CPU load, less accurate");
 
+static int htb_rate_est = 0; /* htb classes have a default rate estimator */
+module_param(htb_rate_est, int, 0640);
+MODULE_PARM_DESC(htb_rate_est, "setup a default rate estimator (4sec 16sec) for htb classes");
+
 /* used internaly to keep status of single class */
 enum htb_cmode {
        HTB_CANT_SEND,          /* class can't send and can't borrow */
@@ -72,23 +76,39 @@ enum htb_cmode {
        HTB_CAN_SEND            /* class can send */
 };
 
-/* interior & leaf nodes; props specific to leaves are marked L: */
+/* interior & leaf nodes; props specific to leaves are marked L:
+ * To reduce false sharing, place mostly read fields at beginning,
+ * and mostly written ones at the end.
+ */
 struct htb_class {
        struct Qdisc_class_common common;
-       /* general class parameters */
-       struct gnet_stats_basic_packed bstats;
-       struct gnet_stats_queue qstats;
-       struct gnet_stats_rate_est rate_est;
-       struct tc_htb_xstats xstats;    /* our special stats */
-       int refcnt;             /* usage count of this class */
+       struct psched_ratecfg   rate;
+       struct psched_ratecfg   ceil;
+       s64                     buffer, cbuffer;/* token bucket depth/rate */
+       s64                     mbuffer;        /* max wait time */
+       int                     prio;           /* these two are used only by leaves... */
+       int                     quantum;        /* but stored for parent-to-leaf return */
+
+       struct tcf_proto        *filter_list;   /* class attached filters */
+       int                     filter_cnt;
+       int                     refcnt;         /* usage count of this class */
 
-       /* topology */
-       int level;              /* our level (see above) */
-       unsigned int children;
-       struct htb_class *parent;       /* parent class */
+       int                     level;          /* our level (see above) */
+       unsigned int            children;
+       struct htb_class        *parent;        /* parent class */
+
+       struct gnet_stats_rate_est64 rate_est;
+
+       /*
+        * Written often fields
+        */
+       struct gnet_stats_basic_packed bstats;
+       struct gnet_stats_queue qstats;
+       struct tc_htb_xstats    xstats; /* our special stats */
 
-       int prio;               /* these two are used only by leaves... */
-       int quantum;            /* but stored for parent-to-leaf return */
+       /* token bucket parameters */
+       s64                     tokens, ctokens;/* current number of tokens */
+       s64                     t_c;            /* checkpoint time */
 
        union {
                struct htb_class_leaf {
@@ -107,24 +127,12 @@ struct htb_class {
                        u32 last_ptr_id[TC_HTB_NUMPRIO];
                } inner;
        } un;
-       struct rb_node node[TC_HTB_NUMPRIO];    /* node for self or feed tree */
-       struct rb_node pq_node; /* node for event queue */
-       psched_time_t pq_key;
-
-       int prio_activity;      /* for which prios are we active */
-       enum htb_cmode cmode;   /* current mode of the class */
-
-       /* class attached filters */
-       struct tcf_proto *filter_list;
-       int filter_cnt;
+       s64                     pq_key;
 
-       /* token bucket parameters */
-       struct psched_ratecfg rate;
-       struct psched_ratecfg ceil;
-       s64 buffer, cbuffer;    /* token bucket depth/rate */
-       psched_tdiff_t mbuffer; /* max wait time */
-       s64 tokens, ctokens;    /* current number of tokens */
-       psched_time_t t_c;      /* checkpoint time */
+       int                     prio_activity;  /* for which prios are we active */
+       enum htb_cmode          cmode;          /* current mode of the class */
+       struct rb_node          pq_node;        /* node for event queue */
+       struct rb_node          node[TC_HTB_NUMPRIO];   /* node for self or feed tree */
 };
 
 struct htb_sched {
@@ -141,15 +149,15 @@ struct htb_sched {
        struct rb_root wait_pq[TC_HTB_MAXDEPTH];
 
        /* time of nearest event per level (row) */
-       psched_time_t near_ev_cache[TC_HTB_MAXDEPTH];
+       s64     near_ev_cache[TC_HTB_MAXDEPTH];
 
        int defcls;             /* class where unclassified flows go to */
 
        /* filters for qdisc itself */
        struct tcf_proto *filter_list;
 
-       int rate2quantum;       /* quant = rate / rate2quantum */
-       psched_time_t now;      /* cached dequeue time */
+       int     rate2quantum;   /* quant = rate / rate2quantum */
+       s64     now;    /* cached dequeue time */
        struct qdisc_watchdog watchdog;
 
        /* non shaped skbs; let them go directly thru */
@@ -664,8 +672,8 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
  * next pending event (0 for no event in pq, q->now for too many events).
  * Note: Applied are events whose have cl->pq_key <= q->now.
  */
-static psched_time_t htb_do_events(struct htb_sched *q, int level,
-                                  unsigned long start)
+static s64 htb_do_events(struct htb_sched *q, int level,
+                        unsigned long start)
 {
        /* don't run for longer than 2 jiffies; 2 is used instead of
         * 1 to simplify things when jiffy is going to be incremented
@@ -857,7 +865,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
        struct sk_buff *skb;
        struct htb_sched *q = qdisc_priv(sch);
        int level;
-       psched_time_t next_event;
+       s64 next_event;
        unsigned long start_at;
 
        /* try to dequeue direct packets as high prio (!) to minimize cpu work */
@@ -880,7 +888,7 @@ ok:
        for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
                /* common case optimization - skip event handler quickly */
                int m;
-               psched_time_t event;
+               s64 event;
 
                if (q->now >= q->near_ev_cache[level]) {
                        event = htb_do_events(q, level, start_at);
@@ -1090,9 +1098,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
 
        memset(&opt, 0, sizeof(opt));
 
-       opt.rate.rate = psched_ratecfg_getrate(&cl->rate);
+       psched_ratecfg_getrate(&opt.rate, &cl->rate);
        opt.buffer = PSCHED_NS2TICKS(cl->buffer);
-       opt.ceil.rate = psched_ratecfg_getrate(&cl->ceil);
+       psched_ratecfg_getrate(&opt.ceil, &cl->ceil);
        opt.cbuffer = PSCHED_NS2TICKS(cl->cbuffer);
        opt.quantum = cl->quantum;
        opt.prio = cl->prio;
@@ -1117,8 +1125,8 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
 
        if (!cl->level && cl->un.leaf.q)
                cl->qstats.qlen = cl->un.leaf.q->q.qlen;
-       cl->xstats.tokens = cl->tokens;
-       cl->xstats.ctokens = cl->ctokens;
+       cl->xstats.tokens = PSCHED_NS2TICKS(cl->tokens);
+       cl->xstats.ctokens = PSCHED_NS2TICKS(cl->ctokens);
 
        if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
            gnet_stats_copy_rate_est(d, NULL, &cl->rate_est) < 0 ||
@@ -1200,7 +1208,7 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl,
        parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
        parent->tokens = parent->buffer;
        parent->ctokens = parent->cbuffer;
-       parent->t_c = psched_get_time();
+       parent->t_c = ktime_to_ns(ktime_get());
        parent->cmode = HTB_CAN_SEND;
 }
 
@@ -1366,12 +1374,14 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                if (!cl)
                        goto failure;
 
-               err = gen_new_estimator(&cl->bstats, &cl->rate_est,
-                                       qdisc_root_sleeping_lock(sch),
-                                       tca[TCA_RATE] ? : &est.nla);
-               if (err) {
-                       kfree(cl);
-                       goto failure;
+               if (htb_rate_est || tca[TCA_RATE]) {
+                       err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+                                               qdisc_root_sleeping_lock(sch),
+                                               tca[TCA_RATE] ? : &est.nla);
+                       if (err) {
+                               kfree(cl);
+                               goto failure;
+                       }
                }
 
                cl->refcnt = 1;
@@ -1417,8 +1427,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                /* set class to be in HTB_CAN_SEND state */
                cl->tokens = PSCHED_TICKS2NS(hopt->buffer);
                cl->ctokens = PSCHED_TICKS2NS(hopt->cbuffer);
-               cl->mbuffer = 60 * PSCHED_TICKS_PER_SEC;        /* 1min */
-               cl->t_c = psched_get_time();
+               cl->mbuffer = 60ULL * NSEC_PER_SEC;     /* 1min */
+               cl->t_c = ktime_to_ns(ktime_get());
                cl->cmode = HTB_CAN_SEND;
 
                /* attach to the hash list and parent's family */
@@ -1459,8 +1469,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                        cl->prio = TC_HTB_NUMPRIO - 1;
        }
 
-       psched_ratecfg_precompute(&cl->rate, hopt->rate.rate);
-       psched_ratecfg_precompute(&cl->ceil, hopt->ceil.rate);
+       psched_ratecfg_precompute(&cl->rate, &hopt->rate);
+       psched_ratecfg_precompute(&cl->ceil, &hopt->ceil);
 
        cl->buffer = PSCHED_TICKS2NS(hopt->buffer);
        cl->cbuffer = PSCHED_TICKS2NS(hopt->buffer);