Merge a7863b3423 ("blk-iocost: update iocost_monitor.py") into android-mainline

Bisection on the way to 5.10-rc1

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Ib96c933a2903e2f30edc0ca13929a318537f77d8
This commit is contained in:
Greg Kroah-Hartman 2020-10-24 14:39:55 +02:00
commit 072f3a5b28
2 changed files with 91 additions and 40 deletions

View File

@ -452,6 +452,9 @@ struct iocg_pcpu_stat {
struct iocg_stat {
u64 usage_us;
u64 wait_us;
u64 indebt_us;
u64 indelay_us;
};
/* per device-cgroup pair */
@ -538,6 +541,9 @@ struct ioc_gq {
struct iocg_stat last_stat;
u64 last_stat_abs_vusage;
u64 usage_delta_us;
u64 wait_since;
u64 indebt_since;
u64 indelay_since;
/* this iocg's depth in the hierarchy and ancestors including self */
int level;
@ -1303,9 +1309,15 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
}
if (delay >= MIN_DELAY) {
if (!iocg->indelay_since)
iocg->indelay_since = now->now;
blkcg_set_delay(blkg, delay * NSEC_PER_USEC);
return true;
} else {
if (iocg->indelay_since) {
iocg->local_stat.indelay_us += now->now - iocg->indelay_since;
iocg->indelay_since = 0;
}
iocg->delay = 0;
blkcg_clear_delay(blkg);
return false;
@ -1325,8 +1337,10 @@ static void iocg_incur_debt(struct ioc_gq *iocg, u64 abs_cost,
* Once in debt, debt handling owns inuse. @iocg stays at the minimum
* inuse donating all of it share to others until its debt is paid off.
*/
if (!iocg->abs_vdebt && abs_cost)
if (!iocg->abs_vdebt && abs_cost) {
iocg->indebt_since = now->now;
propagate_weights(iocg, iocg->active, 0, false, now);
}
iocg->abs_vdebt += abs_cost;
@ -1348,9 +1362,13 @@ static void iocg_pay_debt(struct ioc_gq *iocg, u64 abs_vpay,
iocg->abs_vdebt -= min(abs_vpay, iocg->abs_vdebt);
/* if debt is paid in full, restore inuse */
if (!iocg->abs_vdebt)
if (!iocg->abs_vdebt) {
iocg->local_stat.indebt_us += now->now - iocg->indebt_since;
iocg->indebt_since = 0;
propagate_weights(iocg, iocg->active, iocg->last_inuse,
false, now);
}
}
static int iocg_wake_fn(struct wait_queue_entry *wq_entry, unsigned mode,
@ -1436,8 +1454,17 @@ static void iocg_kick_waitq(struct ioc_gq *iocg, bool pay_debt,
__wake_up_locked_key(&iocg->waitq, TASK_NORMAL, &ctx);
if (!waitqueue_active(&iocg->waitq))
if (!waitqueue_active(&iocg->waitq)) {
if (iocg->wait_since) {
iocg->local_stat.wait_us += now->now - iocg->wait_since;
iocg->wait_since = 0;
}
return;
}
if (!iocg->wait_since)
iocg->wait_since = now->now;
if (WARN_ON_ONCE(ctx.vbudget >= 0))
return;
@ -1579,8 +1606,15 @@ static void iocg_flush_stat_one(struct ioc_gq *iocg, struct ioc_now *now)
iocg->usage_delta_us = div64_u64(vusage_delta, ioc->vtime_base_rate);
iocg->local_stat.usage_us += iocg->usage_delta_us;
/* propagate upwards */
new_stat.usage_us =
iocg->local_stat.usage_us + iocg->desc_stat.usage_us;
new_stat.wait_us =
iocg->local_stat.wait_us + iocg->desc_stat.wait_us;
new_stat.indebt_us =
iocg->local_stat.indebt_us + iocg->desc_stat.indebt_us;
new_stat.indelay_us =
iocg->local_stat.indelay_us + iocg->desc_stat.indelay_us;
/* propagate the deltas to the parent */
if (iocg->level > 0) {
@ -1589,6 +1623,12 @@ static void iocg_flush_stat_one(struct ioc_gq *iocg, struct ioc_now *now)
parent_stat->usage_us +=
new_stat.usage_us - iocg->last_stat.usage_us;
parent_stat->wait_us +=
new_stat.wait_us - iocg->last_stat.wait_us;
parent_stat->indebt_us +=
new_stat.indebt_us - iocg->last_stat.indebt_us;
parent_stat->indelay_us +=
new_stat.indelay_us - iocg->last_stat.indelay_us;
}
iocg->last_stat = new_stat;
@ -1961,8 +2001,6 @@ static void ioc_timer_fn(struct timer_list *timer)
return;
}
iocg_flush_stat(&ioc->active_iocgs, &now);
/*
* Waiters determine the sleep durations based on the vrate they
* saw at the time of sleep. If vrate has increased, some waiters
@ -1976,6 +2014,22 @@ static void ioc_timer_fn(struct timer_list *timer)
spin_lock(&iocg->waitq.lock);
/* flush wait and indebt stat deltas */
if (iocg->wait_since) {
iocg->local_stat.wait_us += now.now - iocg->wait_since;
iocg->wait_since = now.now;
}
if (iocg->indebt_since) {
iocg->local_stat.indebt_us +=
now.now - iocg->indebt_since;
iocg->indebt_since = now.now;
}
if (iocg->indelay_since) {
iocg->local_stat.indelay_us +=
now.now - iocg->indelay_since;
iocg->indelay_since = now.now;
}
if (waitqueue_active(&iocg->waitq) || iocg->abs_vdebt ||
iocg->delay) {
/* might be oversleeping vtime / hweight changes, kick */
@ -2010,6 +2064,12 @@ static void ioc_timer_fn(struct timer_list *timer)
}
commit_weights(ioc);
/*
* Wait and indebt stat are flushed above and the donation calculation
* below needs updated usage stat. Let's bring stat up-to-date.
*/
iocg_flush_stat(&ioc->active_iocgs, &now);
/* calc usage and see whether some weights need to be moved around */
list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
u64 vdone, vtime, usage_us, usage_dur;
@ -2835,6 +2895,13 @@ static size_t ioc_pd_stat(struct blkg_policy_data *pd, char *buf, size_t size)
pos += scnprintf(buf + pos, size - pos, " cost.usage=%llu",
iocg->last_stat.usage_us);
if (blkcg_debug_stats)
pos += scnprintf(buf + pos, size - pos,
" cost.wait=%llu cost.indebt=%llu cost.indelay=%llu",
iocg->last_stat.wait_us,
iocg->last_stat.indebt_us,
iocg->last_stat.indelay_us);
return pos;
}

View File

@ -45,8 +45,7 @@ except:
err('The kernel does not have iocost enabled')
IOC_RUNNING = prog['IOC_RUNNING'].value_()
NR_USAGE_SLOTS = prog['NR_USAGE_SLOTS'].value_()
HWEIGHT_WHOLE = prog['HWEIGHT_WHOLE'].value_()
WEIGHT_ONE = prog['WEIGHT_ONE'].value_()
VTIME_PER_SEC = prog['VTIME_PER_SEC'].value_()
VTIME_PER_USEC = prog['VTIME_PER_USEC'].value_()
AUTOP_SSD_FAST = prog['AUTOP_SSD_FAST'].value_()
@ -100,7 +99,7 @@ class IocStat:
self.period_ms = ioc.period_us.value_() / 1_000
self.period_at = ioc.period_at.value_() / 1_000_000
self.vperiod_at = ioc.period_at_vtime.value_() / VTIME_PER_SEC
self.vrate_pct = ioc.vtime_rate.counter.value_() * 100 / VTIME_PER_USEC
self.vrate_pct = ioc.vtime_base_rate.value_() * 100 / VTIME_PER_USEC
self.busy_level = ioc.busy_level.value_()
self.autop_idx = ioc.autop_idx.value_()
self.user_cost_model = ioc.user_cost_model.value_()
@ -136,7 +135,7 @@ class IocStat:
def table_header_str(self):
return f'{"":25} active {"weight":>9} {"hweight%":>13} {"inflt%":>6} ' \
f'{"dbt":>3} {"delay":>6} {"usages%"}'
f'{"debt":>7} {"delay":>7} {"usage%"}'
class IocgStat:
def __init__(self, iocg):
@ -144,11 +143,11 @@ class IocgStat:
blkg = iocg.pd.blkg
self.is_active = not list_empty(iocg.active_list.address_of_())
self.weight = iocg.weight.value_()
self.active = iocg.active.value_()
self.inuse = iocg.inuse.value_()
self.hwa_pct = iocg.hweight_active.value_() * 100 / HWEIGHT_WHOLE
self.hwi_pct = iocg.hweight_inuse.value_() * 100 / HWEIGHT_WHOLE
self.weight = iocg.weight.value_() / WEIGHT_ONE
self.active = iocg.active.value_() / WEIGHT_ONE
self.inuse = iocg.inuse.value_() / WEIGHT_ONE
self.hwa_pct = iocg.hweight_active.value_() * 100 / WEIGHT_ONE
self.hwi_pct = iocg.hweight_inuse.value_() * 100 / WEIGHT_ONE
self.address = iocg.value_()
vdone = iocg.done_vtime.counter.value_()
@ -160,23 +159,13 @@ class IocgStat:
else:
self.inflight_pct = 0
# vdebt used to be an atomic64_t and is now u64, support both
try:
self.debt_ms = iocg.abs_vdebt.counter.value_() / VTIME_PER_USEC / 1000
except:
self.debt_ms = iocg.abs_vdebt.value_() / VTIME_PER_USEC / 1000
self.use_delay = blkg.use_delay.counter.value_()
self.delay_ms = blkg.delay_nsec.counter.value_() / 1_000_000
usage_idx = iocg.usage_idx.value_()
self.usages = []
self.usage = 0
for i in range(NR_USAGE_SLOTS):
usage = iocg.usages[(usage_idx + 1 + i) % NR_USAGE_SLOTS].value_()
upct = usage * 100 / HWEIGHT_WHOLE
self.usages.append(upct)
self.usage = max(self.usage, upct)
self.usage = (100 * iocg.usage_delta_us.value_() /
ioc.period_us.value_()) if self.active else 0
self.debt_ms = iocg.abs_vdebt.value_() / VTIME_PER_USEC / 1000
if blkg.use_delay.counter.value_() != 0:
self.delay_ms = blkg.delay_nsec.counter.value_() / 1_000_000
else:
self.delay_ms = 0
def dict(self, now, path):
out = { 'cgroup' : path,
@ -189,25 +178,20 @@ class IocgStat:
'hweight_inuse_pct' : self.hwi_pct,
'inflight_pct' : self.inflight_pct,
'debt_ms' : self.debt_ms,
'use_delay' : self.use_delay,
'delay_ms' : self.delay_ms,
'usage_pct' : self.usage,
'address' : self.address }
for i in range(len(self.usages)):
out[f'usage_pct_{i}'] = str(self.usages[i])
return out
def table_row_str(self, path):
out = f'{path[-28:]:28} ' \
f'{"*" if self.is_active else " "} ' \
f'{self.inuse:5}/{self.active:5} ' \
f'{round(self.inuse):5}/{round(self.active):5} ' \
f'{self.hwi_pct:6.2f}/{self.hwa_pct:6.2f} ' \
f'{self.inflight_pct:6.2f} ' \
f'{min(math.ceil(self.debt_ms), 999):3} ' \
f'{min(self.use_delay, 99):2}*'\
f'{min(math.ceil(self.delay_ms), 999):03} '
for u in self.usages:
out += f'{min(round(u), 999):03d}:'
f'{self.debt_ms:7.2f} ' \
f'{self.delay_ms:7.2f} '\
f'{min(self.usage, 999):6.2f}'
out = out.rstrip(':')
return out