]> Git Repo - linux.git/blobdiff - lib/dynamic_queue_limits.c
x86/config: Fix warning for 'make ARCH=x86_64 tinyconfig'
[linux.git] / lib / dynamic_queue_limits.c
index fde0aa2441480032d8ec1b2a42fef62753c0afe2..a1389db1c30a37dda968c65e2ab7145e8728eaf4 100644 (file)
 #include <linux/dynamic_queue_limits.h>
 #include <linux/compiler.h>
 #include <linux/export.h>
+#include <trace/events/napi.h>
 
 #define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0)
 #define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0)
 
+static void dql_check_stall(struct dql *dql)
+{
+       unsigned short stall_thrs;
+       unsigned long now;
+
+       stall_thrs = READ_ONCE(dql->stall_thrs);
+       if (!stall_thrs)
+               return;
+
+       now = jiffies;
+       /* Check for a potential stall */
+       if (time_after_eq(now, dql->last_reap + stall_thrs)) {
+               unsigned long hist_head, t, start, end;
+
+               /* We are trying to detect a period of at least @stall_thrs
+                * jiffies without any Tx completions, but during first half
+                * of which some Tx was posted.
+                */
+dqs_again:
+               hist_head = READ_ONCE(dql->history_head);
+               /* pairs with smp_wmb() in dql_queued() */
+               smp_rmb();
+
+               /* Get the previous entry in the ring buffer, which is the
+                * oldest sample.
+                */
+               start = (hist_head - DQL_HIST_LEN + 1) * BITS_PER_LONG;
+
+               /* Advance start to continue from the last reap time */
+               if (time_before(start, dql->last_reap + 1))
+                       start = dql->last_reap + 1;
+
+               /* Newest sample we should have already seen a completion for */
+               end = hist_head * BITS_PER_LONG + (BITS_PER_LONG - 1);
+
+               /* Shrink the search space to [start, (now - start_thrs/2)] if
+                * `end` is beyond the stall zone
+                */
+               if (time_before(now, end + stall_thrs / 2))
+                       end = now - stall_thrs / 2;
+
+               /* Search for the queued time in [t, end] */
+               for (t = start; time_before_eq(t, end); t++)
+                       if (test_bit(t % (DQL_HIST_LEN * BITS_PER_LONG),
+                                    dql->history))
+                               break;
+
+               /* Variable t contains the time of the queue */
+               if (!time_before_eq(t, end))
+                       goto no_stall;
+
+               /* The ring buffer was modified in the meantime, retry */
+               if (hist_head != READ_ONCE(dql->history_head))
+                       goto dqs_again;
+
+               dql->stall_cnt++;
+               dql->stall_max = max_t(unsigned short, dql->stall_max, now - t);
+
+               trace_dql_stall_detected(dql->stall_thrs, now - t,
+                                        dql->last_reap, dql->history_head,
+                                        now, dql->history);
+       }
+no_stall:
+       dql->last_reap = now;
+}
+
 /* Records completed count and recalculates the queue limit */
 void dql_completed(struct dql *dql, unsigned int count)
 {
@@ -110,6 +177,8 @@ void dql_completed(struct dql *dql, unsigned int count)
        dql->prev_last_obj_cnt = dql->last_obj_cnt;
        dql->num_completed = completed;
        dql->prev_num_queued = num_queued;
+
+       dql_check_stall(dql);
 }
 EXPORT_SYMBOL(dql_completed);
 
@@ -125,6 +194,10 @@ void dql_reset(struct dql *dql)
        dql->prev_ovlimit = 0;
        dql->lowest_slack = UINT_MAX;
        dql->slack_start_time = jiffies;
+
+       dql->last_reap = jiffies;
+       dql->history_head = jiffies / BITS_PER_LONG;
+       memset(dql->history, 0, sizeof(dql->history));
 }
 EXPORT_SYMBOL(dql_reset);
 
@@ -133,6 +206,7 @@ void dql_init(struct dql *dql, unsigned int hold_time)
        dql->max_limit = DQL_MAX_LIMIT;
        dql->min_limit = 0;
        dql->slack_hold_time = hold_time;
+       dql->stall_thrs = 0;
        dql_reset(dql);
 }
 EXPORT_SYMBOL(dql_init);
This page took 0.037826 seconds and 4 git commands to generate.