aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_qfq.c
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@unimore.it>2013-07-16 02:52:30 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-28 19:30:04 -0400
commitc1d220fb027abb92452bf3a59fed7308647b39be (patch)
treee591b8aabfe3819542dde5534cd17264fa9330d9 /net/sched/sch_qfq.c
parent98bec4a114dfd772390a07735606109447481872 (diff)
pkt_sched: sch_qfq: remove a source of high packet delay/jitter
[ Upstream commit 87f40dd6ce7042caca0b3b557e8923127f51f902 ] QFQ+ inherits from QFQ a design choice that may cause a high packet delay/jitter and a severe short-term unfairness. As QFQ, QFQ+ uses a special quantity, the system virtual time, to track the service provided by the ideal system it approximates. When a packet is dequeued, this quantity must be incremented by the size of the packet, divided by the sum of the weights of the aggregates waiting to be served. Tracking this sum correctly is a non-trivial task, because, to preserve tight service guarantees, the decrement of this sum must be delayed in a special way [1]: this sum can be decremented only after that its value would decrease also in the ideal system approximated by QFQ+. For efficiency, QFQ+ keeps track only of the 'instantaneous' weight sum, increased and decreased immediately as the weight of an aggregate changes, and as an aggregate is created or destroyed (which, in its turn, happens as a consequence of some class being created/destroyed/changed). However, to avoid the problems caused to service guarantees by these immediate decreases, QFQ+ increments the system virtual time using the maximum value allowed for the weight sum, 2^10, in place of the dynamic, instantaneous value. The instantaneous value of the weight sum is used only to check whether a request of weight increase or a class creation can be satisfied. Unfortunately, the problems caused by this choice are worse than the temporary degradation of the service guarantees that may occur, when a class is changed or destroyed, if the instantaneous value of the weight sum was used to update the system virtual time. In fact, the fraction of the link bandwidth guaranteed by QFQ+ to each aggregate is equal to the ratio between the weight of the aggregate and the sum of the weights of the competing aggregates. The packet delay guaranteed to the aggregate is instead inversely proportional to the guaranteed bandwidth. By using the maximum possible value, and not the actual value of the weight sum, QFQ+ provides each aggregate with the worst possible service guarantees, and not with service guarantees related to the actual set of competing aggregates. To see the consequences of this fact, consider the following simple example. Suppose that only the following aggregates are backlogged, i.e., that only the classes in the following aggregates have packets to transmit: one aggregate with weight 10, say A, and ten aggregates with weight 1, say B1, B2, ..., B10. In particular, suppose that these aggregates are always backlogged. Given the weight distribution, the smoothest and fairest service order would be: A B1 A B2 A B3 A B4 A B5 A B6 A B7 A B8 A B9 A B10 A B1 A B2 ... QFQ+ would provide exactly this optimal service if it used the actual value for the weight sum instead of the maximum possible value, i.e., 11 instead of 2^10. In contrast, since QFQ+ uses the latter value, it serves aggregates as follows (easy to prove and to reproduce experimentally): A B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 A A A A A A A A A A B1 B2 ... B10 A A ... By replacing 10 with N in the above example, and by increasing N, one can increase at will the maximum packet delay and the jitter experienced by the classes in aggregate A. This patch addresses this issue by just using the above 'instantaneous' value of the weight sum, instead of the maximum possible value, when updating the system virtual time. After the instantaneous weight sum is decreased, QFQ+ may deviate from the ideal service for a time interval in the order of the time to serve one maximum-size packet for each backlogged class. The worst-case extent of the deviation exhibited by QFQ+ during this time interval [1] is basically the same as of the deviation described above (but, without this patch, QFQ+ suffers from such a deviation all the time). Finally, this patch modifies the comment to the function qfq_slot_insert, to make it coherent with the fact that the weight sum used by QFQ+ can now be lower than the maximum possible value. [1] P. Valente, "Extending WF2Q+ to support a dynamic traffic mix", Proceedings of AAA-IDEA'05, June 2005. Signed-off-by: Paolo Valente <paolo.valente@unimore.it> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/sched/sch_qfq.c')
-rw-r--r--net/sched/sch_qfq.c85
1 files changed, 56 insertions, 29 deletions
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index d51852bba01c..57922524f0c7 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -113,7 +113,6 @@
113 113
114#define FRAC_BITS 30 /* fixed point arithmetic */ 114#define FRAC_BITS 30 /* fixed point arithmetic */
115#define ONE_FP (1UL << FRAC_BITS) 115#define ONE_FP (1UL << FRAC_BITS)
116#define IWSUM (ONE_FP/QFQ_MAX_WSUM)
117 116
118#define QFQ_MTU_SHIFT 16 /* to support TSO/GSO */ 117#define QFQ_MTU_SHIFT 16 /* to support TSO/GSO */
119#define QFQ_MIN_LMAX 512 /* see qfq_slot_insert */ 118#define QFQ_MIN_LMAX 512 /* see qfq_slot_insert */
@@ -189,6 +188,7 @@ struct qfq_sched {
189 struct qfq_aggregate *in_serv_agg; /* Aggregate being served. */ 188 struct qfq_aggregate *in_serv_agg; /* Aggregate being served. */
190 u32 num_active_agg; /* Num. of active aggregates */ 189 u32 num_active_agg; /* Num. of active aggregates */
191 u32 wsum; /* weight sum */ 190 u32 wsum; /* weight sum */
191 u32 iwsum; /* inverse weight sum */
192 192
193 unsigned long bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */ 193 unsigned long bitmaps[QFQ_MAX_STATE]; /* Group bitmaps. */
194 struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */ 194 struct qfq_group groups[QFQ_MAX_INDEX + 1]; /* The groups. */
@@ -314,6 +314,7 @@ static void qfq_update_agg(struct qfq_sched *q, struct qfq_aggregate *agg,
314 314
315 q->wsum += 315 q->wsum +=
316 (int) agg->class_weight * (new_num_classes - agg->num_classes); 316 (int) agg->class_weight * (new_num_classes - agg->num_classes);
317 q->iwsum = ONE_FP / q->wsum;
317 318
318 agg->num_classes = new_num_classes; 319 agg->num_classes = new_num_classes;
319} 320}
@@ -340,6 +341,10 @@ static void qfq_destroy_agg(struct qfq_sched *q, struct qfq_aggregate *agg)
340{ 341{
341 if (!hlist_unhashed(&agg->nonfull_next)) 342 if (!hlist_unhashed(&agg->nonfull_next))
342 hlist_del_init(&agg->nonfull_next); 343 hlist_del_init(&agg->nonfull_next);
344 q->wsum -= agg->class_weight;
345 if (q->wsum != 0)
346 q->iwsum = ONE_FP / q->wsum;
347
343 if (q->in_serv_agg == agg) 348 if (q->in_serv_agg == agg)
344 q->in_serv_agg = qfq_choose_next_agg(q); 349 q->in_serv_agg = qfq_choose_next_agg(q);
345 kfree(agg); 350 kfree(agg);
@@ -827,38 +832,60 @@ static void qfq_make_eligible(struct qfq_sched *q)
827 } 832 }
828} 833}
829 834
830
831/* 835/*
832 * The index of the slot in which the aggregate is to be inserted must 836 * The index of the slot in which the input aggregate agg is to be
833 * not be higher than QFQ_MAX_SLOTS-2. There is a '-2' and not a '-1' 837 * inserted must not be higher than QFQ_MAX_SLOTS-2. There is a '-2'
834 * because the start time of the group may be moved backward by one 838 * and not a '-1' because the start time of the group may be moved
835 * slot after the aggregate has been inserted, and this would cause 839 * backward by one slot after the aggregate has been inserted, and
836 * non-empty slots to be right-shifted by one position. 840 * this would cause non-empty slots to be right-shifted by one
841 * position.
842 *
843 * QFQ+ fully satisfies this bound to the slot index if the parameters
844 * of the classes are not changed dynamically, and if QFQ+ never
845 * happens to postpone the service of agg unjustly, i.e., it never
846 * happens that the aggregate becomes backlogged and eligible, or just
847 * eligible, while an aggregate with a higher approximated finish time
848 * is being served. In particular, in this case QFQ+ guarantees that
849 * the timestamps of agg are low enough that the slot index is never
850 * higher than 2. Unfortunately, QFQ+ cannot provide the same
851 * guarantee if it happens to unjustly postpone the service of agg, or
852 * if the parameters of some class are changed.
853 *
854 * As for the first event, i.e., an out-of-order service, the
855 * upper bound to the slot index guaranteed by QFQ+ grows to
856 * 2 +
857 * QFQ_MAX_AGG_CLASSES * ((1<<QFQ_MTU_SHIFT)/QFQ_MIN_LMAX) *
858 * (current_max_weight/current_wsum) <= 2 + 8 * 128 * 1.
837 * 859 *
838 * If the weight and lmax (max_pkt_size) of the classes do not change, 860 * The following function deals with this problem by backward-shifting
839 * then QFQ+ does meet the above contraint according to the current 861 * the timestamps of agg, if needed, so as to guarantee that the slot
840 * values of its parameters. In fact, if the weight and lmax of the 862 * index is never higher than QFQ_MAX_SLOTS-2. This backward-shift may
841 * classes do not change, then, from the theory, QFQ+ guarantees that 863 * cause the service of other aggregates to be postponed, yet the
842 * the slot index is never higher than 864 * worst-case guarantees of these aggregates are not violated. In
843 * 2 + QFQ_MAX_AGG_CLASSES * ((1<<QFQ_MTU_SHIFT)/QFQ_MIN_LMAX) * 865 * fact, in case of no out-of-order service, the timestamps of agg
844 * (QFQ_MAX_WEIGHT/QFQ_MAX_WSUM) = 2 + 8 * 128 * (1 / 64) = 18 866 * would have been even lower than they are after the backward shift,
867 * because QFQ+ would have guaranteed a maximum value equal to 2 for
868 * the slot index, and 2 < QFQ_MAX_SLOTS-2. Hence the aggregates whose
869 * service is postponed because of the backward-shift would have
870 * however waited for the service of agg before being served.
845 * 871 *
846 * When the weight of a class is increased or the lmax of the class is 872 * The other event that may cause the slot index to be higher than 2
847 * decreased, a new aggregate with smaller slot size than the original 873 * for agg is a recent change of the parameters of some class. If the
848 * parent aggregate of the class may happen to be activated. The 874 * weight of a class is increased or the lmax (max_pkt_size) of the
849 * activation of this aggregate should be properly delayed to when the 875 * class is decreased, then a new aggregate with smaller slot size
850 * service of the class has finished in the ideal system tracked by 876 * than the original parent aggregate of the class may happen to be
851 * QFQ+. If the activation of the aggregate is not delayed to this 877 * activated. The activation of this aggregate should be properly
852 * reference time instant, then this aggregate may be unjustly served 878 * delayed to when the service of the class has finished in the ideal
853 * before other aggregates waiting for service. This may cause the 879 * system tracked by QFQ+. If the activation of the aggregate is not
854 * above bound to the slot index to be violated for some of these 880 * delayed to this reference time instant, then this aggregate may be
855 * unlucky aggregates. 881 * unjustly served before other aggregates waiting for service. This
882 * may cause the above bound to the slot index to be violated for some
883 * of these unlucky aggregates.
856 * 884 *
857 * Instead of delaying the activation of the new aggregate, which is 885 * Instead of delaying the activation of the new aggregate, which is
858 * quite complex, the following inaccurate but simple solution is used: 886 * quite complex, the above-discussed capping of the slot index is
859 * if the slot index is higher than QFQ_MAX_SLOTS-2, then the 887 * used to handle also the consequences of a change of the parameters
860 * timestamps of the aggregate are shifted backward so as to let the 888 * of a class.
861 * slot index become equal to QFQ_MAX_SLOTS-2.
862 */ 889 */
863static void qfq_slot_insert(struct qfq_group *grp, struct qfq_aggregate *agg, 890static void qfq_slot_insert(struct qfq_group *grp, struct qfq_aggregate *agg,
864 u64 roundedS) 891 u64 roundedS)
@@ -1077,7 +1104,7 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch)
1077 else 1104 else
1078 in_serv_agg->budget -= len; 1105 in_serv_agg->budget -= len;
1079 1106
1080 q->V += (u64)len * IWSUM; 1107 q->V += (u64)len * q->iwsum;
1081 pr_debug("qfq dequeue: len %u F %lld now %lld\n", 1108 pr_debug("qfq dequeue: len %u F %lld now %lld\n",
1082 len, (unsigned long long) in_serv_agg->F, 1109 len, (unsigned long long) in_serv_agg->F,
1083 (unsigned long long) q->V); 1110 (unsigned long long) q->V);