linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] blk-mq: optimise plugging
@ 2019-11-28 21:11 Pavel Begunkov
  2019-11-28 21:11 ` [PATCH 1/3] blk-mq: optimise rq sort function Pavel Begunkov
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Pavel Begunkov @ 2019-11-28 21:11 UTC (permalink / raw)
  To: Jens Axboe, linux-block, linux-kernel

Clean and optimise blk_mq_flush_plug_list().

Pavel Begunkov (3):
  blk-mq: optimise rq sort function
  list: introduce list_for_each_continue()
  blk-mq: optimise blk_mq_flush_plug_list()

 block/blk-mq.c       | 69 +++++++++++++++-----------------------------
 include/linux/list.h | 10 +++++++
 2 files changed, 33 insertions(+), 46 deletions(-)

-- 
2.24.0


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

* [PATCH 1/3] blk-mq: optimise rq sort function
  2019-11-28 21:11 [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
@ 2019-11-28 21:11 ` Pavel Begunkov
  2019-11-29  8:28   ` Nikolay Borisov
  2019-11-28 21:11 ` [PATCH 2/3] list: introduce list_for_each_continue() Pavel Begunkov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Pavel Begunkov @ 2019-11-28 21:11 UTC (permalink / raw)
  To: Jens Axboe, linux-block, linux-kernel

Check "!=" in multi-layer comparisons. The same memory usage, fewer
instructions, and 2 from 4 jumps are replaced with SETcc.

Note, that list_sort() doesn't differ 0 and <0.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 block/blk-mq.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index 323c9cb28066..f32a3cfdd34e 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1668,14 +1668,10 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
 	struct request *rqa = container_of(a, struct request, queuelist);
 	struct request *rqb = container_of(b, struct request, queuelist);
 
-	if (rqa->mq_ctx < rqb->mq_ctx)
-		return -1;
-	else if (rqa->mq_ctx > rqb->mq_ctx)
-		return 1;
-	else if (rqa->mq_hctx < rqb->mq_hctx)
-		return -1;
-	else if (rqa->mq_hctx > rqb->mq_hctx)
-		return 1;
+	if (rqa->mq_ctx != rqb->mq_ctx)
+		return rqa->mq_ctx > rqb->mq_ctx;
+	if (rqa->mq_hctx != rqb->mq_hctx)
+		return rqa->mq_hctx > rqb->mq_hctx;
 
 	return blk_rq_pos(rqa) > blk_rq_pos(rqb);
 }
-- 
2.24.0


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

* [PATCH 2/3] list: introduce list_for_each_continue()
  2019-11-28 21:11 [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
  2019-11-28 21:11 ` [PATCH 1/3] blk-mq: optimise rq sort function Pavel Begunkov
@ 2019-11-28 21:11 ` Pavel Begunkov
  2019-11-28 21:11 ` [PATCH 3/3] blk-mq: optimise blk_mq_flush_plug_list() Pavel Begunkov
  2019-12-05 13:19 ` [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
  3 siblings, 0 replies; 9+ messages in thread
From: Pavel Begunkov @ 2019-11-28 21:11 UTC (permalink / raw)
  To: Jens Axboe, linux-block, linux-kernel

As other *continue() helpers, this continues iteration from a given
position.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 include/linux/list.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/linux/list.h b/include/linux/list.h
index 85c92555e31f..3c391bbd03c3 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -538,6 +538,16 @@ static inline void list_splice_tail_init(struct list_head *list,
 #define list_for_each(pos, head) \
 	for (pos = (head)->next; pos != (head); pos = pos->next)
 
+/**
+ * list_for_each_continue - continue iteration over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ *
+ * Continue to iterate over a list, continuing after the current position.
+ */
+#define list_for_each_continue(pos, head) \
+	for (pos = pos->next; pos != (head); pos = pos->next)
+
 /**
  * list_for_each_prev	-	iterate over a list backwards
  * @pos:	the &struct list_head to use as a loop cursor.
-- 
2.24.0


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

* [PATCH 3/3] blk-mq: optimise blk_mq_flush_plug_list()
  2019-11-28 21:11 [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
  2019-11-28 21:11 ` [PATCH 1/3] blk-mq: optimise rq sort function Pavel Begunkov
  2019-11-28 21:11 ` [PATCH 2/3] list: introduce list_for_each_continue() Pavel Begunkov
@ 2019-11-28 21:11 ` Pavel Begunkov
  2019-12-05 13:19 ` [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
  3 siblings, 0 replies; 9+ messages in thread
From: Pavel Begunkov @ 2019-11-28 21:11 UTC (permalink / raw)
  To: Jens Axboe, linux-block, linux-kernel

Instead of using list_del_init() in a loop, that generates a lot of
unnecessary memory read/writes, iterate from the first request of a
batch and cut out a sublist with list_cut_before().

Apart from removing the list node initialisation part, this is more
register-friendly, and the assembly uses the stack less intensively.

list_empty() at the beginning is done with hope, that the compiler can
optimise out the same check in the following list_splice_init().

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 block/blk-mq.c | 57 +++++++++++++++++---------------------------------
 1 file changed, 19 insertions(+), 38 deletions(-)

diff --git a/block/blk-mq.c b/block/blk-mq.c
index f32a3cfdd34e..3c71d52b6401 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1678,14 +1678,10 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
 {
-	struct blk_mq_hw_ctx *this_hctx;
-	struct blk_mq_ctx *this_ctx;
-	struct request_queue *this_q;
-	struct request *rq;
 	LIST_HEAD(list);
-	LIST_HEAD(rq_list);
-	unsigned int depth;
 
+	if (list_empty(&plug->mq_list))
+		return;
 	list_splice_init(&plug->mq_list, &list);
 
 	if (plug->rq_count > 2 && plug->multiple_queues)
@@ -1693,42 +1689,27 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
 
 	plug->rq_count = 0;
 
-	this_q = NULL;
-	this_hctx = NULL;
-	this_ctx = NULL;
-	depth = 0;
-
-	while (!list_empty(&list)) {
-		rq = list_entry_rq(list.next);
-		list_del_init(&rq->queuelist);
-		BUG_ON(!rq->q);
-		if (rq->mq_hctx != this_hctx || rq->mq_ctx != this_ctx) {
-			if (this_hctx) {
-				trace_block_unplug(this_q, depth, !from_schedule);
-				blk_mq_sched_insert_requests(this_hctx, this_ctx,
-								&rq_list,
-								from_schedule);
-			}
-
-			this_q = rq->q;
-			this_ctx = rq->mq_ctx;
-			this_hctx = rq->mq_hctx;
-			depth = 0;
+	do {
+		struct list_head rq_list;
+		struct request *rq, *head_rq = list_entry_rq(list.next);
+		struct list_head *pos = &head_rq->queuelist; /* skip first */
+		struct blk_mq_hw_ctx *this_hctx = head_rq->mq_hctx;
+		struct blk_mq_ctx *this_ctx = head_rq->mq_ctx;
+		unsigned int depth = 1;
+
+		list_for_each_continue(pos, &list) {
+			rq = list_entry_rq(pos);
+			BUG_ON(!rq->q);
+			if (rq->mq_hctx != this_hctx || rq->mq_ctx != this_ctx)
+				break;
+			depth++;
 		}
 
-		depth++;
-		list_add_tail(&rq->queuelist, &rq_list);
-	}
-
-	/*
-	 * If 'this_hctx' is set, we know we have entries to complete
-	 * on 'rq_list'. Do those.
-	 */
-	if (this_hctx) {
-		trace_block_unplug(this_q, depth, !from_schedule);
+		list_cut_before(&rq_list, &list, pos);
+		trace_block_unplug(head_rq->q, depth, !from_schedule);
 		blk_mq_sched_insert_requests(this_hctx, this_ctx, &rq_list,
 						from_schedule);
-	}
+	} while(!list_empty(&list));
 }
 
 static void blk_mq_bio_to_request(struct request *rq, struct bio *bio,
-- 
2.24.0


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

* Re: [PATCH 1/3] blk-mq: optimise rq sort function
  2019-11-28 21:11 ` [PATCH 1/3] blk-mq: optimise rq sort function Pavel Begunkov
@ 2019-11-29  8:28   ` Nikolay Borisov
  2019-11-29  9:45     ` Pavel Begunkov
  0 siblings, 1 reply; 9+ messages in thread
From: Nikolay Borisov @ 2019-11-29  8:28 UTC (permalink / raw)
  To: Pavel Begunkov, Jens Axboe, linux-block, linux-kernel



On 28.11.19 г. 23:11 ч., Pavel Begunkov wrote:
> Check "!=" in multi-layer comparisons. The same memory usage, fewer
> instructions, and 2 from 4 jumps are replaced with SETcc.
> 
> Note, that list_sort() doesn't differ 0 and <0.
> 
> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>

My first reaction was this is wrong since you no longer return negative
values. But then I looked into list_sort/merge and this branch
'if (cmp(priv, a, b) <= 0) {' clearly shows this is correct.

So :

Reviewed-by: Nikolay Borisov <nborisov@suse.com>

> ---
>  block/blk-mq.c | 12 ++++--------
>  1 file changed, 4 insertions(+), 8 deletions(-)
> 
> diff --git a/block/blk-mq.c b/block/blk-mq.c
> index 323c9cb28066..f32a3cfdd34e 100644
> --- a/block/blk-mq.c
> +++ b/block/blk-mq.c
> @@ -1668,14 +1668,10 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
>  	struct request *rqa = container_of(a, struct request, queuelist);
>  	struct request *rqb = container_of(b, struct request, queuelist);
>  
> -	if (rqa->mq_ctx < rqb->mq_ctx)
> -		return -1;
> -	else if (rqa->mq_ctx > rqb->mq_ctx)
> -		return 1;
> -	else if (rqa->mq_hctx < rqb->mq_hctx)
> -		return -1;
> -	else if (rqa->mq_hctx > rqb->mq_hctx)
> -		return 1;
> +	if (rqa->mq_ctx != rqb->mq_ctx)
> +		return rqa->mq_ctx > rqb->mq_ctx;
> +	if (rqa->mq_hctx != rqb->mq_hctx)
> +		return rqa->mq_hctx > rqb->mq_hctx;
>  
>  	return blk_rq_pos(rqa) > blk_rq_pos(rqb);
>  }
> 

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

* Re: [PATCH 1/3] blk-mq: optimise rq sort function
  2019-11-29  8:28   ` Nikolay Borisov
@ 2019-11-29  9:45     ` Pavel Begunkov
  2019-11-29 10:07       ` Nikolay Borisov
  0 siblings, 1 reply; 9+ messages in thread
From: Pavel Begunkov @ 2019-11-29  9:45 UTC (permalink / raw)
  To: Nikolay Borisov, Jens Axboe, linux-block, linux-kernel

On 11/29/2019 11:28 AM, Nikolay Borisov wrote:
> On 28.11.19 г. 23:11 ч., Pavel Begunkov wrote:
>> Check "!=" in multi-layer comparisons. The same memory usage, fewer
>> instructions, and 2 from 4 jumps are replaced with SETcc.
>>
>> Note, that list_sort() doesn't differ 0 and <0.
>>
>> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
> 
> My first reaction was this is wrong since you no longer return negative
> values. But then I looked into list_sort/merge and this branch
> 'if (cmp(priv, a, b) <= 0) {' clearly shows this is correct.

Yes, that's why there is a note in the patch description. The same is
told by list_sort() description.

> 
> So :
> 
> Reviewed-by: Nikolay Borisov <nborisov@suse.com>

Thanks for taking a look

> 
>> ---
>>  block/blk-mq.c | 12 ++++--------
>>  1 file changed, 4 insertions(+), 8 deletions(-)
>>
>> diff --git a/block/blk-mq.c b/block/blk-mq.c
>> index 323c9cb28066..f32a3cfdd34e 100644
>> --- a/block/blk-mq.c
>> +++ b/block/blk-mq.c
>> @@ -1668,14 +1668,10 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
>>  	struct request *rqa = container_of(a, struct request, queuelist);
>>  	struct request *rqb = container_of(b, struct request, queuelist);
>>  
>> -	if (rqa->mq_ctx < rqb->mq_ctx)
>> -		return -1;
>> -	else if (rqa->mq_ctx > rqb->mq_ctx)
>> -		return 1;
>> -	else if (rqa->mq_hctx < rqb->mq_hctx)
>> -		return -1;
>> -	else if (rqa->mq_hctx > rqb->mq_hctx)
>> -		return 1;
>> +	if (rqa->mq_ctx != rqb->mq_ctx)
>> +		return rqa->mq_ctx > rqb->mq_ctx;
>> +	if (rqa->mq_hctx != rqb->mq_hctx)
>> +		return rqa->mq_hctx > rqb->mq_hctx;
>>  
>>  	return blk_rq_pos(rqa) > blk_rq_pos(rqb);
>>  }
>>

