Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 359501
b: refs/heads/master
c: 1d3650f
h: refs/heads/master
i:
  359499: fd1b1c2
v: v3
  • Loading branch information
Tejun Heo committed Jan 9, 2013
1 parent 8736e56 commit 7576c95
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7918ffb5b83e3373206ada84873c674fbddf61cc
refs/heads/master: 1d3650f713e7f6392b02fde450c5bae40291e65b
107 changes: 77 additions & 30 deletions trunk/block/cfq-iosched.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,18 @@ struct cfq_group {
int nr_active;
unsigned int children_weight;

/*
* vfraction is the fraction of vdisktime that the tasks in this
* cfqg are entitled to. This is determined by compounding the
* ratios walking up from this cfqg to the root.
*
* It is in fixed point w/ CFQ_SERVICE_SHIFT and the sum of all
* vfractions on a service tree is approximately 1. The sum may
* deviate a bit due to rounding errors and fluctuations caused by
* cfqgs entering and leaving the service tree.
*/
unsigned int vfraction;

/*
* There are two weights - (internal) weight is the weight of this
* cfqg against the sibling cfqgs. leaf_weight is the wight of
Expand Down Expand Up @@ -891,13 +903,27 @@ cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio);
}

static inline u64 cfq_scale_slice(unsigned long delta, struct cfq_group *cfqg)
/**
* cfqg_scale_charge - scale disk time charge according to cfqg weight
* @charge: disk time being charged
* @vfraction: vfraction of the cfqg, fixed point w/ CFQ_SERVICE_SHIFT
*
* Scale @charge according to @vfraction, which is in range (0, 1]. The
* scaling is inversely proportional.
*
* scaled = charge / vfraction
*
* The result is also in fixed point w/ CFQ_SERVICE_SHIFT.
*/
static inline u64 cfqg_scale_charge(unsigned long charge,
unsigned int vfraction)
{
u64 d = delta << CFQ_SERVICE_SHIFT;
u64 c = charge << CFQ_SERVICE_SHIFT; /* make it fixed point */

d = d * CFQ_WEIGHT_DEFAULT;
do_div(d, cfqg->weight);
return d;
/* charge / vfraction */
c <<= CFQ_SERVICE_SHIFT;
do_div(c, vfraction);
return c;
}

static inline u64 max_vdisktime(u64 min_vdisktime, u64 vdisktime)
Expand Down Expand Up @@ -1237,7 +1263,9 @@ cfq_update_group_weight(struct cfq_group *cfqg)
static void
cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
{
unsigned int vfr = 1 << CFQ_SERVICE_SHIFT; /* start with 1 */
struct cfq_group *pos = cfqg;
struct cfq_group *parent;
bool propagate;

/* add to the service tree */
Expand All @@ -1248,22 +1276,34 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
st->total_weight += cfqg->weight;

/*
* Activate @cfqg and propagate activation upwards until we meet an
* already activated node or reach root.
* Activate @cfqg and calculate the portion of vfraction @cfqg is
* entitled to. vfraction is calculated by walking the tree
* towards the root calculating the fraction it has at each level.
* The compounded ratio is how much vfraction @cfqg owns.
*
* Start with the proportion tasks in this cfqg has against active
* children cfqgs - its leaf_weight against children_weight.
*/
propagate = !pos->nr_active++;
pos->children_weight += pos->leaf_weight;
vfr = vfr * pos->leaf_weight / pos->children_weight;

while (propagate) {
struct cfq_group *parent = cfqg_flat_parent(pos);

if (!parent)
break;

propagate = !parent->nr_active++;
parent->children_weight += pos->weight;
/*
* Compound ->weight walking up the tree. Both activation and
* vfraction calculation are done in the same loop. Propagation
* stops once an already activated node is met. vfraction
* calculation should always continue to the root.
*/
while ((parent = cfqg_flat_parent(pos))) {
if (propagate) {
propagate = !parent->nr_active++;
parent->children_weight += pos->weight;
}
vfr = vfr * pos->weight / parent->children_weight;
pos = parent;
}

cfqg->vfraction = max_t(unsigned, vfr, 1);
}

static void
Expand Down Expand Up @@ -1309,6 +1349,7 @@ cfq_group_service_tree_del(struct cfq_rb_root *st, struct cfq_group *cfqg)

/* @pos has 0 nr_active at this point */
WARN_ON_ONCE(pos->children_weight);
pos->vfraction = 0;

if (!parent)
break;
Expand Down Expand Up @@ -1381,6 +1422,7 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
unsigned int used_sl, charge, unaccounted_sl = 0;
int nr_sync = cfqg->nr_cfqq - cfqg_busy_async_queues(cfqd, cfqg)
- cfqg->service_tree_idle.count;
unsigned int vfr;

BUG_ON(nr_sync < 0);
used_sl = charge = cfq_cfqq_slice_usage(cfqq, &unaccounted_sl);
Expand All @@ -1390,10 +1432,15 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
else if (!cfq_cfqq_sync(cfqq) && !nr_sync)
charge = cfqq->allocated_slice;

/* Can't update vdisktime while group is on service tree */
/*
* Can't update vdisktime while on service tree and cfqg->vfraction
* is valid only while on it. Cache vfr, leave the service tree,
* update vdisktime and go back on. The re-addition to the tree
* will also update the weights as necessary.
*/
vfr = cfqg->vfraction;
cfq_group_service_tree_del(st, cfqg);
cfqg->vdisktime += cfq_scale_slice(charge, cfqg);
/* If a new weight was requested, update now, off tree */
cfqg->vdisktime += cfqg_scale_charge(charge, vfr);
cfq_group_service_tree_add(st, cfqg);

/* This group is being expired. Save the context */
Expand Down Expand Up @@ -1669,44 +1716,44 @@ static int cfqg_print_avg_queue_size(struct cgroup *cgrp, struct cftype *cft,
#endif /* CONFIG_DEBUG_BLK_CGROUP */

static struct cftype cfq_blkcg_files[] = {
/* on root, weight is mapped to leaf_weight */
{
.name = "weight_device",
.read_seq_string = cfqg_print_weight_device,
.write_string = cfqg_set_weight_device,
.flags = CFTYPE_ONLY_ON_ROOT,
.read_seq_string = cfqg_print_leaf_weight_device,
.write_string = cfqg_set_leaf_weight_device,
.max_write_len = 256,
},
{
.name = "weight",
.read_seq_string = cfq_print_weight,
.write_u64 = cfq_set_weight,
.flags = CFTYPE_ONLY_ON_ROOT,
.read_seq_string = cfq_print_leaf_weight,
.write_u64 = cfq_set_leaf_weight,
},

/* on root, leaf_weight is mapped to weight */
/* no such mapping necessary for !roots */
{
.name = "leaf_weight_device",
.flags = CFTYPE_ONLY_ON_ROOT,
.name = "weight_device",
.flags = CFTYPE_NOT_ON_ROOT,
.read_seq_string = cfqg_print_weight_device,
.write_string = cfqg_set_weight_device,
.max_write_len = 256,
},
{
.name = "leaf_weight",
.flags = CFTYPE_ONLY_ON_ROOT,
.name = "weight",
.flags = CFTYPE_NOT_ON_ROOT,
.read_seq_string = cfq_print_weight,
.write_u64 = cfq_set_weight,
},

/* no such mapping necessary for !roots */
{
.name = "leaf_weight_device",
.flags = CFTYPE_NOT_ON_ROOT,
.read_seq_string = cfqg_print_leaf_weight_device,
.write_string = cfqg_set_leaf_weight_device,
.max_write_len = 256,
},
{
.name = "leaf_weight",
.flags = CFTYPE_NOT_ON_ROOT,
.read_seq_string = cfq_print_leaf_weight,
.write_u64 = cfq_set_leaf_weight,
},
Expand Down

0 comments on commit 7576c95

Please sign in to comment.