diff options
Diffstat (limited to '0006-BFQ-bugfix-for-v8r12.patch')
-rw-r--r-- | 0006-BFQ-bugfix-for-v8r12.patch | 345 |
1 files changed, 341 insertions, 4 deletions
diff --git a/0006-BFQ-bugfix-for-v8r12.patch b/0006-BFQ-bugfix-for-v8r12.patch index 68e7c41bddf6..09317c62fb45 100644 --- a/0006-BFQ-bugfix-for-v8r12.patch +++ b/0006-BFQ-bugfix-for-v8r12.patch @@ -1,7 +1,7 @@ From 518e5275d6057ee8b3b4eeebaaa779c5aca7a15c Mon Sep 17 00:00:00 2001 From: Paolo Valente <paolo.valente@linaro.org> Date: Thu, 20 Jul 2017 10:46:39 +0200 -Subject: [PATCH 1/3] Add extra checks related to entity scheduling +Subject: [PATCH 1/4] Add extra checks related to entity scheduling - extra checks related to ioprioi-class changes - specific check on st->idle in __bfq_requeue_entity @@ -67,7 +67,7 @@ index 90d2856358a1..b6eb25887262 100644 From 6af8852b69527087d11c81a4dcb49d24f297dbce Mon Sep 17 00:00:00 2001 From: Paolo Valente <paolo.valente@linaro.org> Date: Fri, 21 Jul 2017 12:08:57 +0200 -Subject: [PATCH 2/3] block, bfq: reset in_service_entity if it becomes idle +Subject: [PATCH 2/4] block, bfq: reset in_service_entity if it becomes idle BFQ implements hierarchical scheduling by representing each group of queues with a generic parent entity. For each parent entity, BFQ @@ -125,7 +125,7 @@ index b6eb25887262..fdf1c713d050 100644 From 52ce0ffe68b5e3fefaed21cfb32f104202eddc25 Mon Sep 17 00:00:00 2001 From: Paolo Valente <paolo.valente@linaro.org> Date: Fri, 28 Jul 2017 21:09:51 +0200 -Subject: [PATCH 3/3] block, bfq: consider also in_service_entity to state +Subject: [PATCH 3/4] block, bfq: consider also in_service_entity to state whether an entity is active Groups of BFQ queues are represented by generic entities in BFQ. When @@ -440,4 +440,341 @@ index 77dc72c35fbf..ffa833863d88 100644 + * bfqd. */ struct bfq_sched_data { - struct bfq_entity *in_service_entity; /* entity in service */ + struct bfq_entity *in_service_entity; /* entity in service */ + +From ef8d4eb597ec77088b5d8cd08ff5a9145c47a57c Mon Sep 17 00:00:00 2001 +From: Paolo Valente <paolo.valente@linaro.org> +Date: Thu, 4 May 2017 10:53:43 +0200 +Subject: [PATCH 4/4] block, bfq: improve and refactor throughput-boosting + logic + +When a queue associated with a process remains empty, there are cases +where throughput gets boosted if the device is idled to await the +arrival of a new I/O request for that queue. Currently, BFQ assumes +that one of these cases is when the device has no internal queueing +(regardless of the properties of the I/O being served). Unfortunately, +this condition has proved to be too general. So, this commit refines it +as "the device has no internal queueing and is rotational". + +This refinement provides a significant throughput boost with random +I/O, on flash-based storage without internal queueing. For example, on +a HiKey board, throughput increases by up to 125%, growing, e.g., from +6.9MB/s to 15.6MB/s with two or three random readers in parallel. + +This commit also refactors the code related to device idling, for the +following reason. Finding the change that provides the above large +improvement has been slightly more difficult than it had to be, +because the logic that decides whether to idle the device is still +scattered across three functions. Almost all of the logic is in the +function bfq_bfqq_may_idle, but (1) part of the decision is made in +bfq_update_idle_window, and (2) the function bfq_bfqq_must_idle may +switch off idling regardless of the output of bfq_bfqq_may_idle. In +addition, both bfq_update_idle_window and bfq_bfqq_must_idle make +their decisions as a function of parameters that are used, for similar +purposes, also in bfq_bfqq_may_idle. This commit addresses this issue +by moving all the logic into bfq_bfqq_may_idle. + +Signed-off-by: Paolo Valente <paolo.valente@linaro.org> +Signed-off-by: Luca Miccio <lucmiccio@gmail.com> +--- + block/bfq-iosched.c | 141 ++++++++++++++++++++++++++++------------------------ + block/bfq.h | 12 ++--- + 2 files changed, 83 insertions(+), 70 deletions(-) + +diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c +index ea92c7461b89..e75df37a1cd3 100644 +--- a/block/bfq-iosched.c ++++ b/block/bfq-iosched.c +@@ -684,10 +684,10 @@ bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_data *bfqd, + unsigned int old_wr_coeff; + bool busy = bfq_already_existing && bfq_bfqq_busy(bfqq); + +- if (bic->saved_idle_window) +- bfq_mark_bfqq_idle_window(bfqq); ++ if (bic->saved_has_short_ttime) ++ bfq_mark_bfqq_has_short_ttime(bfqq); + else +- bfq_clear_bfqq_idle_window(bfqq); ++ bfq_clear_bfqq_has_short_ttime(bfqq); + + if (bic->saved_IO_bound) + bfq_mark_bfqq_IO_bound(bfqq); +@@ -2047,7 +2047,7 @@ static void bfq_bfqq_save_state(struct bfq_queue *bfqq) + if (!bic) + return; + +- bic->saved_idle_window = bfq_bfqq_idle_window(bfqq); ++ bic->saved_has_short_ttime = bfq_bfqq_has_short_ttime(bfqq); + bic->saved_IO_bound = bfq_bfqq_IO_bound(bfqq); + bic->saved_in_large_burst = bfq_bfqq_in_large_burst(bfqq); + bic->was_in_burst_list = !hlist_unhashed(&bfqq->burst_list_node); +@@ -3214,9 +3214,9 @@ static void bfq_bfqq_expire(struct bfq_data *bfqd, + } + + bfq_log_bfqq(bfqd, bfqq, +- "expire (%d, slow %d, num_disp %d, idle_win %d, weight %d)", ++ "expire (%d, slow %d, num_disp %d, short_ttime %d, weight %d)", + reason, slow, bfqq->dispatched, +- bfq_bfqq_idle_window(bfqq), entity->weight); ++ bfq_bfqq_has_short_ttime(bfqq), entity->weight); + + /* + * Increase, decrease or leave budget unchanged according to +@@ -3298,7 +3298,10 @@ static bool bfq_may_expire_for_budg_timeout(struct bfq_queue *bfqq) + static bool bfq_bfqq_may_idle(struct bfq_queue *bfqq) + { + struct bfq_data *bfqd = bfqq->bfqd; +- bool idling_boosts_thr, idling_boosts_thr_without_issues, ++ bool rot_without_queueing = ++ !blk_queue_nonrot(bfqd->queue) && !bfqd->hw_tag, ++ bfqq_sequential_and_IO_bound, ++ idling_boosts_thr, idling_boosts_thr_without_issues, + idling_needed_for_service_guarantees, + asymmetric_scenario; + +@@ -3306,27 +3309,44 @@ static bool bfq_bfqq_may_idle(struct bfq_queue *bfqq) + return true; + + /* ++ * Idling is performed only if slice_idle > 0. In addition, we ++ * do not idle if ++ * (a) bfqq is async ++ * (b) bfqq is in the idle io prio class: in this case we do ++ * not idle because we want to minimize the bandwidth that ++ * queues in this class can steal to higher-priority queues ++ */ ++ if (bfqd->bfq_slice_idle == 0 || !bfq_bfqq_sync(bfqq) || ++ bfq_class_idle(bfqq)) ++ return false; ++ ++ bfqq_sequential_and_IO_bound = !BFQQ_SEEKY(bfqq) && ++ bfq_bfqq_IO_bound(bfqq) && bfq_bfqq_has_short_ttime(bfqq); ++ /* + * The next variable takes into account the cases where idling + * boosts the throughput. + * + * The value of the variable is computed considering, first, that + * idling is virtually always beneficial for the throughput if: +- * (a) the device is not NCQ-capable, or +- * (b) regardless of the presence of NCQ, the device is rotational +- * and the request pattern for bfqq is I/O-bound and sequential. ++ * (a) the device is not NCQ-capable and rotational, or ++ * (b) regardless of the presence of NCQ, the device is rotational and ++ * the request pattern for bfqq is I/O-bound and sequential, or ++ * (c) regardless of whether it is rotational, the device is ++ * not NCQ-capable and the request pattern for bfqq is ++ * I/O-bound and sequential. + * + * Secondly, and in contrast to the above item (b), idling an + * NCQ-capable flash-based device would not boost the + * throughput even with sequential I/O; rather it would lower + * the throughput in proportion to how fast the device + * is. Accordingly, the next variable is true if any of the +- * above conditions (a) and (b) is true, and, in particular, +- * happens to be false if bfqd is an NCQ-capable flash-based +- * device. ++ * above conditions (a), (b) or (c) is true, and, in ++ * particular, happens to be false if bfqd is an NCQ-capable ++ * flash-based device. + */ +- idling_boosts_thr = !bfqd->hw_tag || +- (!blk_queue_nonrot(bfqd->queue) && bfq_bfqq_IO_bound(bfqq) && +- bfq_bfqq_idle_window(bfqq)); ++ idling_boosts_thr = rot_without_queueing || ++ ((!blk_queue_nonrot(bfqd->queue) || !bfqd->hw_tag) && ++ bfqq_sequential_and_IO_bound); + + /* + * The value of the next variable, +@@ -3497,12 +3517,10 @@ static bool bfq_bfqq_may_idle(struct bfq_queue *bfqq) + asymmetric_scenario && !bfq_bfqq_in_large_burst(bfqq); + + /* +- * We have now all the components we need to compute the return +- * value of the function, which is true only if both the following +- * conditions hold: +- * 1) bfqq is sync, because idling make sense only for sync queues; +- * 2) idling either boosts the throughput (without issues), or +- * is necessary to preserve service guarantees. ++ * We have now all the components we need to compute the ++ * return value of the function, which is true only if idling ++ * either boosts the throughput (without issues), or is ++ * necessary to preserve service guarantees. + */ + bfq_log_bfqq(bfqd, bfqq, "may_idle: sync %d idling_boosts_thr %d", + bfq_bfqq_sync(bfqq), idling_boosts_thr); +@@ -3514,9 +3532,8 @@ static bool bfq_bfqq_may_idle(struct bfq_queue *bfqq) + bfq_bfqq_IO_bound(bfqq), + idling_needed_for_service_guarantees); + +- return bfq_bfqq_sync(bfqq) && +- (idling_boosts_thr_without_issues || +- idling_needed_for_service_guarantees); ++ return idling_boosts_thr_without_issues || ++ idling_needed_for_service_guarantees; + } + + /* +@@ -3532,10 +3549,7 @@ static bool bfq_bfqq_may_idle(struct bfq_queue *bfqq) + */ + static bool bfq_bfqq_must_idle(struct bfq_queue *bfqq) + { +- struct bfq_data *bfqd = bfqq->bfqd; +- +- return RB_EMPTY_ROOT(&bfqq->sort_list) && bfqd->bfq_slice_idle != 0 && +- bfq_bfqq_may_idle(bfqq); ++ return RB_EMPTY_ROOT(&bfqq->sort_list) && bfq_bfqq_may_idle(bfqq); + } + + /* +@@ -3994,7 +4008,6 @@ static void bfq_set_next_ioprio_data(struct bfq_queue *bfqq, + case IOPRIO_CLASS_IDLE: + bfqq->new_ioprio_class = IOPRIO_CLASS_IDLE; + bfqq->new_ioprio = 7; +- bfq_clear_bfqq_idle_window(bfqq); + break; + } + +@@ -4058,8 +4071,14 @@ static void bfq_init_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, + bfq_set_next_ioprio_data(bfqq, bic); + + if (is_sync) { ++ /* ++ * No need to mark as has_short_ttime if in ++ * idle_class, because no device idling is performed ++ * for queues in idle class ++ */ + if (!bfq_class_idle(bfqq)) +- bfq_mark_bfqq_idle_window(bfqq); ++ /* tentatively mark as has_short_ttime */ ++ bfq_mark_bfqq_has_short_ttime(bfqq); + bfq_mark_bfqq_sync(bfqq); + bfq_mark_bfqq_just_created(bfqq); + } else +@@ -4195,18 +4214,19 @@ bfq_update_io_seektime(struct bfq_data *bfqd, struct bfq_queue *bfqq, + blk_rq_sectors(rq) < BFQQ_SECT_THR_NONROT); + } + +-/* +- * Disable idle window if the process thinks too long or seeks so much that +- * it doesn't matter. +- */ +-static void bfq_update_idle_window(struct bfq_data *bfqd, +- struct bfq_queue *bfqq, +- struct bfq_io_cq *bic) ++static void bfq_update_has_short_ttime(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ struct bfq_io_cq *bic) + { +- int enable_idle; ++ bool has_short_ttime = true; + +- /* Don't idle for async or idle io prio class. */ +- if (!bfq_bfqq_sync(bfqq) || bfq_class_idle(bfqq)) ++ /* ++ * No need to update has_short_ttime if bfqq is async or in ++ * idle io prio class, or if bfq_slice_idle is zero, because ++ * no device idling is performed for bfqq in this case. ++ */ ++ if (!bfq_bfqq_sync(bfqq) || bfq_class_idle(bfqq) || ++ bfqd->bfq_slice_idle == 0) + return; + + /* Idle window just restored, statistics are meaningless. */ +@@ -4214,27 +4234,22 @@ static void bfq_update_idle_window(struct bfq_data *bfqd, + bfqd->bfq_wr_min_idle_time)) + return; + +- enable_idle = bfq_bfqq_idle_window(bfqq); +- ++ /* Think time is infinite if no process is linked to ++ * bfqq. Otherwise check average think time to ++ * decide whether to mark as has_short_ttime ++ */ + if (atomic_read(&bic->icq.ioc->active_ref) == 0 || +- bfqd->bfq_slice_idle == 0 || +- (bfqd->hw_tag && BFQQ_SEEKY(bfqq) && +- bfqq->wr_coeff == 1)) +- enable_idle = 0; +- else if (bfq_sample_valid(bic->ttime.ttime_samples)) { +- if (bic->ttime.ttime_mean > bfqd->bfq_slice_idle && +- bfqq->wr_coeff == 1) +- enable_idle = 0; +- else +- enable_idle = 1; +- } +- bfq_log_bfqq(bfqd, bfqq, "update_idle_window: enable_idle %d", +- enable_idle); ++ (bfq_sample_valid(bic->ttime.ttime_samples) && ++ bic->ttime.ttime_mean > bfqd->bfq_slice_idle)) ++ has_short_ttime = false; ++ ++ bfq_log_bfqq(bfqd, bfqq, "update_has_short_ttime: has_short_ttime %d", ++ has_short_ttime); + +- if (enable_idle) +- bfq_mark_bfqq_idle_window(bfqq); ++ if (has_short_ttime) ++ bfq_mark_bfqq_has_short_ttime(bfqq); + else +- bfq_clear_bfqq_idle_window(bfqq); ++ bfq_clear_bfqq_has_short_ttime(bfqq); + } + + /* +@@ -4250,14 +4265,12 @@ static void bfq_rq_enqueued(struct bfq_data *bfqd, struct bfq_queue *bfqq, + bfqq->meta_pending++; + + bfq_update_io_thinktime(bfqd, bic); ++ bfq_update_has_short_ttime(bfqd, bfqq, bic); + bfq_update_io_seektime(bfqd, bfqq, rq); +- if (bfqq->entity.service > bfq_max_budget(bfqd) / 8 || +- !BFQQ_SEEKY(bfqq)) +- bfq_update_idle_window(bfqd, bfqq, bic); + + bfq_log_bfqq(bfqd, bfqq, +- "rq_enqueued: idle_window=%d (seeky %d)", +- bfq_bfqq_idle_window(bfqq), BFQQ_SEEKY(bfqq)); ++ "rq_enqueued: has_short_ttime=%d (seeky %d)", ++ bfq_bfqq_has_short_ttime(bfqq), BFQQ_SEEKY(bfqq)); + + bfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); + +diff --git a/block/bfq.h b/block/bfq.h +index ffa833863d88..1f2c7518d507 100644 +--- a/block/bfq.h ++++ b/block/bfq.h +@@ -349,11 +349,11 @@ struct bfq_io_cq { + #endif + + /* +- * Snapshot of the idle window before merging; taken to +- * remember this value while the queue is merged, so as to be +- * able to restore it in case of split. ++ * Snapshot of the has_short_time flag before merging; taken ++ * to remember its value while the queue is merged, so as to ++ * be able to restore it in case of split. + */ +- bool saved_idle_window; ++ bool saved_has_short_ttime; + /* + * Same purpose as the previous two fields for the I/O bound + * classification of a queue. +@@ -610,7 +610,7 @@ enum bfqq_state_flags { + */ + BFQ_BFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ + BFQ_BFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ +- BFQ_BFQQ_FLAG_idle_window, /* slice idling enabled */ ++ BFQ_BFQQ_FLAG_has_short_ttime, /* queue has a short think time */ + BFQ_BFQQ_FLAG_sync, /* synchronous queue */ + BFQ_BFQQ_FLAG_IO_bound, /* + * bfqq has timed-out at least once +@@ -649,7 +649,7 @@ BFQ_BFQQ_FNS(wait_request); + BFQ_BFQQ_FNS(non_blocking_wait_rq); + BFQ_BFQQ_FNS(must_alloc); + BFQ_BFQQ_FNS(fifo_expire); +-BFQ_BFQQ_FNS(idle_window); ++BFQ_BFQQ_FNS(has_short_ttime); + BFQ_BFQQ_FNS(sync); + BFQ_BFQQ_FNS(IO_bound); + BFQ_BFQQ_FNS(in_large_burst); |