-- 
Pavel Begunkov

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

* Re: [PATCH 1/3] blk-mq: optimise rq sort function
  2019-11-29  9:45     ` Pavel Begunkov
@ 2019-11-29 10:07       ` Nikolay Borisov
  0 siblings, 0 replies; 9+ messages in thread
From: Nikolay Borisov @ 2019-11-29 10:07 UTC (permalink / raw)
  To: Pavel Begunkov, Jens Axboe, linux-block, linux-kernel



On 29.11.19 г. 11:45 ч., Pavel Begunkov wrote:
> On 11/29/2019 11:28 AM, Nikolay Borisov wrote:
>> On 28.11.19 г. 23:11 ч., Pavel Begunkov wrote:
>>> Check "!=" in multi-layer comparisons. The same memory usage, fewer
>>> instructions, and 2 from 4 jumps are replaced with SETcc.
>>>
>>> Note, that list_sort() doesn't differ 0 and <0.
>>>
>>> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
>>
>> My first reaction was this is wrong since you no longer return negative
>> values. But then I looked into list_sort/merge and this branch
>> 'if (cmp(priv, a, b) <= 0) {' clearly shows this is correct.
> 
> Yes, that's why there is a note in the patch description. The same is
> told by list_sort() description.

And of course I have missed your remark in the changelog :)

