Skip to content

Commit d0c9876

Browse files
poluoaxboe
authored andcommitted
blk-mq: use array manage hctx map instead of xarray
After commit 4e5cc99 ("blk-mq: manage hctx map via xarray"), we use an xarray instead of array to store hctx, but in poll mode, each time in blk_mq_poll, we need use xa_load to find corresponding hctx, this introduce some costs. In my test, xa_load may cost 3.8% cpu. This patch revert previous change, eliminates the overhead of xa_load and can result in a 3% performance improvement. Signed-off-by: Fengnan Chang <changfengnan@bytedance.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent c6a45ee commit d0c9876

5 files changed

Lines changed: 42 additions & 25 deletions

File tree

block/blk-mq-tag.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_tag_iter_fn *fn,
499499
int srcu_idx;
500500

501501
/*
502-
* __blk_mq_update_nr_hw_queues() updates nr_hw_queues and hctx_table
502+
* __blk_mq_update_nr_hw_queues() updates nr_hw_queues and queue_hw_ctx
503503
* while the queue is frozen. So we can use q_usage_counter to avoid
504504
* racing with it.
505505
*/

block/blk-mq.c

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
730730
* If not tell the caller that it should skip this queue.
731731
*/
732732
ret = -EXDEV;
733-
data.hctx = xa_load(&q->hctx_table, hctx_idx);
733+
data.hctx = q->queue_hw_ctx[hctx_idx];
734734
if (!blk_mq_hw_queue_mapped(data.hctx))
735735
goto out_queue_exit;
736736
cpu = cpumask_first_and(data.hctx->cpumask, cpu_online_mask);
@@ -3946,8 +3946,6 @@ static void blk_mq_exit_hctx(struct request_queue *q,
39463946
blk_free_flush_queue_callback);
39473947
hctx->fq = NULL;
39483948

3949-
xa_erase(&q->hctx_table, hctx_idx);
3950-
39513949
spin_lock(&q->unused_hctx_lock);
39523950
list_add(&hctx->hctx_list, &q->unused_hctx_list);
39533951
spin_unlock(&q->unused_hctx_lock);
@@ -3989,14 +3987,8 @@ static int blk_mq_init_hctx(struct request_queue *q,
39893987
hctx->numa_node))
39903988
goto exit_hctx;
39913989

3992-
if (xa_insert(&q->hctx_table, hctx_idx, hctx, GFP_KERNEL))
3993-
goto exit_flush_rq;
3994-
39953990
return 0;
39963991

3997-
exit_flush_rq:
3998-
if (set->ops->exit_request)
3999-
set->ops->exit_request(set, hctx->fq->flush_rq, hctx_idx);
40003992
exit_hctx:
40013993
if (set->ops->exit_hctx)
40023994
set->ops->exit_hctx(hctx, hctx_idx);
@@ -4385,7 +4377,7 @@ void blk_mq_release(struct request_queue *q)
43854377
kobject_put(&hctx->kobj);
43864378
}
43874379

4388-
xa_destroy(&q->hctx_table);
4380+
kfree(q->queue_hw_ctx);
43894381

43904382
/*
43914383
* release .mq_kobj and sw queue's kobject now because
@@ -4529,26 +4521,44 @@ static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx(
45294521
static void __blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
45304522
struct request_queue *q)
45314523
{
4532-
struct blk_mq_hw_ctx *hctx;
4533-
unsigned long i, j;
4524+
int i, j, end;
4525+
struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx;
4526+
4527+
if (q->nr_hw_queues < set->nr_hw_queues) {
4528+
struct blk_mq_hw_ctx **new_hctxs;
4529+
4530+
new_hctxs = kcalloc_node(set->nr_hw_queues,
4531+
sizeof(*new_hctxs), GFP_KERNEL,
4532+
set->numa_node);
4533+
if (!new_hctxs)
4534+
return;
4535+
if (hctxs)
4536+
memcpy(new_hctxs, hctxs, q->nr_hw_queues *
4537+
sizeof(*hctxs));
4538+
q->queue_hw_ctx = new_hctxs;
4539+
kfree(hctxs);
4540+
hctxs = new_hctxs;
4541+
}
45344542

45354543
for (i = 0; i < set->nr_hw_queues; i++) {
45364544
int old_node;
45374545
int node = blk_mq_get_hctx_node(set, i);
4538-
struct blk_mq_hw_ctx *old_hctx = xa_load(&q->hctx_table, i);
4546+
struct blk_mq_hw_ctx *old_hctx = hctxs[i];
45394547

45404548
if (old_hctx) {
45414549
old_node = old_hctx->numa_node;
45424550
blk_mq_exit_hctx(q, set, old_hctx, i);
45434551
}
45444552

4545-
if (!blk_mq_alloc_and_init_hctx(set, q, i, node)) {
4553+
hctxs[i] = blk_mq_alloc_and_init_hctx(set, q, i, node);
4554+
if (!hctxs[i]) {
45464555
if (!old_hctx)
45474556
break;
45484557
pr_warn("Allocate new hctx on node %d fails, fallback to previous one on node %d\n",
45494558
node, old_node);
4550-
hctx = blk_mq_alloc_and_init_hctx(set, q, i, old_node);
4551-
WARN_ON_ONCE(!hctx);
4559+
hctxs[i] = blk_mq_alloc_and_init_hctx(set, q, i,
4560+
old_node);
4561+
WARN_ON_ONCE(!hctxs[i]);
45524562
}
45534563
}
45544564
/*
@@ -4557,13 +4567,21 @@ static void __blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
45574567
*/
45584568
if (i != set->nr_hw_queues) {
45594569
j = q->nr_hw_queues;
4570+
end = i;
45604571
} else {
45614572
j = i;
4573+
end = q->nr_hw_queues;
45624574
q->nr_hw_queues = set->nr_hw_queues;
45634575
}
45644576

4565-
xa_for_each_start(&q->hctx_table, j, hctx, j)
4566-
blk_mq_exit_hctx(q, set, hctx, j);
4577+
for (; j < end; j++) {
4578+
struct blk_mq_hw_ctx *hctx = hctxs[j];
4579+
4580+
if (hctx) {
4581+
blk_mq_exit_hctx(q, set, hctx, j);
4582+
hctxs[j] = NULL;
4583+
}
4584+
}
45674585
}
45684586

45694587
static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
@@ -4599,8 +4617,6 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
45994617
INIT_LIST_HEAD(&q->unused_hctx_list);
46004618
spin_lock_init(&q->unused_hctx_lock);
46014619

4602-
xa_init(&q->hctx_table);
4603-
46044620
blk_mq_realloc_hw_ctxs(set, q);
46054621
if (!q->nr_hw_queues)
46064622
goto err_hctxs;
@@ -5187,7 +5203,7 @@ int blk_mq_poll(struct request_queue *q, blk_qc_t cookie,
51875203
{
51885204
if (!blk_mq_can_poll(q))
51895205
return 0;
5190-
return blk_hctx_poll(q, xa_load(&q->hctx_table, cookie), iob, flags);
5206+
return blk_hctx_poll(q, q->queue_hw_ctx[cookie], iob, flags);
51915207
}
51925208

51935209
int blk_rq_poll(struct request *rq, struct io_comp_batch *iob,

block/blk-mq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ static inline struct blk_mq_hw_ctx *blk_mq_map_queue_type(struct request_queue *
8484
enum hctx_type type,
8585
unsigned int cpu)
8686
{
87-
return xa_load(&q->hctx_table, q->tag_set->map[type].mq_map[cpu]);
87+
return q->queue_hw_ctx[q->tag_set->map[type].mq_map[cpu]];
8888
}
8989

9090
static inline enum hctx_type blk_mq_get_hctx_type(blk_opf_t opf)

include/linux/blk-mq.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,8 @@ static inline void *blk_mq_rq_to_pdu(struct request *rq)
10161016
}
10171017

10181018
#define queue_for_each_hw_ctx(q, hctx, i) \
1019-
xa_for_each(&(q)->hctx_table, (i), (hctx))
1019+
for ((i) = 0; (i) < (q)->nr_hw_queues && \
1020+
({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++)
10201021

10211022
#define hctx_for_each_ctx(hctx, ctx, i) \
10221023
for ((i) = 0; (i) < (hctx)->nr_ctx && \

include/linux/blkdev.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ struct request_queue {
503503

504504
/* hw dispatch queues */
505505
unsigned int nr_hw_queues;
506-
struct xarray hctx_table;
506+
struct blk_mq_hw_ctx **queue_hw_ctx;
507507

508508
struct percpu_ref q_usage_counter;
509509
struct lock_class_key io_lock_cls_key;

0 commit comments

Comments
 (0)