mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] block: plug attempts to batch allocate tags multiple times
@ 2025-09-18  7:55 Xue He
       [not found] ` <CGME20250924053907epcas5p10c550389234cb8feff8e5625d1d3d2a1@epcas5p1.samsung.com>
  0 siblings, 1 reply; 10+ messages in thread
From: Xue He @ 2025-09-18  7:55 UTC (permalink / raw)
  To: axboe, akpm; +Cc: linux-block, linux-kernel, hexue

In the existing plug mechanism, tags are allocated in batches based on
the number of requests. However, testing has shown that the plug only
attempts batch allocation of tags once at the beginning of a batch of
I/O operations. Since the tag_mask does not always have enough available
tags to satisfy the requested number, a full batch allocation is not
guaranteed to succeed each time. The remaining tags are then allocated
individually (occurs frequently), leading to multiple single-tag
allocation overheads.

This patch aims to retry batch allocation of tags when the initial batch
allocation fails to reach the requested number, thereby reducing the
overhead of individual allocation attempts.

--------------------------------------------------------------------
perf:
base code: __blk_mq_alloc_requests() 1.33%
patch:__blk_mq_alloc_requests() 0.72%
-------------------------------------------------------------------

Signed-off-by: hexue <xue01.he@samsung.com>
---
 block/blk-mq.c | 43 +++++++++++++++++++++++--------------------
 lib/sbitmap.c  |  7 ++++---
 2 files changed, 27 insertions(+), 23 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index ba3a4b77f578..3ed8da176831 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -456,28 +456,31 @@ __blk_mq_alloc_requests_batch(struct blk_mq_alloc_data *data)
 	struct blk_mq_tags *tags;
 	struct request *rq;
 	unsigned long tag_mask;
-	int i, nr = 0;
 
-	tag_mask = blk_mq_get_tags(data, data->nr_tags, &tag_offset);
-	if (unlikely(!tag_mask))
-		return NULL;
+	do {
+		int i, nr = 0;
 
-	tags = blk_mq_tags_from_data(data);
-	for (i = 0; tag_mask; i++) {
-		if (!(tag_mask & (1UL << i)))
-			continue;
-		tag = tag_offset + i;
-		prefetch(tags->static_rqs[tag]);
-		tag_mask &= ~(1UL << i);
-		rq = blk_mq_rq_ctx_init(data, tags, tag);
-		rq_list_add_head(data->cached_rqs, rq);
-		nr++;
-	}
-	if (!(data->rq_flags & RQF_SCHED_TAGS))
-		blk_mq_add_active_requests(data->hctx, nr);
-	/* caller already holds a reference, add for remainder */
-	percpu_ref_get_many(&data->q->q_usage_counter, nr - 1);
-	data->nr_tags -= nr;
+		tag_mask = blk_mq_get_tags(data, data->nr_tags, &tag_offset);
+		if (unlikely(!tag_mask))
+			return NULL;
+
+		tags = blk_mq_tags_from_data(data);
+		for (i = 0; tag_mask; i++) {
+			if (!(tag_mask & (1UL << i)))
+				continue;
+			tag = tag_offset + i;
+			prefetch(tags->static_rqs[tag]);
+			tag_mask &= ~(1UL << i);
+			rq = blk_mq_rq_ctx_init(data, tags, tag);
+			rq_list_add_head(data->cached_rqs, rq);
+			nr++;
+		}
+		if (!(data->rq_flags & RQF_SCHED_TAGS))
+			blk_mq_add_active_requests(data->hctx, nr);
+		/* caller already holds a reference, add for remainder */
+		percpu_ref_get_many(&data->q->q_usage_counter, nr - 1);
+		data->nr_tags -= nr;
+	} while (data->nr_tags);
 
 	return rq_list_pop(data->cached_rqs);
 }
diff --git a/lib/sbitmap.c b/lib/sbitmap.c
index 4d188d05db15..4ac303842aec 100644
--- a/lib/sbitmap.c
+++ b/lib/sbitmap.c
@@ -534,10 +534,11 @@ unsigned long __sbitmap_queue_get_batch(struct sbitmap_queue *sbq, int nr_tags,
 		unsigned int map_depth = __map_depth(sb, index);
 		unsigned long val;
 
-		sbitmap_deferred_clear(map, 0, 0, 0);
 		val = READ_ONCE(map->word);
-		if (val == (1UL << (map_depth - 1)) - 1)
-			goto next;
+		if (val == (1UL << (map_depth - 1)) - 1) {
+			if (!sbitmap_deferred_clear(map, map_depth, 0, 0))
+				goto next;
+		}
 
 		nr = find_first_zero_bit(&val, map_depth);
 		if (nr + nr_tags <= map_depth) {
-- 
2.34.1


^ permalink raw reply	[flat|nested] 10+ messages in thread
* Re: [PATCH v2] block: plug attempts to batch allocate tags multiple times
  2025-09-18  7:55 [PATCH v2] " Xue He
@ 2025-09-24  9:23 Yu Kuai
       [not found] ` <CGME20250924114923epcas5p24d397694d8ce433d126136b79f3fd21d@epcas5p2.samsung.com>
  0 siblings, 1 reply; 10+ messages in thread