> 
>>
>> So :
>>
>> Reviewed-by: Nikolay Borisov <nborisov@suse.com>
> 
> Thanks for taking a look
> 
>>
>>> ---
>>>  block/blk-mq.c | 12 ++++--------
>>>  1 file changed, 4 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/block/blk-mq.c b/block/blk-mq.c
>>> index 323c9cb28066..f32a3cfdd34e 100644
>>> --- a/block/blk-mq.c
>>> +++ b/block/blk-mq.c
>>> @@ -1668,14 +1668,10 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
>>>  	struct request *rqa = container_of(a, struct request, queuelist);
>>>  	struct request *rqb = container_of(b, struct request, queuelist);
>>>  
>>> -	if (rqa->mq_ctx < rqb->mq_ctx)
>>> -		return -1;
>>> -	else if (rqa->mq_ctx > rqb->mq_ctx)
>>> -		return 1;
>>> -	else if (rqa->mq_hctx < rqb->mq_hctx)
>>> -		return -1;
>>> -	else if (rqa->mq_hctx > rqb->mq_hctx)
>>> -		return 1;
>>> +	if (rqa->mq_ctx != rqb->mq_ctx)
>>> +		return rqa->mq_ctx > rqb->mq_ctx;
>>> +	if (rqa->mq_hctx != rqb->mq_hctx)
>>> +		return rqa->mq_hctx > rqb->mq_hctx;
>>>  
>>>  	return blk_rq_pos(rqa) > blk_rq_pos(rqb);
>>>  }
>>>
> 

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

* Re: [PATCH 0/3] blk-mq: optimise plugging
  2019-11-28 21:11 [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
                   ` (2 preceding siblings ...)
  2019-11-28 21:11 ` [PATCH 3/3] blk-mq: optimise blk_mq_flush_plug_list() Pavel Begunkov
@ 2019-12-05 13:19 ` Pavel Begunkov
  2019-12-05 15:00   ` Jens Axboe
  3 siblings, 1 reply; 9+ messages in thread
From: Pavel Begunkov @ 2019-12-05 13:19 UTC (permalink / raw)
  To: Jens Axboe, linux-block, linux-kernel


[-- Attachment #1.1: Type: text/plain, Size: 460 bytes --]

On 29/11/2019 00:11, Pavel Begunkov wrote:
> Clean and optimise blk_mq_flush_plug_list().
> 
ping

> Pavel Begunkov (3):
>   blk-mq: optimise rq sort function
>   list: introduce list_for_each_continue()
>   blk-mq: optimise blk_mq_flush_plug_list()
> 
>  block/blk-mq.c       | 69 +++++++++++++++-----------------------------
>  include/linux/list.h | 10 +++++++
>  2 files changed, 33 insertions(+), 46 deletions(-)
> 

-- 
Pavel Begunkov


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH 0/3] blk-mq: optimise plugging
  2019-12-05 13:19 ` [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
@ 2019-12-05 15:00   ` Jens Axboe
  0 siblings, 0 replies; 9+ messages in thread
From: Jens Axboe @ 2019-12-05 15:00 UTC (permalink / raw)
  To: Pavel Begunkov, linux-block, linux-kernel

On 12/5/19 6:19 AM, Pavel Begunkov wrote:
> On 29/11/2019 00:11, Pavel Begunkov wrote:
>> Clean and optimise blk_mq_flush_plug_list().
>>
> ping

Looks good to me, I've been waiting a bit on this as I'll queue it up
for 5.6.

-- 
Jens Axboe


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

end of thread, other threads:[~2019-12-05 15:00 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-28 21:11 [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
2019-11-28 21:11 ` [PATCH 1/3] blk-mq: optimise rq sort function Pavel Begunkov
2019-11-29  8:28   ` Nikolay Borisov
2019-11-29  9:45     ` Pavel Begunkov
2019-11-29 10:07       ` Nikolay Borisov
2019-11-28 21:11 ` [PATCH 2/3] list: introduce list_for_each_continue() Pavel Begunkov
2019-11-28 21:11 ` [PATCH 3/3] blk-mq: optimise blk_mq_flush_plug_list() Pavel Begunkov
2019-12-05 13:19 ` [PATCH 0/3] blk-mq: optimise plugging Pavel Begunkov
2019-12-05 15:00   ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).