diff options
Diffstat (limited to 'block/blk-stat.c')
-rw-r--r-- | block/blk-stat.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/block/blk-stat.c b/block/blk-stat.c index 8e3974d87..bdb16d84b 100644 --- a/block/blk-stat.c +++ b/block/blk-stat.c @@ -9,11 +9,29 @@ #include "blk-stat.h" #include "blk-mq.h" +static void blk_stat_flush_batch(struct blk_rq_stat *stat) +{ + if (!stat->nr_batch) + return; + if (!stat->nr_samples) + stat->mean = div64_s64(stat->batch, stat->nr_batch); + else { + stat->mean = div64_s64((stat->mean * stat->nr_samples) + + stat->batch, + stat->nr_samples + stat->nr_batch); + } + + stat->nr_samples += stat->nr_batch; + stat->nr_batch = stat->batch = 0; +} + void blk_stat_sum(struct blk_rq_stat *dst, struct blk_rq_stat *src) { if (!src->nr_samples) return; + blk_stat_flush_batch(src); + dst->min = min(dst->min, src->min); dst->max = max(dst->max, src->max); @@ -31,6 +49,7 @@ static void blk_mq_stat_get(struct request_queue *q, struct blk_rq_stat *dst) { struct blk_mq_hw_ctx *hctx; struct blk_mq_ctx *ctx; + uint64_t latest = 0; int i, j, nr; blk_stat_init(&dst[0]); @@ -58,6 +77,9 @@ static void blk_mq_stat_get(struct request_queue *q, struct blk_rq_stat *dst) if (!newest) break; + if (newest > latest) + latest = newest; + queue_for_each_hw_ctx(q, hctx, i) { hctx_for_each_ctx(hctx, ctx, j) { if (ctx->stat[0].time == newest) { @@ -75,6 +97,8 @@ static void blk_mq_stat_get(struct request_queue *q, struct blk_rq_stat *dst) * Should be very rare. */ } while (!nr); + + dst[0].time = dst[1].time = latest; } void blk_queue_stat_get(struct request_queue *q, struct blk_rq_stat *dst) @@ -132,6 +156,7 @@ static void __blk_stat_init(struct blk_rq_stat *stat, s64 time_now) { stat->min = -1ULL; stat->max = stat->nr_samples = stat->mean = 0; + stat->batch = stat->nr_batch = 0; stat->time = time_now & BLK_STAT_MASK; } @@ -140,16 +165,26 @@ void blk_stat_init(struct blk_rq_stat *stat) __blk_stat_init(stat, ktime_to_ns(ktime_get())); } +static bool __blk_stat_is_current(struct blk_rq_stat *stat, s64 now) +{ + return (now & BLK_STAT_MASK) == (stat->time & BLK_STAT_MASK); +} + +bool blk_stat_is_current(struct blk_rq_stat *stat) +{ + return __blk_stat_is_current(stat, ktime_to_ns(ktime_get())); +} + void blk_stat_add(struct blk_rq_stat *stat, struct request *rq) { - s64 delta, now, value; + s64 now, value; u64 rq_time = wbt_issue_stat_get_time(&rq->wb_stat); now = ktime_to_ns(ktime_get()); if (now < rq_time) return; - if ((now & BLK_STAT_MASK) != (stat->time & BLK_STAT_MASK)) + if (!__blk_stat_is_current(stat, now)) __blk_stat_init(stat, now); value = now - rq_time; @@ -158,11 +193,12 @@ void blk_stat_add(struct blk_rq_stat *stat, struct request *rq) if (value < stat->min) stat->min = value; - delta = value - stat->mean; - if (delta) - stat->mean += div64_s64(delta, stat->nr_samples + 1); + if (stat->batch + value < stat->batch || + stat->nr_batch + 1 == BLK_RQ_STAT_BATCH) + blk_stat_flush_batch(stat); - stat->nr_samples++; + stat->batch += value; + stat->nr_batch++; } void blk_stat_clear(struct request_queue *q) |