Skip to content

Commit fb92603

Browse files
bvanasscheaxboe
authored andcommitted
block/mq-deadline: Prioritize high-priority requests
While one or more requests with a certain I/O priority are pending, do not dispatch lower priority requests. Dispatch lower priority requests anyway after the "aging" time has expired. This patch has been tested as follows: modprobe scsi_debug ndelay=1000000 max_queue=16 && sd='' && while [ -z "$sd" ]; do sd=/dev/$(basename /sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*/block/*) done && echo $((100*1000)) > /sys/block/$sd/queue/iosched/aging_expire && cd /sys/fs/cgroup/blkio/ && echo $$ >cgroup.procs && echo restrict-to-be >blkio.prio.class && mkdir -p hipri && cd hipri && echo none-to-rt >blkio.prio.class && { max-iops -a1 -d32 -j1 -e mq-deadline $sd >& ~/low-pri.txt & } && echo $$ >cgroup.procs && max-iops -a1 -d32 -j1 -e mq-deadline $sd >& ~/hi-pri.txt Result: * 11000 IOPS for the high-priority job * 40 IOPS for the low-priority job If the aging expiry time is changed from 100s into 0, the IOPS results change into 6712 and 6796 IOPS. The max-iops script is a script that runs fio with the following arguments: --bs=4K --gtod_reduce=1 --ioengine=libaio --ioscheduler=${arg_e} --runtime=60 --norandommap --rw=read --thread --buffered=0 --numjobs=${arg_j} --iodepth=${arg_d} --iodepth_batch_submit=${arg_a} --iodepth_batch_complete=$((arg_d / 2)) --name=${positional_argument_1} --filename=${positional_argument_1} Reviewed-by: Damien Le Moal <[email protected]> Cc: Hannes Reinecke <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Ming Lei <[email protected]> Cc: Johannes Thumshirn <[email protected]> Cc: Himanshu Madhani <[email protected]> Signed-off-by: Bart Van Assche <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 08a9ad8 commit fb92603

File tree

1 file changed

+37
-5
lines changed

1 file changed

+37
-5
lines changed

block/mq-deadline-main.c

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
*/
3333
static const int read_expire = HZ / 2; /* max time before a read is submitted. */
3434
static const int write_expire = 5 * HZ; /* ditto for writes, these limits are SOFT! */
35+
/*
36+
* Time after which to dispatch lower priority requests even if higher
37+
* priority requests are pending.
38+
*/
39+
static const int aging_expire = 10 * HZ;
3540
static const int writes_starved = 2; /* max times reads can starve a write */
3641
static const int fifo_batch = 16; /* # of sequential requests treated as one
3742
by the above parameters. For throughput. */
@@ -94,6 +99,7 @@ struct deadline_data {
9499
int writes_starved;
95100
int front_merges;
96101
u32 async_depth;
102+
int aging_expire;
97103

98104
spinlock_t lock;
99105
spinlock_t zone_lock;
@@ -361,10 +367,11 @@ deadline_next_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
361367

362368
/*
363369
* deadline_dispatch_requests selects the best request according to
364-
* read/write expire, fifo_batch, etc
370+
* read/write expire, fifo_batch, etc and with a start time <= @latest.
365371
*/
366372
static struct request *__dd_dispatch_request(struct deadline_data *dd,
367-
struct dd_per_prio *per_prio)
373+
struct dd_per_prio *per_prio,
374+
u64 latest_start_ns)
368375
{
369376
struct request *rq, *next_rq;
370377
enum dd_data_dir data_dir;
@@ -377,6 +384,8 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd,
377384
if (!list_empty(&per_prio->dispatch)) {
378385
rq = list_first_entry(&per_prio->dispatch, struct request,
379386
queuelist);
387+
if (rq->start_time_ns > latest_start_ns)
388+
return NULL;
380389
list_del_init(&rq->queuelist);
381390
goto done;
382391
}
@@ -454,6 +463,8 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd,
454463
dd->batching = 0;
455464

456465
dispatch_request:
466+
if (rq->start_time_ns > latest_start_ns)
467+
return NULL;
457468
/*
458469
* rq is the selected appropriate request.
459470
*/
@@ -484,15 +495,32 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd,
484495
static struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx)
485496
{
486497
struct deadline_data *dd = hctx->queue->elevator->elevator_data;
487-
struct request *rq;
498+
const u64 now_ns = ktime_get_ns();
499+
struct request *rq = NULL;
488500
enum dd_prio prio;
489501

490502
spin_lock(&dd->lock);
491-
for (prio = 0; prio <= DD_PRIO_MAX; prio++) {
492-
rq = __dd_dispatch_request(dd, &dd->per_prio[prio]);
503+
/*
504+
* Start with dispatching requests whose deadline expired more than
505+
* aging_expire jiffies ago.
506+
*/
507+
for (prio = DD_BE_PRIO; prio <= DD_PRIO_MAX; prio++) {
508+
rq = __dd_dispatch_request(dd, &dd->per_prio[prio], now_ns -
509+
jiffies_to_nsecs(dd->aging_expire));
493510
if (rq)
511+
goto unlock;
512+
}
513+
/*
514+
* Next, dispatch requests in priority order. Ignore lower priority
515+
* requests if any higher priority requests are pending.
516+
*/
517+
for (prio = 0; prio <= DD_PRIO_MAX; prio++) {
518+
rq = __dd_dispatch_request(dd, &dd->per_prio[prio], now_ns);
519+
if (rq || dd_queued(dd, prio))
494520
break;
495521
}
522+
523+
unlock:
496524
spin_unlock(&dd->lock);
497525

498526
return rq;
@@ -603,6 +631,7 @@ static int dd_init_sched(struct request_queue *q, struct elevator_type *e)
603631
dd->front_merges = 1;
604632
dd->last_dir = DD_WRITE;
605633
dd->fifo_batch = fifo_batch;
634+
dd->aging_expire = aging_expire;
606635
spin_lock_init(&dd->lock);
607636
spin_lock_init(&dd->zone_lock);
608637

@@ -835,6 +864,7 @@ static ssize_t __FUNC(struct elevator_queue *e, char *page) \
835864
#define SHOW_JIFFIES(__FUNC, __VAR) SHOW_INT(__FUNC, jiffies_to_msecs(__VAR))
836865
SHOW_JIFFIES(deadline_read_expire_show, dd->fifo_expire[DD_READ]);
837866
SHOW_JIFFIES(deadline_write_expire_show, dd->fifo_expire[DD_WRITE]);
867+
SHOW_JIFFIES(deadline_aging_expire_show, dd->aging_expire);
838868
SHOW_INT(deadline_writes_starved_show, dd->writes_starved);
839869
SHOW_INT(deadline_front_merges_show, dd->front_merges);
840870
SHOW_INT(deadline_async_depth_show, dd->front_merges);
@@ -864,6 +894,7 @@ static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count)
864894
STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, msecs_to_jiffies)
865895
STORE_JIFFIES(deadline_read_expire_store, &dd->fifo_expire[DD_READ], 0, INT_MAX);
866896
STORE_JIFFIES(deadline_write_expire_store, &dd->fifo_expire[DD_WRITE], 0, INT_MAX);
897+
STORE_JIFFIES(deadline_aging_expire_store, &dd->aging_expire, 0, INT_MAX);
867898
STORE_INT(deadline_writes_starved_store, &dd->writes_starved, INT_MIN, INT_MAX);
868899
STORE_INT(deadline_front_merges_store, &dd->front_merges, 0, 1);
869900
STORE_INT(deadline_async_depth_store, &dd->front_merges, 1, INT_MAX);
@@ -882,6 +913,7 @@ static struct elv_fs_entry deadline_attrs[] = {
882913
DD_ATTR(front_merges),
883914
DD_ATTR(async_depth),
884915
DD_ATTR(fifo_batch),
916+
DD_ATTR(aging_expire),
885917
__ATTR_NULL
886918
};
887919

0 commit comments

Comments
 (0)