* [Cake] progress? dual-src/dsthost unfairness @ 2019-02-13 17:33 Kevin Darbyshire-Bryant 2019-02-13 18:31 ` George Amanakis 0 siblings, 1 reply; 16+ messages in thread From: Kevin Darbyshire-Bryant @ 2019-02-13 17:33 UTC (permalink / raw) To: Cake List Last month there was an extensive thread about dual-src & dual-dst mode unfairness. Has there been any progress on the topic? It seemed to revolve around sparse flows v bulk flows being included in some overall host fairness count/bias. Naive out loud thought experiment…is it worth maintaining a count of sparse flows & bulk flows per host so the sparse group and bulk group are treated separately? Cheers, Kevin D-B 012C ACB2 28C6 C53E 9775 9123 B3A2 389B 9DE2 334A ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Cake] progress? dual-src/dsthost unfairness 2019-02-13 17:33 [Cake] progress? dual-src/dsthost unfairness Kevin Darbyshire-Bryant @ 2019-02-13 18:31 ` George Amanakis 2019-02-13 18:41 ` Jonathan Morton 0 siblings, 1 reply; 16+ messages in thread From: George Amanakis @ 2019-02-13 18:31 UTC (permalink / raw) To: kevin; +Cc: cake, George Amanakis I recently rewrote the patch (out-of-tree cake) so as to keep track of the bulk/sparse flow-count per host. I have been testing it for about a month on a WRT1900ACS and it runs fine. Would love to hear if Jonathan or anybody else has thought of implementing something different. Best, George --- sch_cake.c | 120 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/sch_cake.c b/sch_cake.c index d434ae0..10364ec 100644 --- a/sch_cake.c +++ b/sch_cake.c @@ -146,8 +146,10 @@ struct cake_flow { struct cake_host { u32 srchost_tag; u32 dsthost_tag; - u16 srchost_refcnt; - u16 dsthost_refcnt; + u16 srchost_bulk_flow_count; + u16 srchost_sparse_flow_count; + u16 dsthost_bulk_flow_count; + u16 dsthost_sparse_flow_count; }; struct cake_heap_entry { @@ -844,8 +846,6 @@ skip_hash: * queue, accept the collision, update the host tags. */ q->way_collisions++; - q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--; - q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--; allocate_src = cake_dsrc(flow_mode); allocate_dst = cake_ddst(flow_mode); found: @@ -865,13 +865,13 @@ found: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].srchost_refcnt) + if (!q->hosts[outer_hash + k].srchost_bulk_flow_count && + !q->hosts[outer_hash + k].srchost_sparse_flow_count) break; } q->hosts[outer_hash + k].srchost_tag = srchost_hash; found_src: srchost_idx = outer_hash + k; - q->hosts[srchost_idx].srchost_refcnt++; q->flows[reduced_hash].srchost = srchost_idx; } @@ -887,13 +887,13 @@ found_src: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].dsthost_refcnt) + if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count && + !q->hosts[outer_hash + k].dsthost_sparse_flow_count) break; } q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; found_dst: dsthost_idx = outer_hash + k; - q->hosts[dsthost_idx].dsthost_refcnt++; q->flows[reduced_hash].dsthost = dsthost_idx; } } @@ -1912,21 +1912,39 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, flow->set = CAKE_SET_SPARSE; b->sparse_flow_count++; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); + if (cake_dsrc(q->flow_mode)) { + srchost->srchost_sparse_flow_count++; + host_load = max(host_load, srchost->srchost_sparse_flow_count); + } - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); + if (cake_ddst(q->flow_mode)) { + dsthost->dsthost_sparse_flow_count++; + host_load = max(host_load, dsthost->dsthost_sparse_flow_count); + } flow->deficit = (b->flow_quantum * quantum_div[host_load]) >> 16; } else if (flow->set == CAKE_SET_SPARSE_WAIT) { + struct cake_host *srchost = &b->hosts[flow->srchost]; + struct cake_host *dsthost = &b->hosts[flow->dsthost]; + /* this flow was empty, accounted as a sparse flow, but actually * in the bulk rotation. */ flow->set = CAKE_SET_BULK; b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) { + srchost->srchost_sparse_flow_count--; + srchost->srchost_bulk_flow_count++; + } + + if (cake_ddst(q->flow_mode)) { + dsthost->dsthost_sparse_flow_count--; + dsthost->dsthost_bulk_flow_count++; + } + } if (q->buffer_used > q->buffer_max_used) @@ -2097,23 +2115,8 @@ retry: dsthost = &b->hosts[flow->dsthost]; host_load = 1; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); - - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); - - WARN_ON(host_load > CAKE_QUEUES); - /* flow isolation (DRR++) */ if (flow->deficit <= 0) { - /* The shifted prandom_u32() is a way to apply dithering to - * avoid accumulating roundoff errors - */ - flow->deficit += (b->flow_quantum * quantum_div[host_load] + - (prandom_u32() >> 16)) >> 16; - list_move_tail(&flow->flowchain, &b->old_flows); - /* Keep all flows with deficits out of the sparse and decaying * rotations. No non-empty flow can go into the decaying * rotation, so they can't get deficits @@ -2122,6 +2125,17 @@ retry: if (flow->head) { b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) { + srchost->srchost_sparse_flow_count--; + srchost->srchost_bulk_flow_count++; + } + + if (cake_ddst(q->flow_mode)) { + dsthost->dsthost_sparse_flow_count--; + dsthost->dsthost_bulk_flow_count++; + } + flow->set = CAKE_SET_BULK; } else { /* we've moved it to the bulk rotation for @@ -2131,6 +2145,22 @@ retry: flow->set = CAKE_SET_SPARSE_WAIT; } } + + if (cake_dsrc(q->flow_mode)) + host_load = max(host_load, srchost->srchost_bulk_flow_count); + + if (cake_ddst(q->flow_mode)) + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); + + WARN_ON(host_load > CAKE_QUEUES); + + /* The shifted prandom_u32() is a way to apply dithering to + * avoid accumulating roundoff errors + */ + flow->deficit += (b->flow_quantum * quantum_div[host_load] + + (prandom_u32() >> 16)) >> 16; + list_move_tail(&flow->flowchain, &b->old_flows); + goto retry; } @@ -2151,10 +2181,24 @@ retry: &b->decaying_flows); if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + b->decaying_flow_count++; } else if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) { b->sparse_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_sparse_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_sparse_flow_count--; + b->decaying_flow_count++; } flow->set = CAKE_SET_DECAYING; @@ -2162,16 +2206,28 @@ retry: /* remove empty queue from the flowchain */ list_del_init(&flow->flowchain); if (flow->set == CAKE_SET_SPARSE || - flow->set == CAKE_SET_SPARSE_WAIT) + flow->set == CAKE_SET_SPARSE_WAIT) { b->sparse_flow_count--; - else if (flow->set == CAKE_SET_BULK) + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_sparse_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_sparse_flow_count--; + + } else if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; - else + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + + } else b->decaying_flow_count--; flow->set = CAKE_SET_NONE; - srchost->srchost_refcnt--; - dsthost->dsthost_refcnt--; } goto begin; } -- 2.20.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-13 18:31 ` George Amanakis @ 2019-02-13 18:41 ` Jonathan Morton 2019-02-13 19:26 ` gamanakis 0 siblings, 1 reply; 16+ messages in thread From: Jonathan Morton @ 2019-02-13 18:41 UTC (permalink / raw) To: George Amanakis; +Cc: kevin, cake > On 13 Feb, 2019, at 8:31 pm, George Amanakis <gamanakis@gmail.com> wrote: > > I recently rewrote the patch (out-of-tree cake) so as to keep track of the > bulk/sparse flow-count per host. I have been testing it for about a month > on a WRT1900ACS and it runs fine. > > Would love to hear if Jonathan or anybody else has thought of > implementing something different. This does actually look more reasonable. However: 1: Why is host_load calculated using host_sparse_flow_count instead of host_bulk_flow_count in cake_enqueue()? 2: Do we actually need to maintain host_sparse_flow_count at all, or only the bulk one? If the above is corrected, I don't think there are any uses left. - Jonathan Morton ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-13 18:41 ` Jonathan Morton @ 2019-02-13 19:26 ` gamanakis 2019-02-13 19:31 ` Jonathan Morton 0 siblings, 1 reply; 16+ messages in thread From: gamanakis @ 2019-02-13 19:26 UTC (permalink / raw) To: 'Jonathan Morton'; +Cc: kevin, cake >1: Why is host_load calculated using host_sparse_flow_count instead of host_bulk_flow_count in cake_enqueue()? Because the flow for which cake_enqueue() is run is by definition a sparse one. So the host_load should be adjusted according to the sparse flow count for the particular host. That's my reasoning behing this, would be happy to hear other opinions. >2: Do we actually need to maintain host_sparse_flow_count at all, or only the bulk one? If the above is corrected, I don't think there are any uses left. See above. George ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-13 19:26 ` gamanakis @ 2019-02-13 19:31 ` Jonathan Morton 2019-02-13 19:35 ` gamanakis 0 siblings, 1 reply; 16+ messages in thread From: Jonathan Morton @ 2019-02-13 19:31 UTC (permalink / raw) To: George Amanakis; +Cc: kevin, cake > On 13 Feb, 2019, at 9:26 pm, <gamanakis@gmail.com> <gamanakis@gmail.com> wrote: > > Because the flow for which cake_enqueue() is run is by definition a sparse > one. So the host_load should be adjusted according to the sparse flow count > for the particular host. That's my reasoning behing this, would be happy to > hear other opinions. On the contrary, even if a particular flow is sparse, the relevant quantum calculation should involve the number of *bulk* flows attached to the same host. Though there is possibly an argument for making it the *sum* of the sparse and bulk flows, making it just the sparse ones is wrong. I need to think about this a bit more. But meanwhile, try it with the sum. - Jonathan Morton ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-13 19:31 ` Jonathan Morton @ 2019-02-13 19:35 ` gamanakis 2019-02-13 20:55 ` George Amanakis 2019-02-14 11:15 ` Toke Høiland-Jørgensen 0 siblings, 2 replies; 16+ messages in thread From: gamanakis @ 2019-02-13 19:35 UTC (permalink / raw) To: 'Jonathan Morton'; +Cc: kevin, cake > On the contrary, even if a particular flow is sparse, the relevant quantum > calculation should involve the number of *bulk* flows attached to the same > host. Though there is possibly an argument for making it the *sum* of the > sparse and bulk flows, making it just the sparse ones is wrong. I was about to point out that my assumption is obviously wrong. cake_enqueue() can still assign a packet to a bulk flow. Will try with the sum of the flows and report. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Cake] progress? dual-src/dsthost unfairness 2019-02-13 19:35 ` gamanakis @ 2019-02-13 20:55 ` George Amanakis 2019-02-14 11:15 ` Toke Høiland-Jørgensen 1 sibling, 0 replies; 16+ messages in thread From: George Amanakis @ 2019-02-13 20:55 UTC (permalink / raw) To: chromatix99; +Cc: cake, George Amanakis Updated version with Jonathan's suggestion. Fairness is preserved. enp4s0 enp1s0 Client A/B <------> router <------> server tc qdisc add dev enp1s0 root cake bandwidth 100mbit dual-srchost besteffort tc qdisc add dev enp4s0 root cake bandwidth 100mbit dual-dsthost besteffort -----------8<----------- Client A: Data file written to ./tcp_8down-2019-02-13T150846.110370.flent.gz. Summary of tcp_8down test run at 2019-02-13 20:08:46.110370: avg median # data pts Ping (ms) ICMP : 0.82 0.66 ms 340 TCP download avg : 5.97 5.80 Mbits/s 301 TCP download sum : 47.73 46.42 Mbits/s 301 TCP download::1 : 5.96 5.82 Mbits/s 297 TCP download::2 : 5.96 5.82 Mbits/s 298 TCP download::3 : 5.97 5.82 Mbits/s 297 TCP download::4 : 5.96 5.82 Mbits/s 297 TCP download::5 : 5.97 5.82 Mbits/s 297 TCP download::6 : 5.97 5.82 Mbits/s 297 TCP download::7 : 5.97 5.82 Mbits/s 297 TCP download::8 : 5.97 5.82 Mbits/s 297 Data file written to ./tcp_1up-2019-02-13T150847.148563.flent.gz. Summary of tcp_1up test run at 2019-02-13 20:08:47.148563: avg median # data pts Ping (ms) ICMP : 0.87 0.68 ms 340 TCP upload : 47.46 46.39 Mbits/s 265 Client B: Data file written to ./tcp_1down-2019-02-13T150848.112225.flent.gz. Summary of tcp_1down test run at 2019-02-13 20:08:48.112225: avg median # data pts Ping (ms) ICMP : 0.75 0.65 ms 340 TCP download : 47.50 46.57 Mbits/s 300 Data file written to ./tcp_8up-2019-02-13T150849.120750.flent.gz. Summary of tcp_8up test run at 2019-02-13 20:08:49.120750: avg median # data pts Ping (ms) ICMP : 0.79 0.68 ms 340 TCP upload avg : 5.95 5.78 Mbits/s 301 TCP upload sum : 47.61 46.23 Mbits/s 301 TCP upload::1 : 5.97 5.82 Mbits/s 171 TCP upload::2 : 5.95 5.83 Mbits/s 224 TCP upload::3 : 5.95 5.81 Mbits/s 223 TCP upload::4 : 5.95 5.82 Mbits/s 224 TCP upload::5 : 5.94 5.82 Mbits/s 223 TCP upload::6 : 5.95 5.76 Mbits/s 275 TCP upload::7 : 5.95 5.77 Mbits/s 222 TCP upload::8 : 5.95 5.77 Mbits/s 221 -----------8<----------- --- sch_cake.c | 125 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 32 deletions(-) diff --git a/sch_cake.c b/sch_cake.c index d434ae0..7567378 100644 --- a/sch_cake.c +++ b/sch_cake.c @@ -146,8 +146,10 @@ struct cake_flow { struct cake_host { u32 srchost_tag; u32 dsthost_tag; - u16 srchost_refcnt; - u16 dsthost_refcnt; + u16 srchost_bulk_flow_count; + u16 dsthost_bulk_flow_count; + u16 srchost_sparse_flow_count; + u16 dsthost_sparse_flow_count; }; struct cake_heap_entry { @@ -844,8 +846,6 @@ skip_hash: * queue, accept the collision, update the host tags. */ q->way_collisions++; - q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--; - q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--; allocate_src = cake_dsrc(flow_mode); allocate_dst = cake_ddst(flow_mode); found: @@ -865,13 +865,13 @@ found: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].srchost_refcnt) + if (!q->hosts[outer_hash + k].srchost_bulk_flow_count && + !q->hosts[outer_hash + k].srchost_sparse_flow_count) break; } q->hosts[outer_hash + k].srchost_tag = srchost_hash; found_src: srchost_idx = outer_hash + k; - q->hosts[srchost_idx].srchost_refcnt++; q->flows[reduced_hash].srchost = srchost_idx; } @@ -887,13 +887,13 @@ found_src: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].dsthost_refcnt) + if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count && + !q->hosts[outer_hash + k].dsthost_sparse_flow_count) break; } q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; found_dst: dsthost_idx = outer_hash + k; - q->hosts[dsthost_idx].dsthost_refcnt++; q->flows[reduced_hash].dsthost = dsthost_idx; } } @@ -1901,6 +1901,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (!flow->set || flow->set == CAKE_SET_DECAYING) { struct cake_host *srchost = &b->hosts[flow->srchost]; struct cake_host *dsthost = &b->hosts[flow->dsthost]; + u16 sum; u16 host_load = 1; if (!flow->set) { @@ -1912,21 +1913,43 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, flow->set = CAKE_SET_SPARSE; b->sparse_flow_count++; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); + if (cake_dsrc(q->flow_mode)) { + srchost->srchost_sparse_flow_count++; + sum = srchost->srchost_sparse_flow_count + + srchost->srchost_bulk_flow_count; + host_load = max(host_load, sum); + } - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); + if (cake_ddst(q->flow_mode)) { + dsthost->dsthost_sparse_flow_count++; + sum = dsthost->dsthost_sparse_flow_count + + dsthost->dsthost_bulk_flow_count; + host_load = max(host_load, sum); + } flow->deficit = (b->flow_quantum * quantum_div[host_load]) >> 16; } else if (flow->set == CAKE_SET_SPARSE_WAIT) { + struct cake_host *srchost = &b->hosts[flow->srchost]; + struct cake_host *dsthost = &b->hosts[flow->dsthost]; + /* this flow was empty, accounted as a sparse flow, but actually * in the bulk rotation. */ flow->set = CAKE_SET_BULK; b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) { + srchost->srchost_sparse_flow_count--; + srchost->srchost_bulk_flow_count++; + } + + if (cake_ddst(q->flow_mode)) { + dsthost->dsthost_sparse_flow_count--; + dsthost->dsthost_bulk_flow_count++; + } + } if (q->buffer_used > q->buffer_max_used) @@ -2097,23 +2120,8 @@ retry: dsthost = &b->hosts[flow->dsthost]; host_load = 1; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); - - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); - - WARN_ON(host_load > CAKE_QUEUES); - /* flow isolation (DRR++) */ if (flow->deficit <= 0) { - /* The shifted prandom_u32() is a way to apply dithering to - * avoid accumulating roundoff errors - */ - flow->deficit += (b->flow_quantum * quantum_div[host_load] + - (prandom_u32() >> 16)) >> 16; - list_move_tail(&flow->flowchain, &b->old_flows); - /* Keep all flows with deficits out of the sparse and decaying * rotations. No non-empty flow can go into the decaying * rotation, so they can't get deficits @@ -2122,6 +2130,17 @@ retry: if (flow->head) { b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) { + srchost->srchost_sparse_flow_count--; + srchost->srchost_bulk_flow_count++; + } + + if (cake_ddst(q->flow_mode)) { + dsthost->dsthost_sparse_flow_count--; + dsthost->dsthost_bulk_flow_count++; + } + flow->set = CAKE_SET_BULK; } else { /* we've moved it to the bulk rotation for @@ -2131,6 +2150,22 @@ retry: flow->set = CAKE_SET_SPARSE_WAIT; } } + + if (cake_dsrc(q->flow_mode)) + host_load = max(host_load, srchost->srchost_bulk_flow_count); + + if (cake_ddst(q->flow_mode)) + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); + + WARN_ON(host_load > CAKE_QUEUES); + + /* The shifted prandom_u32() is a way to apply dithering to + * avoid accumulating roundoff errors + */ + flow->deficit += (b->flow_quantum * quantum_div[host_load] + + (prandom_u32() >> 16)) >> 16; + list_move_tail(&flow->flowchain, &b->old_flows); + goto retry; } @@ -2151,10 +2186,24 @@ retry: &b->decaying_flows); if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + b->decaying_flow_count++; } else if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) { b->sparse_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_sparse_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_sparse_flow_count--; + b->decaying_flow_count++; } flow->set = CAKE_SET_DECAYING; @@ -2162,16 +2211,28 @@ retry: /* remove empty queue from the flowchain */ list_del_init(&flow->flowchain); if (flow->set == CAKE_SET_SPARSE || - flow->set == CAKE_SET_SPARSE_WAIT) + flow->set == CAKE_SET_SPARSE_WAIT) { b->sparse_flow_count--; - else if (flow->set == CAKE_SET_BULK) + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_sparse_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_sparse_flow_count--; + + } else if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; - else + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + + } else b->decaying_flow_count--; flow->set = CAKE_SET_NONE; - srchost->srchost_refcnt--; - dsthost->dsthost_refcnt--; } goto begin; } -- 2.20.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-13 19:35 ` gamanakis 2019-02-13 20:55 ` George Amanakis @ 2019-02-14 11:15 ` Toke Høiland-Jørgensen 2019-02-14 18:02 ` George Amanakis 1 sibling, 1 reply; 16+ messages in thread From: Toke Høiland-Jørgensen @ 2019-02-14 11:15 UTC (permalink / raw) To: gamanakis, 'Jonathan Morton'; +Cc: cake gamanakis@gmail.com writes: >> On the contrary, even if a particular flow is sparse, the relevant >> quantum calculation should involve the number of *bulk* flows >> attached to the same host. Though there is possibly an argument for >> making it the *sum* of the sparse and bulk flows, making it just the >> sparse ones is wrong. > > I was about to point out that my assumption is obviously wrong. > cake_enqueue() can still assign a packet to a bulk flow. Will try with > the sum of the flows and report. From a fairness perspective it doesn't really matter whether you count the sparse flows or not. You use this for assigning a single quantum's worth of initial deficit; any flow that actually needs fairness enforced is going to be backlogged anyway, and the deficit increase in bulk state is what matters for enforcing fairness. What the initial quantum does is that it limits how big packet(s) a sparse flow can send before it is demoted to bulk. There are certainly some esoteric cases where this might matter (things like, can a DNS flow get two small back-to-back packets through in one go); but this is going to vary with the traffic conditions anyway, so I doubt it matters in practice. Given this, and given that the state tracking is already plenty complicated, I'd suggest not counting per-host sparse flows at all, and just using the bulk count. I'm pretty sure you'll get the same fairness behaviour in this case. Care to try that? :) -Toke ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Cake] progress? dual-src/dsthost unfairness 2019-02-14 11:15 ` Toke Høiland-Jørgensen @ 2019-02-14 18:02 ` George Amanakis 2019-02-14 18:14 ` Toke Høiland-Jørgensen 2019-02-14 19:00 ` [Cake] progress? dual-src/dsthost unfairness Pete Heist 0 siblings, 2 replies; 16+ messages in thread From: George Amanakis @ 2019-02-14 18:02 UTC (permalink / raw) To: toke; +Cc: cake, chromatix99, George Amanakis I tried Toke's and Jonathan's suggestion, dropping the sparse_flow_count. Tthe results are the same (fairness). In a hash collision in this patch the host_bulk_flow_count is not updated, does this make sense? -------------------8<------------------- Client A: Data file written to ./tcp_8down-2019-02-14T115248.702453.flent.gz. Summary of tcp_8down test run at 2019-02-14 16:52:48.702453: avg median # data pts Ping (ms) ICMP : 0.78 0.69 ms 341 TCP download avg : 6.00 5.81 Mbits/s 301 TCP download sum : 48.00 46.51 Mbits/s 301 TCP download::1 : 6.00 5.82 Mbits/s 297 TCP download::2 : 5.99 5.82 Mbits/s 297 TCP download::3 : 6.00 5.82 Mbits/s 297 TCP download::4 : 6.00 5.82 Mbits/s 297 TCP download::5 : 6.00 5.82 Mbits/s 297 TCP download::6 : 6.00 5.82 Mbits/s 298 TCP download::7 : 6.01 5.82 Mbits/s 297 TCP download::8 : 6.00 5.82 Mbits/s 298 Data file written to ./tcp_1up-2019-02-14T115249.700445.flent.gz. Summary of tcp_1up test run at 2019-02-14 16:52:49.700445: avg median # data pts Ping (ms) ICMP : 0.79 0.69 ms 341 TCP upload : 47.69 46.33 Mbits/s 266 Client B: Data file written to ./tcp_1down-2019-02-14T115250.817948.flent.gz. Summary of tcp_1down test run at 2019-02-14 16:52:50.817948: avg median # data pts Ping (ms) ICMP : 0.83 0.69 ms 341 TCP download : 47.82 46.57 Mbits/s 300 Data file written to ./tcp_8up-2019-02-14T115251.710755.flent.gz. Summary of tcp_8up test run at 2019-02-14 16:52:51.710755: avg median # data pts Ping (ms) ICMP : 0.78 0.69 ms 341 TCP upload avg : 5.99 5.79 Mbits/s 301 TCP upload sum : 47.88 46.30 Mbits/s 301 TCP upload::1 : 5.98 5.81 Mbits/s 224 TCP upload::2 : 5.99 5.82 Mbits/s 224 TCP upload::3 : 5.98 5.77 Mbits/s 219 TCP upload::4 : 5.98 5.82 Mbits/s 224 TCP upload::5 : 5.99 5.77 Mbits/s 218 TCP upload::6 : 5.99 5.77 Mbits/s 221 TCP upload::7 : 5.98 5.77 Mbits/s 219 TCP upload::8 : 5.99 5.77 Mbits/s 221 -------------------8<------------------- --- sch_cake.c | 84 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/sch_cake.c b/sch_cake.c index d434ae0..ed3fbd9 100644 --- a/sch_cake.c +++ b/sch_cake.c @@ -146,8 +146,8 @@ struct cake_flow { struct cake_host { u32 srchost_tag; u32 dsthost_tag; - u16 srchost_refcnt; - u16 dsthost_refcnt; + u16 srchost_bulk_flow_count; + u16 dsthost_bulk_flow_count; }; struct cake_heap_entry { @@ -844,8 +844,6 @@ skip_hash: * queue, accept the collision, update the host tags. */ q->way_collisions++; - q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--; - q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--; allocate_src = cake_dsrc(flow_mode); allocate_dst = cake_ddst(flow_mode); found: @@ -865,13 +863,12 @@ found: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].srchost_refcnt) + if (!q->hosts[outer_hash + k].srchost_bulk_flow_count) break; } q->hosts[outer_hash + k].srchost_tag = srchost_hash; found_src: srchost_idx = outer_hash + k; - q->hosts[srchost_idx].srchost_refcnt++; q->flows[reduced_hash].srchost = srchost_idx; } @@ -887,13 +884,12 @@ found_src: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].dsthost_refcnt) + if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count) break; } q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; found_dst: dsthost_idx = outer_hash + k; - q->hosts[dsthost_idx].dsthost_refcnt++; q->flows[reduced_hash].dsthost = dsthost_idx; } } @@ -1913,20 +1909,30 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, b->sparse_flow_count++; if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); + host_load = max(host_load, srchost->srchost_bulk_flow_count); if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); flow->deficit = (b->flow_quantum * quantum_div[host_load]) >> 16; } else if (flow->set == CAKE_SET_SPARSE_WAIT) { + struct cake_host *srchost = &b->hosts[flow->srchost]; + struct cake_host *dsthost = &b->hosts[flow->dsthost]; + /* this flow was empty, accounted as a sparse flow, but actually * in the bulk rotation. */ flow->set = CAKE_SET_BULK; b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count++; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count++; + } if (q->buffer_used > q->buffer_max_used) @@ -2097,23 +2103,8 @@ retry: dsthost = &b->hosts[flow->dsthost]; host_load = 1; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); - - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); - - WARN_ON(host_load > CAKE_QUEUES); - /* flow isolation (DRR++) */ if (flow->deficit <= 0) { - /* The shifted prandom_u32() is a way to apply dithering to - * avoid accumulating roundoff errors - */ - flow->deficit += (b->flow_quantum * quantum_div[host_load] + - (prandom_u32() >> 16)) >> 16; - list_move_tail(&flow->flowchain, &b->old_flows); - /* Keep all flows with deficits out of the sparse and decaying * rotations. No non-empty flow can go into the decaying * rotation, so they can't get deficits @@ -2122,6 +2113,13 @@ retry: if (flow->head) { b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count++; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count++; + flow->set = CAKE_SET_BULK; } else { /* we've moved it to the bulk rotation for @@ -2131,6 +2129,22 @@ retry: flow->set = CAKE_SET_SPARSE_WAIT; } } + + if (cake_dsrc(q->flow_mode)) + host_load = max(host_load, srchost->srchost_bulk_flow_count); + + if (cake_ddst(q->flow_mode)) + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); + + WARN_ON(host_load > CAKE_QUEUES); + + /* The shifted prandom_u32() is a way to apply dithering to + * avoid accumulating roundoff errors + */ + flow->deficit += (b->flow_quantum * quantum_div[host_load] + + (prandom_u32() >> 16)) >> 16; + list_move_tail(&flow->flowchain, &b->old_flows); + goto retry; } @@ -2151,6 +2165,13 @@ retry: &b->decaying_flows); if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + b->decaying_flow_count++; } else if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) { @@ -2164,14 +2185,19 @@ retry: if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) b->sparse_flow_count--; - else if (flow->set == CAKE_SET_BULK) + else if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; - else + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + + } else b->decaying_flow_count--; flow->set = CAKE_SET_NONE; - srchost->srchost_refcnt--; - dsthost->dsthost_refcnt--; } goto begin; } -- 2.20.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-14 18:02 ` George Amanakis @ 2019-02-14 18:14 ` Toke Høiland-Jørgensen 2019-02-14 18:45 ` [Cake] Make the dual modes fairer George Amanakis 2019-02-14 19:07 ` [Cake] progress? dual-src/dsthost unfairness Jonathan Morton 2019-02-14 19:00 ` [Cake] progress? dual-src/dsthost unfairness Pete Heist 1 sibling, 2 replies; 16+ messages in thread From: Toke Høiland-Jørgensen @ 2019-02-14 18:14 UTC (permalink / raw) To: George Amanakis; +Cc: cake, chromatix99, George Amanakis George Amanakis <gamanakis@gmail.com> writes: > I tried Toke's and Jonathan's suggestion, dropping the > sparse_flow_count. Tthe results are the same (fairness). > In a hash collision in this patch the host_bulk_flow_count is not updated, > does this make sense? Yeah, think so; it should be updated later when that flow transitions to bulk. Care to resend with a proper commit message + signed-off-by line (or open a pull request on github)? I figure we can put it into the github repo for a bit more testing before submitting a patch upstream :) -Toke ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Cake] Make the dual modes fairer 2019-02-14 18:14 ` Toke Høiland-Jørgensen @ 2019-02-14 18:45 ` George Amanakis 2019-02-14 19:07 ` [Cake] progress? dual-src/dsthost unfairness Jonathan Morton 1 sibling, 0 replies; 16+ messages in thread From: George Amanakis @ 2019-02-14 18:45 UTC (permalink / raw) To: toke; +Cc: cake, chromatix99, George Amanakis, Pete Heist Host fairness does not work well with TCP flows in dual-srchost, and dual-dsthost setup. The reason is that ACKs generated by TCP flows are classified as sparse flows and affect flow isolation from other hosts. Fix this by calculating host_load based only on the bulk flows a host generates. Reported-by: Pete Heist <peteheist@gmail.com> Signed-off-by: George Amanakis <gamanakis@gmail.com> --- sch_cake.c | 84 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/sch_cake.c b/sch_cake.c index d434ae0..ed3fbd9 100644 --- a/sch_cake.c +++ b/sch_cake.c @@ -146,8 +146,8 @@ struct cake_flow { struct cake_host { u32 srchost_tag; u32 dsthost_tag; - u16 srchost_refcnt; - u16 dsthost_refcnt; + u16 srchost_bulk_flow_count; + u16 dsthost_bulk_flow_count; }; struct cake_heap_entry { @@ -844,8 +844,6 @@ skip_hash: * queue, accept the collision, update the host tags. */ q->way_collisions++; - q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--; - q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--; allocate_src = cake_dsrc(flow_mode); allocate_dst = cake_ddst(flow_mode); found: @@ -865,13 +863,12 @@ found: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].srchost_refcnt) + if (!q->hosts[outer_hash + k].srchost_bulk_flow_count) break; } q->hosts[outer_hash + k].srchost_tag = srchost_hash; found_src: srchost_idx = outer_hash + k; - q->hosts[srchost_idx].srchost_refcnt++; q->flows[reduced_hash].srchost = srchost_idx; } @@ -887,13 +884,12 @@ found_src: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].dsthost_refcnt) + if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count) break; } q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; found_dst: dsthost_idx = outer_hash + k; - q->hosts[dsthost_idx].dsthost_refcnt++; q->flows[reduced_hash].dsthost = dsthost_idx; } } @@ -1913,20 +1909,30 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, b->sparse_flow_count++; if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); + host_load = max(host_load, srchost->srchost_bulk_flow_count); if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); flow->deficit = (b->flow_quantum * quantum_div[host_load]) >> 16; } else if (flow->set == CAKE_SET_SPARSE_WAIT) { + struct cake_host *srchost = &b->hosts[flow->srchost]; + struct cake_host *dsthost = &b->hosts[flow->dsthost]; + /* this flow was empty, accounted as a sparse flow, but actually * in the bulk rotation. */ flow->set = CAKE_SET_BULK; b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count++; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count++; + } if (q->buffer_used > q->buffer_max_used) @@ -2097,23 +2103,8 @@ retry: dsthost = &b->hosts[flow->dsthost]; host_load = 1; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); - - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); - - WARN_ON(host_load > CAKE_QUEUES); - /* flow isolation (DRR++) */ if (flow->deficit <= 0) { - /* The shifted prandom_u32() is a way to apply dithering to - * avoid accumulating roundoff errors - */ - flow->deficit += (b->flow_quantum * quantum_div[host_load] + - (prandom_u32() >> 16)) >> 16; - list_move_tail(&flow->flowchain, &b->old_flows); - /* Keep all flows with deficits out of the sparse and decaying * rotations. No non-empty flow can go into the decaying * rotation, so they can't get deficits @@ -2122,6 +2113,13 @@ retry: if (flow->head) { b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count++; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count++; + flow->set = CAKE_SET_BULK; } else { /* we've moved it to the bulk rotation for @@ -2131,6 +2129,22 @@ retry: flow->set = CAKE_SET_SPARSE_WAIT; } } + + if (cake_dsrc(q->flow_mode)) + host_load = max(host_load, srchost->srchost_bulk_flow_count); + + if (cake_ddst(q->flow_mode)) + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); + + WARN_ON(host_load > CAKE_QUEUES); + + /* The shifted prandom_u32() is a way to apply dithering to + * avoid accumulating roundoff errors + */ + flow->deficit += (b->flow_quantum * quantum_div[host_load] + + (prandom_u32() >> 16)) >> 16; + list_move_tail(&flow->flowchain, &b->old_flows); + goto retry; } @@ -2151,6 +2165,13 @@ retry: &b->decaying_flows); if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + b->decaying_flow_count++; } else if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) { @@ -2164,14 +2185,19 @@ retry: if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) b->sparse_flow_count--; - else if (flow->set == CAKE_SET_BULK) + else if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; - else + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + + } else b->decaying_flow_count--; flow->set = CAKE_SET_NONE; - srchost->srchost_refcnt--; - dsthost->dsthost_refcnt--; } goto begin; } -- 2.20.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-14 18:14 ` Toke Høiland-Jørgensen 2019-02-14 18:45 ` [Cake] Make the dual modes fairer George Amanakis @ 2019-02-14 19:07 ` Jonathan Morton 2019-02-14 20:27 ` gamanakis 1 sibling, 1 reply; 16+ messages in thread From: Jonathan Morton @ 2019-02-14 19:07 UTC (permalink / raw) To: Toke Høiland-Jørgensen; +Cc: George Amanakis, cake >> I tried Toke's and Jonathan's suggestion, dropping the >> sparse_flow_count. Tthe results are the same (fairness). >> In a hash collision in this patch the host_bulk_flow_count is not updated, >> does this make sense? > > Yeah, think so; it should be updated later when that flow transitions to > bulk. > > Care to resend with a proper commit message + signed-off-by line (or > open a pull request on github)? I figure we can put it into the github > repo for a bit more testing before submitting a patch upstream :) The important thing is that the host_bulk_flow_count values match the actual bulk-status and host-reference properties assigned to each flow queue. When a hash collision occurs, the bulk-status of the affected flow doesn't change but the hosts to which it refers might do. In that case the host_bulk_flow_count values must be decremented on the old hosts and incremented on the new ones *if* the queue is in the bulk set. - Jonathan Morton ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-14 19:07 ` [Cake] progress? dual-src/dsthost unfairness Jonathan Morton @ 2019-02-14 20:27 ` gamanakis 2019-02-14 21:22 ` [Cake] Make the dual modes fairer George Amanakis 0 siblings, 1 reply; 16+ messages in thread From: gamanakis @ 2019-02-14 20:27 UTC (permalink / raw) To: 'Jonathan Morton', 'Toke Høiland-Jørgensen' Cc: cake > The important thing is that the host_bulk_flow_count values match the > actual bulk-status and host-reference properties assigned to each flow > queue. When a hash collision occurs, the bulk-status of the affected flow > doesn't change but the hosts to which it refers might do. In that case the > host_bulk_flow_count values must be decremented on the old hosts and > incremented on the new ones *if* the queue is in the bulk set. Thanks for the clarification, I think I get it. Have to rewrite that part. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Cake] Make the dual modes fairer 2019-02-14 20:27 ` gamanakis @ 2019-02-14 21:22 ` George Amanakis 2019-02-14 21:59 ` Toke Høiland-Jørgensen 0 siblings, 1 reply; 16+ messages in thread From: George Amanakis @ 2019-02-14 21:22 UTC (permalink / raw) To: chromatix99; +Cc: cake, toke, George Amanakis, Pete Heist Host fairness does not work well with TCP flows in dual-srchost and dual-dsthost setup. The reason is that ACKs generated by TCP flows are classified as sparse flows, and affect flow isolation from other hosts. Fix this by calculating host_load based only on the bulk flows a host generates. In a hash collision the host_bulk_flow_count values must be decremented on the old hosts and incremented on the new ones *if* the queue is in the bulk set. Reported-by: Pete Heist <peteheist@gmail.com> Signed-off-by: George Amanakis <gamanakis@gmail.com> --- sch_cake.c | 92 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/sch_cake.c b/sch_cake.c index d434ae0..7ddbe37 100644 --- a/sch_cake.c +++ b/sch_cake.c @@ -146,8 +146,8 @@ struct cake_flow { struct cake_host { u32 srchost_tag; u32 dsthost_tag; - u16 srchost_refcnt; - u16 dsthost_refcnt; + u16 srchost_bulk_flow_count; + u16 dsthost_bulk_flow_count; }; struct cake_heap_entry { @@ -844,8 +844,10 @@ skip_hash: * queue, accept the collision, update the host tags. */ q->way_collisions++; - q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--; - q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--; + if (q->flows[outer_hash + k].set == CAKE_SET_BULK) { + q->hosts[q->flows[reduced_hash].srchost].srchost_bulk_flow_count--; + q->hosts[q->flows[reduced_hash].dsthost].dsthost_bulk_flow_count--; + } allocate_src = cake_dsrc(flow_mode); allocate_dst = cake_ddst(flow_mode); found: @@ -865,13 +867,14 @@ found: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].srchost_refcnt) + if (!q->hosts[outer_hash + k].srchost_bulk_flow_count) break; } q->hosts[outer_hash + k].srchost_tag = srchost_hash; found_src: srchost_idx = outer_hash + k; - q->hosts[srchost_idx].srchost_refcnt++; + if (q->flows[reduced_hash].set == CAKE_SET_BULK) + q->hosts[srchost_idx].srchost_bulk_flow_count++; q->flows[reduced_hash].srchost = srchost_idx; } @@ -887,13 +890,14 @@ found_src: } for (i = 0; i < CAKE_SET_WAYS; i++, k = (k + 1) % CAKE_SET_WAYS) { - if (!q->hosts[outer_hash + k].dsthost_refcnt) + if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count) break; } q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; found_dst: dsthost_idx = outer_hash + k; - q->hosts[dsthost_idx].dsthost_refcnt++; + if (q->flows[reduced_hash].set == CAKE_SET_BULK) + q->hosts[dsthost_idx].dsthost_bulk_flow_count++; q->flows[reduced_hash].dsthost = dsthost_idx; } } @@ -1913,20 +1917,30 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, b->sparse_flow_count++; if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); + host_load = max(host_load, srchost->srchost_bulk_flow_count); if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); flow->deficit = (b->flow_quantum * quantum_div[host_load]) >> 16; } else if (flow->set == CAKE_SET_SPARSE_WAIT) { + struct cake_host *srchost = &b->hosts[flow->srchost]; + struct cake_host *dsthost = &b->hosts[flow->dsthost]; + /* this flow was empty, accounted as a sparse flow, but actually * in the bulk rotation. */ flow->set = CAKE_SET_BULK; b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count++; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count++; + } if (q->buffer_used > q->buffer_max_used) @@ -2097,23 +2111,8 @@ retry: dsthost = &b->hosts[flow->dsthost]; host_load = 1; - if (cake_dsrc(q->flow_mode)) - host_load = max(host_load, srchost->srchost_refcnt); - - if (cake_ddst(q->flow_mode)) - host_load = max(host_load, dsthost->dsthost_refcnt); - - WARN_ON(host_load > CAKE_QUEUES); - /* flow isolation (DRR++) */ if (flow->deficit <= 0) { - /* The shifted prandom_u32() is a way to apply dithering to - * avoid accumulating roundoff errors - */ - flow->deficit += (b->flow_quantum * quantum_div[host_load] + - (prandom_u32() >> 16)) >> 16; - list_move_tail(&flow->flowchain, &b->old_flows); - /* Keep all flows with deficits out of the sparse and decaying * rotations. No non-empty flow can go into the decaying * rotation, so they can't get deficits @@ -2122,6 +2121,13 @@ retry: if (flow->head) { b->sparse_flow_count--; b->bulk_flow_count++; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count++; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count++; + flow->set = CAKE_SET_BULK; } else { /* we've moved it to the bulk rotation for @@ -2131,6 +2137,22 @@ retry: flow->set = CAKE_SET_SPARSE_WAIT; } } + + if (cake_dsrc(q->flow_mode)) + host_load = max(host_load, srchost->srchost_bulk_flow_count); + + if (cake_ddst(q->flow_mode)) + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); + + WARN_ON(host_load > CAKE_QUEUES); + + /* The shifted prandom_u32() is a way to apply dithering to + * avoid accumulating roundoff errors + */ + flow->deficit += (b->flow_quantum * quantum_div[host_load] + + (prandom_u32() >> 16)) >> 16; + list_move_tail(&flow->flowchain, &b->old_flows); + goto retry; } @@ -2151,6 +2173,13 @@ retry: &b->decaying_flows); if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + b->decaying_flow_count++; } else if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) { @@ -2164,14 +2193,19 @@ retry: if (flow->set == CAKE_SET_SPARSE || flow->set == CAKE_SET_SPARSE_WAIT) b->sparse_flow_count--; - else if (flow->set == CAKE_SET_BULK) + else if (flow->set == CAKE_SET_BULK) { b->bulk_flow_count--; - else + + if (cake_dsrc(q->flow_mode)) + srchost->srchost_bulk_flow_count--; + + if (cake_ddst(q->flow_mode)) + dsthost->dsthost_bulk_flow_count--; + + } else b->decaying_flow_count--; flow->set = CAKE_SET_NONE; - srchost->srchost_refcnt--; - dsthost->dsthost_refcnt--; } goto begin; } -- 2.20.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] Make the dual modes fairer 2019-02-14 21:22 ` [Cake] Make the dual modes fairer George Amanakis @ 2019-02-14 21:59 ` Toke Høiland-Jørgensen 0 siblings, 0 replies; 16+ messages in thread From: Toke Høiland-Jørgensen @ 2019-02-14 21:59 UTC (permalink / raw) To: George Amanakis, chromatix99; +Cc: cake, George Amanakis, Pete Heist George Amanakis <gamanakis@gmail.com> writes: > Host fairness does not work well with TCP flows in dual-srchost and > dual-dsthost setup. The reason is that ACKs generated by TCP flows > are classified as sparse flows, and affect flow isolation from other > hosts. Fix this by calculating host_load based only on the bulk flows > a host generates. In a hash collision the host_bulk_flow_count values must > be decremented on the old hosts and incremented on the new ones *if* the > queue is in the bulk set. Right, thanks! Pushed this to master; go forth and test, everyone! :) -Toke ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Cake] progress? dual-src/dsthost unfairness 2019-02-14 18:02 ` George Amanakis 2019-02-14 18:14 ` Toke Høiland-Jørgensen @ 2019-02-14 19:00 ` Pete Heist 1 sibling, 0 replies; 16+ messages in thread From: Pete Heist @ 2019-02-14 19:00 UTC (permalink / raw) To: George Amanakis; +Cc: toke, cake Thanks for the work on this George! That’s a nice step forward for Cake’s fairness with bi-directional traffic. :) I’ll try some tests when I get a chance... > On Feb 14, 2019, at 7:02 PM, George Amanakis <gamanakis@gmail.com> wrote: > > I tried Toke's and Jonathan's suggestion, dropping the > sparse_flow_count. Tthe results are the same (fairness). > In a hash collision in this patch the host_bulk_flow_count is not updated, > does this make sense? > > -------------------8<------------------- > Client A: > Data file written to ./tcp_8down-2019-02-14T115248.702453.flent.gz. > Summary of tcp_8down test run at 2019-02-14 16:52:48.702453: > > avg median # data pts > Ping (ms) ICMP : 0.78 0.69 ms 341 > TCP download avg : 6.00 5.81 Mbits/s 301 > TCP download sum : 48.00 46.51 Mbits/s 301 > TCP download::1 : 6.00 5.82 Mbits/s 297 > TCP download::2 : 5.99 5.82 Mbits/s 297 > TCP download::3 : 6.00 5.82 Mbits/s 297 > TCP download::4 : 6.00 5.82 Mbits/s 297 > TCP download::5 : 6.00 5.82 Mbits/s 297 > TCP download::6 : 6.00 5.82 Mbits/s 298 > TCP download::7 : 6.01 5.82 Mbits/s 297 > TCP download::8 : 6.00 5.82 Mbits/s 298 > Data file written to ./tcp_1up-2019-02-14T115249.700445.flent.gz. > Summary of tcp_1up test run at 2019-02-14 16:52:49.700445: > > avg median # data pts > Ping (ms) ICMP : 0.79 0.69 ms 341 > TCP upload : 47.69 46.33 Mbits/s 266 > > > > Client B: > Data file written to ./tcp_1down-2019-02-14T115250.817948.flent.gz. > Summary of tcp_1down test run at 2019-02-14 16:52:50.817948: > > avg median # data pts > Ping (ms) ICMP : 0.83 0.69 ms 341 > TCP download : 47.82 46.57 Mbits/s 300 > Data file written to ./tcp_8up-2019-02-14T115251.710755.flent.gz. > Summary of tcp_8up test run at 2019-02-14 16:52:51.710755: > > avg median # data pts > Ping (ms) ICMP : 0.78 0.69 ms 341 > TCP upload avg : 5.99 5.79 Mbits/s 301 > TCP upload sum : 47.88 46.30 Mbits/s 301 > TCP upload::1 : 5.98 5.81 Mbits/s 224 > TCP upload::2 : 5.99 5.82 Mbits/s 224 > TCP upload::3 : 5.98 5.77 Mbits/s 219 > TCP upload::4 : 5.98 5.82 Mbits/s 224 > TCP upload::5 : 5.99 5.77 Mbits/s 218 > TCP upload::6 : 5.99 5.77 Mbits/s 221 > TCP upload::7 : 5.98 5.77 Mbits/s 219 > TCP upload::8 : 5.99 5.77 Mbits/s 221 > -------------------8<------------------- > > > --- > sch_cake.c | 84 +++++++++++++++++++++++++++++++++++------------------- > 1 file changed, 55 insertions(+), 29 deletions(-) > > diff --git a/sch_cake.c b/sch_cake.c > index d434ae0..ed3fbd9 100644 > --- a/sch_cake.c > +++ b/sch_cake.c > @@ -146,8 +146,8 @@ struct cake_flow { > struct cake_host { > u32 srchost_tag; > u32 dsthost_tag; > - u16 srchost_refcnt; > - u16 dsthost_refcnt; > + u16 srchost_bulk_flow_count; > + u16 dsthost_bulk_flow_count; > }; > > struct cake_heap_entry { > @@ -844,8 +844,6 @@ skip_hash: > * queue, accept the collision, update the host tags. > */ > q->way_collisions++; > - q->hosts[q->flows[reduced_hash].srchost].srchost_refcnt--; > - q->hosts[q->flows[reduced_hash].dsthost].dsthost_refcnt--; > allocate_src = cake_dsrc(flow_mode); > allocate_dst = cake_ddst(flow_mode); > found: > @@ -865,13 +863,12 @@ found: > } > for (i = 0; i < CAKE_SET_WAYS; > i++, k = (k + 1) % CAKE_SET_WAYS) { > - if (!q->hosts[outer_hash + k].srchost_refcnt) > + if (!q->hosts[outer_hash + k].srchost_bulk_flow_count) > break; > } > q->hosts[outer_hash + k].srchost_tag = srchost_hash; > found_src: > srchost_idx = outer_hash + k; > - q->hosts[srchost_idx].srchost_refcnt++; > q->flows[reduced_hash].srchost = srchost_idx; > } > > @@ -887,13 +884,12 @@ found_src: > } > for (i = 0; i < CAKE_SET_WAYS; > i++, k = (k + 1) % CAKE_SET_WAYS) { > - if (!q->hosts[outer_hash + k].dsthost_refcnt) > + if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count) > break; > } > q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; > found_dst: > dsthost_idx = outer_hash + k; > - q->hosts[dsthost_idx].dsthost_refcnt++; > q->flows[reduced_hash].dsthost = dsthost_idx; > } > } > @@ -1913,20 +1909,30 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, > b->sparse_flow_count++; > > if (cake_dsrc(q->flow_mode)) > - host_load = max(host_load, srchost->srchost_refcnt); > + host_load = max(host_load, srchost->srchost_bulk_flow_count); > > if (cake_ddst(q->flow_mode)) > - host_load = max(host_load, dsthost->dsthost_refcnt); > + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); > > flow->deficit = (b->flow_quantum * > quantum_div[host_load]) >> 16; > } else if (flow->set == CAKE_SET_SPARSE_WAIT) { > + struct cake_host *srchost = &b->hosts[flow->srchost]; > + struct cake_host *dsthost = &b->hosts[flow->dsthost]; > + > /* this flow was empty, accounted as a sparse flow, but actually > * in the bulk rotation. > */ > flow->set = CAKE_SET_BULK; > b->sparse_flow_count--; > b->bulk_flow_count++; > + > + if (cake_dsrc(q->flow_mode)) > + srchost->srchost_bulk_flow_count++; > + > + if (cake_ddst(q->flow_mode)) > + dsthost->dsthost_bulk_flow_count++; > + > } > > if (q->buffer_used > q->buffer_max_used) > @@ -2097,23 +2103,8 @@ retry: > dsthost = &b->hosts[flow->dsthost]; > host_load = 1; > > - if (cake_dsrc(q->flow_mode)) > - host_load = max(host_load, srchost->srchost_refcnt); > - > - if (cake_ddst(q->flow_mode)) > - host_load = max(host_load, dsthost->dsthost_refcnt); > - > - WARN_ON(host_load > CAKE_QUEUES); > - > /* flow isolation (DRR++) */ > if (flow->deficit <= 0) { > - /* The shifted prandom_u32() is a way to apply dithering to > - * avoid accumulating roundoff errors > - */ > - flow->deficit += (b->flow_quantum * quantum_div[host_load] + > - (prandom_u32() >> 16)) >> 16; > - list_move_tail(&flow->flowchain, &b->old_flows); > - > /* Keep all flows with deficits out of the sparse and decaying > * rotations. No non-empty flow can go into the decaying > * rotation, so they can't get deficits > @@ -2122,6 +2113,13 @@ retry: > if (flow->head) { > b->sparse_flow_count--; > b->bulk_flow_count++; > + > + if (cake_dsrc(q->flow_mode)) > + srchost->srchost_bulk_flow_count++; > + > + if (cake_ddst(q->flow_mode)) > + dsthost->dsthost_bulk_flow_count++; > + > flow->set = CAKE_SET_BULK; > } else { > /* we've moved it to the bulk rotation for > @@ -2131,6 +2129,22 @@ retry: > flow->set = CAKE_SET_SPARSE_WAIT; > } > } > + > + if (cake_dsrc(q->flow_mode)) > + host_load = max(host_load, srchost->srchost_bulk_flow_count); > + > + if (cake_ddst(q->flow_mode)) > + host_load = max(host_load, dsthost->dsthost_bulk_flow_count); > + > + WARN_ON(host_load > CAKE_QUEUES); > + > + /* The shifted prandom_u32() is a way to apply dithering to > + * avoid accumulating roundoff errors > + */ > + flow->deficit += (b->flow_quantum * quantum_div[host_load] + > + (prandom_u32() >> 16)) >> 16; > + list_move_tail(&flow->flowchain, &b->old_flows); > + > goto retry; > } > > @@ -2151,6 +2165,13 @@ retry: > &b->decaying_flows); > if (flow->set == CAKE_SET_BULK) { > b->bulk_flow_count--; > + > + if (cake_dsrc(q->flow_mode)) > + srchost->srchost_bulk_flow_count--; > + > + if (cake_ddst(q->flow_mode)) > + dsthost->dsthost_bulk_flow_count--; > + > b->decaying_flow_count++; > } else if (flow->set == CAKE_SET_SPARSE || > flow->set == CAKE_SET_SPARSE_WAIT) { > @@ -2164,14 +2185,19 @@ retry: > if (flow->set == CAKE_SET_SPARSE || > flow->set == CAKE_SET_SPARSE_WAIT) > b->sparse_flow_count--; > - else if (flow->set == CAKE_SET_BULK) > + else if (flow->set == CAKE_SET_BULK) { > b->bulk_flow_count--; > - else > + > + if (cake_dsrc(q->flow_mode)) > + srchost->srchost_bulk_flow_count--; > + > + if (cake_ddst(q->flow_mode)) > + dsthost->dsthost_bulk_flow_count--; > + > + } else > b->decaying_flow_count--; > > flow->set = CAKE_SET_NONE; > - srchost->srchost_refcnt--; > - dsthost->dsthost_refcnt--; > } > goto begin; > } > -- > 2.20.1 > > _______________________________________________ > Cake mailing list > Cake@lists.bufferbloat.net > https://lists.bufferbloat.net/listinfo/cake ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2019-02-14 21:59 UTC | newest] Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-02-13 17:33 [Cake] progress? dual-src/dsthost unfairness Kevin Darbyshire-Bryant 2019-02-13 18:31 ` George Amanakis 2019-02-13 18:41 ` Jonathan Morton 2019-02-13 19:26 ` gamanakis 2019-02-13 19:31 ` Jonathan Morton 2019-02-13 19:35 ` gamanakis 2019-02-13 20:55 ` George Amanakis 2019-02-14 11:15 ` Toke Høiland-Jørgensen 2019-02-14 18:02 ` George Amanakis 2019-02-14 18:14 ` Toke Høiland-Jørgensen 2019-02-14 18:45 ` [Cake] Make the dual modes fairer George Amanakis 2019-02-14 19:07 ` [Cake] progress? dual-src/dsthost unfairness Jonathan Morton 2019-02-14 20:27 ` gamanakis 2019-02-14 21:22 ` [Cake] Make the dual modes fairer George Amanakis 2019-02-14 21:59 ` Toke Høiland-Jørgensen 2019-02-14 19:00 ` [Cake] progress? dual-src/dsthost unfairness Pete Heist
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox