Commit f0bf84a5 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

blk-iocost: add three debug stat - cost.wait, indebt and indelay

These are really cheap to collect and can be useful in debugging iocost
behavior. Add them as debug stats for now.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 04603755
...@@ -452,6 +452,9 @@ struct iocg_pcpu_stat { ...@@ -452,6 +452,9 @@ struct iocg_pcpu_stat {
struct iocg_stat { struct iocg_stat {
u64 usage_us; u64 usage_us;
u64 wait_us;
u64 indebt_us;
u64 indelay_us;
}; };
/* per device-cgroup pair */ /* per device-cgroup pair */
...@@ -538,6 +541,9 @@ struct ioc_gq { ...@@ -538,6 +541,9 @@ struct ioc_gq {
struct iocg_stat last_stat; struct iocg_stat last_stat;
u64 last_stat_abs_vusage; u64 last_stat_abs_vusage;
u64 usage_delta_us; u64 usage_delta_us;
u64 wait_since;
u64 indebt_since;
u64 indelay_since;
/* this iocg's depth in the hierarchy and ancestors including self */ /* this iocg's depth in the hierarchy and ancestors including self */
int level; int level;
...@@ -1303,9 +1309,15 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now) ...@@ -1303,9 +1309,15 @@ static bool iocg_kick_delay(struct ioc_gq *iocg, struct ioc_now *now)
} }
if (delay >= MIN_DELAY) { if (delay >= MIN_DELAY) {
if (!iocg->indelay_since)
iocg->indelay_since = now->now;
blkcg_set_delay(blkg, delay * NSEC_PER_USEC); blkcg_set_delay(blkg, delay * NSEC_PER_USEC);
return true; return true;
} else { } else {
if (iocg->indelay_since) {
iocg->local_stat.indelay_us += now->now - iocg->indelay_since;
iocg->indelay_since = 0;
}
iocg->delay = 0; iocg->delay = 0;
blkcg_clear_delay(blkg); blkcg_clear_delay(blkg);
return false; return false;
...@@ -1325,8 +1337,10 @@ static void iocg_incur_debt(struct ioc_gq *iocg, u64 abs_cost, ...@@ -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 * 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. * 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); propagate_weights(iocg, iocg->active, 0, false, now);
}
iocg->abs_vdebt += abs_cost; iocg->abs_vdebt += abs_cost;
...@@ -1348,9 +1362,13 @@ static void iocg_pay_debt(struct ioc_gq *iocg, u64 abs_vpay, ...@@ -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); iocg->abs_vdebt -= min(abs_vpay, iocg->abs_vdebt);
/* if debt is paid in full, restore inuse */ /* 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, propagate_weights(iocg, iocg->active, iocg->last_inuse,
false, now); false, now);
}
} }
static int iocg_wake_fn(struct wait_queue_entry *wq_entry, unsigned mode, 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, ...@@ -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); __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; return;
}
if (!iocg->wait_since)
iocg->wait_since = now->now;
if (WARN_ON_ONCE(ctx.vbudget >= 0)) if (WARN_ON_ONCE(ctx.vbudget >= 0))
return; return;
...@@ -1579,8 +1606,15 @@ static void iocg_flush_stat_one(struct ioc_gq *iocg, struct ioc_now *now) ...@@ -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->usage_delta_us = div64_u64(vusage_delta, ioc->vtime_base_rate);
iocg->local_stat.usage_us += iocg->usage_delta_us; iocg->local_stat.usage_us += iocg->usage_delta_us;
/* propagate upwards */
new_stat.usage_us = new_stat.usage_us =
iocg->local_stat.usage_us + iocg->desc_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 */ /* propagate the deltas to the parent */
if (iocg->level > 0) { if (iocg->level > 0) {
...@@ -1589,6 +1623,12 @@ static void iocg_flush_stat_one(struct ioc_gq *iocg, struct ioc_now *now) ...@@ -1589,6 +1623,12 @@ static void iocg_flush_stat_one(struct ioc_gq *iocg, struct ioc_now *now)
parent_stat->usage_us += parent_stat->usage_us +=
new_stat.usage_us - iocg->last_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; iocg->last_stat = new_stat;
...@@ -1961,8 +2001,6 @@ static void ioc_timer_fn(struct timer_list *timer) ...@@ -1961,8 +2001,6 @@ static void ioc_timer_fn(struct timer_list *timer)
return; return;
} }
iocg_flush_stat(&ioc->active_iocgs, &now);
/* /*
* Waiters determine the sleep durations based on the vrate they * Waiters determine the sleep durations based on the vrate they
* saw at the time of sleep. If vrate has increased, some waiters * 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) ...@@ -1976,6 +2014,22 @@ static void ioc_timer_fn(struct timer_list *timer)
spin_lock(&iocg->waitq.lock); 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 || if (waitqueue_active(&iocg->waitq) || iocg->abs_vdebt ||
iocg->delay) { iocg->delay) {
/* might be oversleeping vtime / hweight changes, kick */ /* might be oversleeping vtime / hweight changes, kick */
...@@ -2010,6 +2064,12 @@ static void ioc_timer_fn(struct timer_list *timer) ...@@ -2010,6 +2064,12 @@ static void ioc_timer_fn(struct timer_list *timer)
} }
commit_weights(ioc); 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 */ /* calc usage and see whether some weights need to be moved around */
list_for_each_entry(iocg, &ioc->active_iocgs, active_list) { list_for_each_entry(iocg, &ioc->active_iocgs, active_list) {
u64 vdone, vtime, usage_us, usage_dur; 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) ...@@ -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", pos += scnprintf(buf + pos, size - pos, " cost.usage=%llu",
iocg->last_stat.usage_us); 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; return pos;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment