Skip to content

Commit 73d5811

Browse files
Algodev-githubaxboe
authored andcommitted
block, bfq: consider also ioprio classes in symmetry detection
In asymmetric scenarios, i.e., when some bfq_queue or bfq_group needs to be guaranteed a different bandwidth than other bfq_queues or bfq_groups, these service guaranteed can be provided only by plugging I/O dispatch, completely or partially, when the queue in service remains temporarily empty. A case where asymmetry is particularly strong is when some active bfq_queues belong to a higher-priority class than some other active bfq_queues. Unfortunately, this important case is not considered at all in the code for detecting asymmetric scenarios. This commit adds the missing logic. Signed-off-by: Paolo Valente <paolo.valente@linaro.org> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 03e565e commit 73d5811

File tree

3 files changed

+59
-47
lines changed

3 files changed

+59
-47
lines changed

block/bfq-iosched.c

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -623,26 +623,6 @@ void bfq_pos_tree_add_move(struct bfq_data *bfqd, struct bfq_queue *bfqq)
623623
bfqq->pos_root = NULL;
624624
}
625625

626-
/*
627-
* Tell whether there are active queues with different weights or
628-
* active groups.
629-
*/
630-
static bool bfq_varied_queue_weights_or_active_groups(struct bfq_data *bfqd)
631-
{
632-
/*
633-
* For queue weights to differ, queue_weights_tree must contain
634-
* at least two nodes.
635-
*/
636-
return (!RB_EMPTY_ROOT(&bfqd->queue_weights_tree) &&
637-
(bfqd->queue_weights_tree.rb_node->rb_left ||
638-
bfqd->queue_weights_tree.rb_node->rb_right)
639-
#ifdef CONFIG_BFQ_GROUP_IOSCHED
640-
) ||
641-
(bfqd->num_groups_with_pending_reqs > 0
642-
#endif
643-
);
644-
}
645-
646626
/*
647627
* The following function returns true if every queue must receive the
648628
* same share of the throughput (this condition is used when deciding
@@ -651,25 +631,48 @@ static bool bfq_varied_queue_weights_or_active_groups(struct bfq_data *bfqd)
651631
*
652632
* Such a scenario occurs when:
653633
* 1) all active queues have the same weight,
654-
* 2) all active groups at the same level in the groups tree have the same
655-
* weight,
634+
* 2) all active queues belong to the same I/O-priority class,
656635
* 3) all active groups at the same level in the groups tree have the same
636+
* weight,
637+
* 4) all active groups at the same level in the groups tree have the same
657638
* number of children.
658639
*
659640
* Unfortunately, keeping the necessary state for evaluating exactly
660641
* the last two symmetry sub-conditions above would be quite complex
661-
* and time consuming. Therefore this function evaluates, instead,
662-
* only the following stronger two sub-conditions, for which it is
642+
* and time consuming. Therefore this function evaluates, instead,
643+
* only the following stronger three sub-conditions, for which it is
663644
* much easier to maintain the needed state:
664645
* 1) all active queues have the same weight,
665-
* 2) there are no active groups.
646+
* 2) all active queues belong to the same I/O-priority class,
647+
* 3) there are no active groups.
666648
* In particular, the last condition is always true if hierarchical
667649
* support or the cgroups interface are not enabled, thus no state
668650
* needs to be maintained in this case.
669651
*/
670652
static bool bfq_symmetric_scenario(struct bfq_data *bfqd)
671653
{
672-
return !bfq_varied_queue_weights_or_active_groups(bfqd);
654+
/*
655+
* For queue weights to differ, queue_weights_tree must contain
656+
* at least two nodes.
657+
*/
658+
bool varied_queue_weights = !RB_EMPTY_ROOT(&bfqd->queue_weights_tree) &&
659+
(bfqd->queue_weights_tree.rb_node->rb_left ||
660+
bfqd->queue_weights_tree.rb_node->rb_right);
661+
662+
bool multiple_classes_busy =
663+
(bfqd->busy_queues[0] && bfqd->busy_queues[1]) ||
664+
(bfqd->busy_queues[0] && bfqd->busy_queues[2]) ||
665+
(bfqd->busy_queues[1] && bfqd->busy_queues[2]);
666+
667+
/*
668+
* For queue weights to differ, queue_weights_tree must contain
669+
* at least two nodes.
670+
*/
671+
return !(varied_queue_weights || multiple_classes_busy
672+
#ifdef BFQ_GROUP_IOSCHED_ENABLED
673+
|| bfqd->num_groups_with_pending_reqs > 0
674+
#endif
675+
);
673676
}
674677

675678
/*
@@ -728,15 +731,14 @@ void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq,
728731
/*
729732
* In the unlucky event of an allocation failure, we just
730733
* exit. This will cause the weight of queue to not be
731-
* considered in bfq_varied_queue_weights_or_active_groups,
732-
* which, in its turn, causes the scenario to be deemed
733-
* wrongly symmetric in case bfqq's weight would have been
734-
* the only weight making the scenario asymmetric. On the
735-
* bright side, no unbalance will however occur when bfqq
736-
* becomes inactive again (the invocation of this function
737-
* is triggered by an activation of queue). In fact,
738-
* bfq_weights_tree_remove does nothing if
739-
* !bfqq->weight_counter.
734+
* considered in bfq_symmetric_scenario, which, in its turn,
735+
* causes the scenario to be deemed wrongly symmetric in case
736+
* bfqq's weight would have been the only weight making the
737+
* scenario asymmetric. On the bright side, no unbalance will
738+
* however occur when bfqq becomes inactive again (the
739+
* invocation of this function is triggered by an activation
740+
* of queue). In fact, bfq_weights_tree_remove does nothing
741+
* if !bfqq->weight_counter.
740742
*/
741743
if (unlikely(!bfqq->weight_counter))
742744
return;
@@ -2227,7 +2229,7 @@ bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq,
22272229
return NULL;
22282230

22292231
/* If there is only one backlogged queue, don't search. */
2230-
if (bfqd->busy_queues == 1)
2232+
if (bfq_tot_busy_queues(bfqd) == 1)
22312233
return NULL;
22322234

22332235
in_service_bfqq = bfqd->in_service_queue;
@@ -3681,7 +3683,8 @@ static bool bfq_better_to_idle(struct bfq_queue *bfqq)
36813683
* the requests already queued in the device have been served.
36823684
*/
36833685
asymmetric_scenario = (bfqq->wr_coeff > 1 &&
3684-
bfqd->wr_busy_queues < bfqd->busy_queues) ||
3686+
bfqd->wr_busy_queues <
3687+
bfq_tot_busy_queues(bfqd)) ||
36853688
!bfq_symmetric_scenario(bfqd);
36863689

36873690
/*
@@ -3960,7 +3963,7 @@ static struct request *bfq_dispatch_rq_from_bfqq(struct bfq_data *bfqd,
39603963
* belongs to CLASS_IDLE and other queues are waiting for
39613964
* service.
39623965
*/
3963-
if (!(bfqd->busy_queues > 1 && bfq_class_idle(bfqq)))
3966+
if (!(bfq_tot_busy_queues(bfqd) > 1 && bfq_class_idle(bfqq)))
39643967
goto return_rq;
39653968

39663969
bfq_bfqq_expire(bfqd, bfqq, false, BFQQE_BUDGET_EXHAUSTED);
@@ -3978,7 +3981,7 @@ static bool bfq_has_work(struct blk_mq_hw_ctx *hctx)
39783981
* most a call to dispatch for nothing
39793982
*/
39803983
return !list_empty_careful(&bfqd->dispatch) ||
3981-
bfqd->busy_queues > 0;
3984+
bfq_tot_busy_queues(bfqd) > 0;
39823985
}
39833986

39843987
static struct request *__bfq_dispatch_request(struct blk_mq_hw_ctx *hctx)
@@ -4032,9 +4035,10 @@ static struct request *__bfq_dispatch_request(struct blk_mq_hw_ctx *hctx)
40324035
goto start_rq;
40334036
}
40344037

4035-
bfq_log(bfqd, "dispatch requests: %d busy queues", bfqd->busy_queues);
4038+
bfq_log(bfqd, "dispatch requests: %d busy queues",
4039+
bfq_tot_busy_queues(bfqd));
40364040

4037-
if (bfqd->busy_queues == 0)
4041+
if (bfq_tot_busy_queues(bfqd) == 0)
40384042
goto exit;
40394043

40404044
/*

block/bfq-iosched.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -501,10 +501,11 @@ struct bfq_data {
501501
unsigned int num_groups_with_pending_reqs;
502502

503503
/*
504-
* Number of bfq_queues containing requests (including the
505-
* queue in service, even if it is idling).
504+
* Per-class (RT, BE, IDLE) number of bfq_queues containing
505+
* requests (including the queue in service, even if it is
506+
* idling).
506507
*/
507-
int busy_queues;
508+
unsigned int busy_queues[3];
508509
/* number of weight-raised busy @bfq_queues */
509510
int wr_busy_queues;
510511
/* number of queued requests */
@@ -974,6 +975,7 @@ extern struct blkcg_policy blkcg_policy_bfq;
974975

975976
struct bfq_group *bfq_bfqq_to_bfqg(struct bfq_queue *bfqq);
976977
struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity);
978+
unsigned int bfq_tot_busy_queues(struct bfq_data *bfqd);
977979
struct bfq_service_tree *bfq_entity_service_tree(struct bfq_entity *entity);
978980
struct bfq_entity *bfq_entity_of(struct rb_node *node);
979981
unsigned short bfq_ioprio_to_weight(int ioprio);

block/bfq-wf2q.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ static unsigned int bfq_class_idx(struct bfq_entity *entity)
4444
BFQ_DEFAULT_GRP_CLASS - 1;
4545
}
4646

47+
unsigned int bfq_tot_busy_queues(struct bfq_data *bfqd)
48+
{
49+
return bfqd->busy_queues[0] + bfqd->busy_queues[1] +
50+
bfqd->busy_queues[2];
51+
}
52+
4753
static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
4854
bool expiration);
4955

@@ -1513,7 +1519,7 @@ struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
15131519
struct bfq_sched_data *sd;
15141520
struct bfq_queue *bfqq;
15151521

1516-
if (bfqd->busy_queues == 0)
1522+
if (bfq_tot_busy_queues(bfqd) == 0)
15171523
return NULL;
15181524

15191525
/*
@@ -1665,7 +1671,7 @@ void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
16651671

16661672
bfq_clear_bfqq_busy(bfqq);
16671673

1668-
bfqd->busy_queues--;
1674+
bfqd->busy_queues[bfqq->ioprio_class - 1]--;
16691675

16701676
if (!bfqq->dispatched)
16711677
bfq_weights_tree_remove(bfqd, bfqq);
@@ -1688,7 +1694,7 @@ void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq)
16881694
bfq_activate_bfqq(bfqd, bfqq);
16891695

16901696
bfq_mark_bfqq_busy(bfqq);
1691-
bfqd->busy_queues++;
1697+
bfqd->busy_queues[bfqq->ioprio_class - 1]++;
16921698

16931699
if (!bfqq->dispatched)
16941700
if (bfqq->wr_coeff == 1)

0 commit comments

Comments
 (0)