diff options
| author | Ingo Molnar <mingo@kernel.org> | 2024-03-25 13:32:29 +0300 | 
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2024-03-25 13:32:29 +0300 | 
| commit | f4566a1e73957800df75a3dd2dccee8a4697f327 (patch) | |
| tree | b043b875228c0b25988af66c680d60cae69d761d /lib/dynamic_queue_limits.c | |
| parent | b9e6e28663928cab836a19abbdec3d036a07db3b (diff) | |
| parent | 4cece764965020c22cff7665b18a012006359095 (diff) | |
| download | linux-f4566a1e73957800df75a3dd2dccee8a4697f327.tar.xz | |
Merge tag 'v6.9-rc1' into sched/core, to pick up fixes and to refresh the branch
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'lib/dynamic_queue_limits.c')
| -rw-r--r-- | lib/dynamic_queue_limits.c | 74 | 
1 files changed, 74 insertions, 0 deletions
diff --git a/lib/dynamic_queue_limits.c b/lib/dynamic_queue_limits.c index fde0aa244148..a1389db1c30a 100644 --- a/lib/dynamic_queue_limits.c +++ b/lib/dynamic_queue_limits.c @@ -10,10 +10,77 @@  #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);  | 
