diff mbox series

[-next,RFC,v3,8/8] sbitmap: wake up the number of threads based on required tags

Message ID 20220415101053.554495-9-yukuai3@huawei.com (mailing list archive)
State New, archived
Headers show
Series improve tag allocation under heavy load | expand

Commit Message

Yu Kuai April 15, 2022, 10:10 a.m. UTC
Now that split bios are forced to preemt tag, however, they are unlikely
to get tags continuously because 'wake_batch' threads are woke up each
time while there are only 'wake_batch' tags available.

Since it can be known in advance how many tags are required for huge io,
it's safe to wake up based on required tags, because it can be sure that
wakers will use up 'wake_batch' tags.

Signed-off-by: Yu Kuai <yukuai3@huawei.com>
---
 lib/sbitmap.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/lib/sbitmap.c b/lib/sbitmap.c
index 315e5619b384..5ac5ad1b4b1e 100644
--- a/lib/sbitmap.c
+++ b/lib/sbitmap.c
@@ -633,6 +633,32 @@  static inline void sbq_update_preemption(struct sbitmap_queue *sbq,
 		true : false;
 }
 
+static unsigned int get_wake_nr(struct sbq_wait_state *ws, unsigned int nr_tags)
+{
+	struct sbq_wait *wait;
+	struct wait_queue_entry *entry;
+	unsigned int nr = 1;
+
+	spin_lock_irq(&ws->wait.lock);
+	list_for_each_entry(entry, &ws->wait.head, entry) {
+		wait = container_of(entry, struct sbq_wait, wait);
+		if (nr_tags <= wait->nr_tags) {
+			nr_tags = 0;
+			break;
+		}
+
+		nr++;
+		nr_tags -= wait->nr_tags;
+	}
+	spin_unlock_irq(&ws->wait.lock);
+
+	/*
+	 * If nr_tags is not 0, additional wakeup is triggered to fix the race
+	 * that new threads are waited before wake_up_nr() is called.
+	 */
+	return nr + nr_tags;
+}
+
 static bool __sbq_wake_up(struct sbitmap_queue *sbq)
 {
 	struct sbq_wait_state *ws;
@@ -672,7 +698,7 @@  static bool __sbq_wake_up(struct sbitmap_queue *sbq)
 	smp_mb__before_atomic();
 	atomic_set(&ws->wait_cnt, wake_batch);
 	sbq_update_preemption(sbq, wake_batch);
-	wake_up_nr(&ws->wait, wake_batch);
+	wake_up_nr(&ws->wait, get_wake_nr(ws, wake_batch));
 
 	return false;
 }