From: Yu Kuai @ 2025-09-24  9:23 UTC (permalink / raw)
  To: Xue He, axboe, akpm; +Cc: linux-block, linux-kernel, yukuai (C)

Hi,

I'm not in the cc list, so it can take sometime before I notice this
patch.

在 2025/09/18 15:55, Xue He 写道:
> In the existing plug mechanism, tags are allocated in batches based on
> the number of requests. However, testing has shown that the plug only
> attempts batch allocation of tags once at the beginning of a batch of
> I/O operations. Since the tag_mask does not always have enough available
> tags to satisfy the requested number, a full batch allocation is not
> guaranteed to succeed each time. The remaining tags are then allocated
> individually (occurs frequently), leading to multiple single-tag
> allocation overheads.
> 
> This patch aims to retry batch allocation of tags when the initial batch
> allocation fails to reach the requested number, thereby reducing the
> overhead of individual allocation attempts.
> 
> --------------------------------------------------------------------
> perf:
> base code: __blk_mq_alloc_requests() 1.33%
> patch:__blk_mq_alloc_requests() 0.72%
> -------------------------------------------------------------------
> 
> Signed-off-by: hexue <xue01.he@samsung.com>
> ---

Please add change log.

>   block/blk-mq.c | 43 +++++++++++++++++++++++--------------------
>   lib/sbitmap.c  |  7 ++++---
>   2 files changed, 27 insertions(+), 23 deletions(-)
> 
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index ba3a4b77f578..3ed8da176831 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -456,28 +456,31 @@ __blk_mq_alloc_requests_batch(struct blk_mq_alloc_data *data)
>   	struct blk_mq_tags *tags;
>   	struct request *rq;
>   	unsigned long tag_mask;
> -	int i, nr = 0;
>   
> -	tag_mask = blk_mq_get_tags(data, data->nr_tags, &tag_offset);
> -	if (unlikely(!tag_mask))
> -		return NULL;
> +	do {
> +		int i, nr = 0;
>   
> -	tags = blk_mq_tags_from_data(data);
> -	for (i = 0; tag_mask; i++) {
> -		if (!(tag_mask & (1UL << i)))
> -			continue;
> -		tag = tag_offset + i;
> -		prefetch(tags->static_rqs[tag]);
> -		tag_mask &= ~(1UL << i);
> -		rq = blk_mq_rq_ctx_init(data, tags, tag);
> -		rq_list_add_head(data->cached_rqs, rq);
> -		nr++;
> -	}
> -	if (!(data->rq_flags & RQF_SCHED_TAGS))
> -		blk_mq_add_active_requests(data->hctx, nr);
> -	/* caller already holds a reference, add for remainder */
> -	percpu_ref_get_many(&data->q->q_usage_counter, nr - 1);
> -	data->nr_tags -= nr;
> +		tag_mask = blk_mq_get_tags(data, data->nr_tags, &tag_offset);
> +		if (unlikely(!tag_mask))
> +			return NULL;
> +
> +		tags = blk_mq_tags_from_data(data);
> +		for (i = 0; tag_mask; i++) {
> +			if (!(tag_mask & (1UL << i)))
> +				continue;
> +			tag = tag_offset + i;
> +			prefetch(tags->static_rqs[tag]);
> +			tag_mask &= ~(1UL << i);
> +			rq = blk_mq_rq_ctx_init(data, tags, tag);
> +			rq_list_add_head(data->cached_rqs, rq);
> +			nr++;
> +		}
> +		if (!(data->rq_flags & RQF_SCHED_TAGS))
> +			blk_mq_add_active_requests(data->hctx, nr);
> +		/* caller already holds a reference, add for remainder */
> +		percpu_ref_get_many(&data->q->q_usage_counter, nr - 1);

This should move outside of the loop, the remainder handling is one time
thing.

> +		data->nr_tags -= nr;
> +	} while (data->nr_tags);
>   
>   	return rq_list_pop(data->cached_rqs);
>   }
> diff --git a/lib/sbitmap.c b/lib/sbitmap.c
> index 4d188d05db15..4ac303842aec 100644
> --- a/lib/sbitmap.c
> +++ b/lib/sbitmap.c
> @@ -534,10 +534,11 @@ unsigned long __sbitmap_queue_get_batch(struct sbitmap_queue *sbq, int nr_tags,
>   		unsigned int map_depth = __map_depth(sb, index);
>   		unsigned long val;
>   
> -		sbitmap_deferred_clear(map, 0, 0, 0);
>   		val = READ_ONCE(map->word);
> -		if (val == (1UL << (map_depth - 1)) - 1)
> -			goto next;
> +		if (val == (1UL << (map_depth - 1)) - 1) {
> +			if (!sbitmap_deferred_clear(map, map_depth, 0, 0))
> +				goto next;

This looks wrong, you're still using the old val after
sbitmap_deferred_clear().
> +		}
>   
>   		nr = find_first_zero_bit(&val, map_depth);
>   		if (nr + nr_tags <= map_depth) {
> 

And I think if above checking failed, sbitmap_deferred_clear() should be
called and retry as well.

Thanks,
Kuai


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-09-24 13:54 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20250901082648epcas5p18f81021213f2b8a050efa25f76e0fb54@epcas5p1.samsung.com>
2025-09-01  8:22 ` [PATCH] block: plug attempts to batch allocate tags multiple times Xue He
2025-09-02  8:47   ` Yu Kuai
     [not found]     ` <CGME20250903084608epcas5p19a0ad4f0d1bad27889426e525d0c4598@epcas5p1.samsung.com>
2025-09-03  8:41       ` Xue He
2025-09-03  9:35         ` Yu Kuai
     [not found]           ` <CGME20250904063643epcas5p3a831ee47fb91bae02b07dfe398b77dd8@epcas5p3.samsung.com>
2025-09-04  6:32             ` Xue He
     [not found]           ` <CGME20250912031032epcas5p3f38da43ad6cf93b849bb44f14e49c8f9@epcas5p3.samsung.com>
2025-09-12  3:06             ` Xue He
2025-09-15  1:22               ` Yu Kuai
     [not found]                 ` <CGME20250917091039epcas5p1855bfdd913923953d69be9d736685f42@epcas5p1.samsung.com>
2025-09-17  9:06                   ` Xue He
2025-09-18  7:55 [PATCH v2] " Xue He
     [not found] ` <CGME20250924053907epcas5p10c550389234cb8feff8e5625d1d3d2a1@epcas5p1.samsung.com>
2025-09-24  5:34   ` [PATCH] " Xue He
2025-09-24  9:23 [PATCH v2] " Yu Kuai
     [not found] ` <CGME20250924114923epcas5p24d397694d8ce433d126136b79f3fd21d@epcas5p2.samsung.com>
2025-09-24 11:44   ` [PATCH] " Xue He

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®