--- Begin Message --- I am exploring this idea further. If q->time_next_packet is incremented for dropped packets proportionally to (1-1/x), where x is the count of all flows in the tin that is being served, ingress mode works much more smoothly: latency is still <50ms and throughput is very near to the set limit.

I *tried* to make a patch from latest cobalt.

=============8<=============
diff --git a/sch_cake.c b/sch_cake.c
index 82f264f..752783a 100644
--- a/sch_cake.c
+++ b/sch_cake.c
@@ -145,6 +145,7 @@ struct cake_flow {
        struct list_head  flowchain;
        s32               deficit;
        struct cobalt_vars cvars;
+       struct cobalt_vars cvars2;
        u16               srchost; /* index into cake_host table */
        u16               dsthost;
        u8                set;
@@ -254,6 +255,7 @@ struct cake_sched_data {
        u32             avg_window_bytes;
        u32             avg_peak_bandwidth;
        u64             last_reconfig_time;
+       u32             drop_len;
 };

 enum {
@@ -820,7 +822,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
        sch->qstats.drops++;

        if(q->rate_flags & CAKE_FLAG_INGRESS)
-               cake_advance_shaper(q, b, cake_overhead(q, len), now);
+               q->drop_len += len;

 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
        kfree_skb(skb);
@@ -1274,7 +1276,9 @@ retry:
                /* drop this packet, get another one */
                if(q->rate_flags & CAKE_FLAG_INGRESS) {
                        len = cake_overhead(q, qdisc_pkt_len(skb));
-                       cake_advance_shaper(q, b, len, now);
+                       flow->cvars2.count = b->bulk_flow_count+b->sparse_flow_count+b->decaying_flow_count+b->unresponsive_flow_count;
+                       cobalt_invsqrt(&(flow->cvars2));
+                       q->drop_len += (len - reciprocal_scale(len, flow->cvars2.rec_inv_sqrt));
                        flow->deficit -= len;
                        b->tin_deficit -= len;
                }
@@ -1286,8 +1290,6 @@ retry:
                qdisc_qstats_drop(sch);
                kfree_skb(skb);
 #endif
-               if(q->rate_flags & CAKE_FLAG_INGRESS)
-                       goto retry;
        }

        b->tin_ecn_mark += !!flow->cvars.ecn_marked;
@@ -1340,7 +1342,7 @@ static void cake_advance_shaper(struct cake_sched_data *q, struct cake_tin_data
        if(q->rate_ns) {
                s64 tdiff1 = b->tin_time_next_packet - now;
                s64 tdiff2 = (len * (u64)b->tin_rate_ns) >> b->tin_rate_shft;
-               s64 tdiff3 = (len * (u64)q->rate_ns) >> q->rate_shft;
+               s64 tdiff3 = ((q->drop_len + len) * (u64)q->rate_ns) >> q->rate_shft;

                if(tdiff1 < 0)
                        b->tin_time_next_packet += tdiff2;
@@ -1348,6 +1350,7 @@ static void cake_advance_shaper(struct cake_sched_data *q, struct cake_tin_data
                        b->tin_time_next_packet = now + tdiff2;

                q->time_next_packet += tdiff3;
+               q->drop_len = 0;
        }
 }

@@ -1711,6 +1714,7 @@ static void cake_reconfigure(struct Qdisc *sch)
 {
        struct cake_sched_data *q = qdisc_priv(sch);
        int c, ft;
+       q->drop_len=0;

        switch (q->tin_mode) {
        case CAKE_MODE_BESTEFFORT:
@@ -1941,6 +1945,7 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt)

                        INIT_LIST_HEAD(&flow->flowchain);
                        cobalt_vars_init(&flow->cvars);
+                       cobalt_vars_init(&flow->cvars2);

                        q->overflow_heap[k].t = i;
                        q->overflow_heap[k].b = j;

=============8<=============



On 11/11/2017 10:48 PM, George Amanakis wrote:
I totally understand what you are saying. However, I believe cake's egress and ingress modes currently behave as two extremes. One could argue that neither of them is the golden mean. With a patch in ingress mode (see below) and a single host using 32 flows to download I managed to increase throughput from ~7Mbps to ~10Mbps (configured limit 12200kbps) while latency increased from ~10ms to ~50ms, which would still be acceptable. As a comparison egress mode in the same setup gives me throughput ~11.5Mbps and latency ~500ms.

I would like to hear your thoughts about this idea: the patch is incrementing q->time_next_packet for dropped packets differently than for passed-through ones. Please focus on the idea, not the actual implementation :) (also pasted in https://pastebin.com/SZ14WiYw)

=============8<=============

diff --git a/sch_cake.c b/sch_cake.c
index 82f264f..a3a4a88 100644
--- a/sch_cake.c
+++ b/sch_cake.c
@@ -769,6 +769,7 @@ static void cake_heapify_up(struct cake_sched_data *q, u16 i)
 }

 static void cake_advance_shaper(struct cake_sched_data *q, struct cake_tin_data *b, u32 len, u64 now); +static void cake_advance_shaper2(struct cake_sched_data *q, struct cake_tin_data *b, u32 len, u64 now);

 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
 static unsigned int cake_drop(struct Qdisc *sch)
@@ -1274,7 +1275,7 @@ retry:
                /* drop this packet, get another one */
                if(q->rate_flags & CAKE_FLAG_INGRESS) {
                        len = cake_overhead(q, qdisc_pkt_len(skb));
-                       cake_advance_shaper(q, b, len, now);
+                       cake_advance_shaper2(q, b, len, now);
                        flow->deficit -= len;
                        b->tin_deficit -= len;
                }
@@ -1286,8 +1287,6 @@ retry:
                qdisc_qstats_drop(sch);
                kfree_skb(skb);
 #endif
-               if(q->rate_flags & CAKE_FLAG_INGRESS)
-                       goto retry;
        }

        b->tin_ecn_mark += !!flow->cvars.ecn_marked;
@@ -1351,6 +1350,24 @@ static void cake_advance_shaper(struct cake_sched_data *q, struct cake_tin_data
        }
 }

+static void cake_advance_shaper2(struct cake_sched_data *q, struct cake_tin_data *b, u32 len, u64 now)
+{
+       /* charge packet bandwidth to this tin, lower tins,
+        * and to the global shaper.
+        */
+       if(q->rate_ns) {
+               s64 tdiff1 = b->tin_time_next_packet - now;
+               s64 tdiff2 = (len * (u64)b->tin_rate_ns) >> b->tin_rate_shft;
+               s64 tdiff3 = (len * (u64)q->rate_ns) >> q->rate_shft;
+
+               if(tdiff1 < 0)
+                       b->tin_time_next_packet += tdiff2;
+               else if(tdiff1 < tdiff2)
+                       b->tin_time_next_packet = now + tdiff2;
+
+               q->time_next_packet += (tdiff3*27)>>5;
+       }
+}
 static void cake_reset(struct Qdisc *sch)
 {
        u32 c;

=============8<=============

On 11/10/2017 4:50 PM, Jonathan Morton wrote:

In fact, that's why I put a failsafe into ingress mode, so that it would never stall completely.  It can happen, however, that throughput is significantly reduced when the drop rate is high.

If throughput is more important to you than induced latency, switch to egress mode.

Unfortunately it's not possible to guarantee both low latency and high throughput when operating downstream of the bottleneck link.  ECN gives you better results, though.

- Jonathan Morton




--- End Message ---
_______________________________________________
Cake mailing list
[email protected]
https://lists.bufferbloat.net/listinfo/cake

Reply via email to