1cf43e6beSJens Axboe /* 2cf43e6beSJens Axboe * Block stat tracking code 3cf43e6beSJens Axboe * 4cf43e6beSJens Axboe * Copyright (C) 2016 Jens Axboe 5cf43e6beSJens Axboe */ 6cf43e6beSJens Axboe #include <linux/kernel.h> 7cf43e6beSJens Axboe #include <linux/blk-mq.h> 8cf43e6beSJens Axboe 9cf43e6beSJens Axboe #include "blk-stat.h" 10cf43e6beSJens Axboe #include "blk-mq.h" 11cf43e6beSJens Axboe 12cf43e6beSJens Axboe static void blk_stat_flush_batch(struct blk_rq_stat *stat) 13cf43e6beSJens Axboe { 14cf43e6beSJens Axboe const s32 nr_batch = READ_ONCE(stat->nr_batch); 15209200efSShaohua Li const s32 nr_samples = READ_ONCE(stat->nr_samples); 16cf43e6beSJens Axboe 17cf43e6beSJens Axboe if (!nr_batch) 18cf43e6beSJens Axboe return; 19cf43e6beSJens Axboe if (!nr_samples) 20cf43e6beSJens Axboe stat->mean = div64_s64(stat->batch, nr_batch); 21cf43e6beSJens Axboe else { 22cf43e6beSJens Axboe stat->mean = div64_s64((stat->mean * nr_samples) + 23cf43e6beSJens Axboe stat->batch, 24cf43e6beSJens Axboe nr_batch + nr_samples); 25cf43e6beSJens Axboe } 26cf43e6beSJens Axboe 27cf43e6beSJens Axboe stat->nr_samples += nr_batch; 28cf43e6beSJens Axboe stat->nr_batch = stat->batch = 0; 29cf43e6beSJens Axboe } 30cf43e6beSJens Axboe 31cf43e6beSJens Axboe static void blk_stat_sum(struct blk_rq_stat *dst, struct blk_rq_stat *src) 32cf43e6beSJens Axboe { 33*7d8d0014SOmar Sandoval blk_stat_flush_batch(src); 34*7d8d0014SOmar Sandoval 35cf43e6beSJens Axboe if (!src->nr_samples) 36cf43e6beSJens Axboe return; 37cf43e6beSJens Axboe 38cf43e6beSJens Axboe dst->min = min(dst->min, src->min); 39cf43e6beSJens Axboe dst->max = max(dst->max, src->max); 40cf43e6beSJens Axboe 41cf43e6beSJens Axboe if (!dst->nr_samples) 42cf43e6beSJens Axboe dst->mean = src->mean; 43cf43e6beSJens Axboe else { 44cf43e6beSJens Axboe dst->mean = div64_s64((src->mean * src->nr_samples) + 45cf43e6beSJens Axboe (dst->mean * dst->nr_samples), 46cf43e6beSJens Axboe dst->nr_samples + src->nr_samples); 47cf43e6beSJens Axboe } 48cf43e6beSJens Axboe dst->nr_samples += src->nr_samples; 49cf43e6beSJens Axboe } 50cf43e6beSJens Axboe 51cf43e6beSJens Axboe static void blk_mq_stat_get(struct request_queue *q, struct blk_rq_stat *dst) 52cf43e6beSJens Axboe { 53cf43e6beSJens Axboe struct blk_mq_hw_ctx *hctx; 54cf43e6beSJens Axboe struct blk_mq_ctx *ctx; 55cf43e6beSJens Axboe uint64_t latest = 0; 56cf43e6beSJens Axboe int i, j, nr; 57cf43e6beSJens Axboe 58cf43e6beSJens Axboe blk_stat_init(&dst[BLK_STAT_READ]); 59cf43e6beSJens Axboe blk_stat_init(&dst[BLK_STAT_WRITE]); 60cf43e6beSJens Axboe 61cf43e6beSJens Axboe nr = 0; 62cf43e6beSJens Axboe do { 63cf43e6beSJens Axboe uint64_t newest = 0; 64cf43e6beSJens Axboe 65cf43e6beSJens Axboe queue_for_each_hw_ctx(q, hctx, i) { 66cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, j) { 677cd54aa8SJens Axboe blk_stat_flush_batch(&ctx->stat[BLK_STAT_READ]); 687cd54aa8SJens Axboe blk_stat_flush_batch(&ctx->stat[BLK_STAT_WRITE]); 697cd54aa8SJens Axboe 70cf43e6beSJens Axboe if (!ctx->stat[BLK_STAT_READ].nr_samples && 71cf43e6beSJens Axboe !ctx->stat[BLK_STAT_WRITE].nr_samples) 72cf43e6beSJens Axboe continue; 73cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time > newest) 74cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_READ].time; 75cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time > newest) 76cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_WRITE].time; 77cf43e6beSJens Axboe } 78cf43e6beSJens Axboe } 79cf43e6beSJens Axboe 80cf43e6beSJens Axboe /* 81cf43e6beSJens Axboe * No samples 82cf43e6beSJens Axboe */ 83cf43e6beSJens Axboe if (!newest) 84cf43e6beSJens Axboe break; 85cf43e6beSJens Axboe 86cf43e6beSJens Axboe if (newest > latest) 87cf43e6beSJens Axboe latest = newest; 88cf43e6beSJens Axboe 89cf43e6beSJens Axboe queue_for_each_hw_ctx(q, hctx, i) { 90cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, j) { 91cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time == newest) { 92cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_READ], 93cf43e6beSJens Axboe &ctx->stat[BLK_STAT_READ]); 94cf43e6beSJens Axboe nr++; 95cf43e6beSJens Axboe } 96cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time == newest) { 97cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_WRITE], 98cf43e6beSJens Axboe &ctx->stat[BLK_STAT_WRITE]); 99cf43e6beSJens Axboe nr++; 100cf43e6beSJens Axboe } 101cf43e6beSJens Axboe } 102cf43e6beSJens Axboe } 103cf43e6beSJens Axboe /* 104cf43e6beSJens Axboe * If we race on finding an entry, just loop back again. 105cf43e6beSJens Axboe * Should be very rare. 106cf43e6beSJens Axboe */ 107cf43e6beSJens Axboe } while (!nr); 108cf43e6beSJens Axboe 109cf43e6beSJens Axboe dst[BLK_STAT_READ].time = dst[BLK_STAT_WRITE].time = latest; 110cf43e6beSJens Axboe } 111cf43e6beSJens Axboe 112cf43e6beSJens Axboe void blk_queue_stat_get(struct request_queue *q, struct blk_rq_stat *dst) 113cf43e6beSJens Axboe { 114cf43e6beSJens Axboe if (q->mq_ops) 115cf43e6beSJens Axboe blk_mq_stat_get(q, dst); 116cf43e6beSJens Axboe else { 1177cd54aa8SJens Axboe blk_stat_flush_batch(&q->rq_stats[BLK_STAT_READ]); 1187cd54aa8SJens Axboe blk_stat_flush_batch(&q->rq_stats[BLK_STAT_WRITE]); 119cf43e6beSJens Axboe memcpy(&dst[BLK_STAT_READ], &q->rq_stats[BLK_STAT_READ], 120cf43e6beSJens Axboe sizeof(struct blk_rq_stat)); 121cf43e6beSJens Axboe memcpy(&dst[BLK_STAT_WRITE], &q->rq_stats[BLK_STAT_WRITE], 122cf43e6beSJens Axboe sizeof(struct blk_rq_stat)); 123cf43e6beSJens Axboe } 124cf43e6beSJens Axboe } 125cf43e6beSJens Axboe 126cf43e6beSJens Axboe void blk_hctx_stat_get(struct blk_mq_hw_ctx *hctx, struct blk_rq_stat *dst) 127cf43e6beSJens Axboe { 128cf43e6beSJens Axboe struct blk_mq_ctx *ctx; 129cf43e6beSJens Axboe unsigned int i, nr; 130cf43e6beSJens Axboe 131cf43e6beSJens Axboe nr = 0; 132cf43e6beSJens Axboe do { 133cf43e6beSJens Axboe uint64_t newest = 0; 134cf43e6beSJens Axboe 135cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, i) { 1367cd54aa8SJens Axboe blk_stat_flush_batch(&ctx->stat[BLK_STAT_READ]); 1377cd54aa8SJens Axboe blk_stat_flush_batch(&ctx->stat[BLK_STAT_WRITE]); 1387cd54aa8SJens Axboe 139cf43e6beSJens Axboe if (!ctx->stat[BLK_STAT_READ].nr_samples && 140cf43e6beSJens Axboe !ctx->stat[BLK_STAT_WRITE].nr_samples) 141cf43e6beSJens Axboe continue; 142cf43e6beSJens Axboe 143cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time > newest) 144cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_READ].time; 145cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time > newest) 146cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_WRITE].time; 147cf43e6beSJens Axboe } 148cf43e6beSJens Axboe 149cf43e6beSJens Axboe if (!newest) 150cf43e6beSJens Axboe break; 151cf43e6beSJens Axboe 152cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, i) { 153cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time == newest) { 154cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_READ], 155cf43e6beSJens Axboe &ctx->stat[BLK_STAT_READ]); 156cf43e6beSJens Axboe nr++; 157cf43e6beSJens Axboe } 158cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time == newest) { 159cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_WRITE], 160cf43e6beSJens Axboe &ctx->stat[BLK_STAT_WRITE]); 161cf43e6beSJens Axboe nr++; 162cf43e6beSJens Axboe } 163cf43e6beSJens Axboe } 164cf43e6beSJens Axboe /* 165cf43e6beSJens Axboe * If we race on finding an entry, just loop back again. 166cf43e6beSJens Axboe * Should be very rare, as the window is only updated 167cf43e6beSJens Axboe * occasionally 168cf43e6beSJens Axboe */ 169cf43e6beSJens Axboe } while (!nr); 170cf43e6beSJens Axboe } 171cf43e6beSJens Axboe 172cf43e6beSJens Axboe static void __blk_stat_init(struct blk_rq_stat *stat, s64 time_now) 173cf43e6beSJens Axboe { 174cf43e6beSJens Axboe stat->min = -1ULL; 175cf43e6beSJens Axboe stat->max = stat->nr_samples = stat->mean = 0; 176cf43e6beSJens Axboe stat->batch = stat->nr_batch = 0; 177cf43e6beSJens Axboe stat->time = time_now & BLK_STAT_NSEC_MASK; 178cf43e6beSJens Axboe } 179cf43e6beSJens Axboe 180cf43e6beSJens Axboe void blk_stat_init(struct blk_rq_stat *stat) 181cf43e6beSJens Axboe { 182cf43e6beSJens Axboe __blk_stat_init(stat, ktime_to_ns(ktime_get())); 183cf43e6beSJens Axboe } 184cf43e6beSJens Axboe 185cf43e6beSJens Axboe static bool __blk_stat_is_current(struct blk_rq_stat *stat, s64 now) 186cf43e6beSJens Axboe { 187cf43e6beSJens Axboe return (now & BLK_STAT_NSEC_MASK) == (stat->time & BLK_STAT_NSEC_MASK); 188cf43e6beSJens Axboe } 189cf43e6beSJens Axboe 190cf43e6beSJens Axboe bool blk_stat_is_current(struct blk_rq_stat *stat) 191cf43e6beSJens Axboe { 192cf43e6beSJens Axboe return __blk_stat_is_current(stat, ktime_to_ns(ktime_get())); 193cf43e6beSJens Axboe } 194cf43e6beSJens Axboe 195cf43e6beSJens Axboe void blk_stat_add(struct blk_rq_stat *stat, struct request *rq) 196cf43e6beSJens Axboe { 197cf43e6beSJens Axboe s64 now, value; 198cf43e6beSJens Axboe 199cf43e6beSJens Axboe now = __blk_stat_time(ktime_to_ns(ktime_get())); 200cf43e6beSJens Axboe if (now < blk_stat_time(&rq->issue_stat)) 201cf43e6beSJens Axboe return; 202cf43e6beSJens Axboe 203cf43e6beSJens Axboe if (!__blk_stat_is_current(stat, now)) 204cf43e6beSJens Axboe __blk_stat_init(stat, now); 205cf43e6beSJens Axboe 206cf43e6beSJens Axboe value = now - blk_stat_time(&rq->issue_stat); 207cf43e6beSJens Axboe if (value > stat->max) 208cf43e6beSJens Axboe stat->max = value; 209cf43e6beSJens Axboe if (value < stat->min) 210cf43e6beSJens Axboe stat->min = value; 211cf43e6beSJens Axboe 212cf43e6beSJens Axboe if (stat->batch + value < stat->batch || 213cf43e6beSJens Axboe stat->nr_batch + 1 == BLK_RQ_STAT_BATCH) 214cf43e6beSJens Axboe blk_stat_flush_batch(stat); 215cf43e6beSJens Axboe 216cf43e6beSJens Axboe stat->batch += value; 217cf43e6beSJens Axboe stat->nr_batch++; 218cf43e6beSJens Axboe } 219cf43e6beSJens Axboe 220cf43e6beSJens Axboe void blk_stat_clear(struct request_queue *q) 221cf43e6beSJens Axboe { 222cf43e6beSJens Axboe if (q->mq_ops) { 223cf43e6beSJens Axboe struct blk_mq_hw_ctx *hctx; 224cf43e6beSJens Axboe struct blk_mq_ctx *ctx; 225cf43e6beSJens Axboe int i, j; 226cf43e6beSJens Axboe 227cf43e6beSJens Axboe queue_for_each_hw_ctx(q, hctx, i) { 228cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, j) { 229cf43e6beSJens Axboe blk_stat_init(&ctx->stat[BLK_STAT_READ]); 230cf43e6beSJens Axboe blk_stat_init(&ctx->stat[BLK_STAT_WRITE]); 231cf43e6beSJens Axboe } 232cf43e6beSJens Axboe } 233cf43e6beSJens Axboe } else { 234cf43e6beSJens Axboe blk_stat_init(&q->rq_stats[BLK_STAT_READ]); 235cf43e6beSJens Axboe blk_stat_init(&q->rq_stats[BLK_STAT_WRITE]); 236cf43e6beSJens Axboe } 237cf43e6beSJens Axboe } 238cf43e6beSJens Axboe 239cf43e6beSJens Axboe void blk_stat_set_issue_time(struct blk_issue_stat *stat) 240cf43e6beSJens Axboe { 241cf43e6beSJens Axboe stat->time = (stat->time & BLK_STAT_MASK) | 242cf43e6beSJens Axboe (ktime_to_ns(ktime_get()) & BLK_STAT_TIME_MASK); 243cf43e6beSJens Axboe } 244cf43e6beSJens Axboe 245cf43e6beSJens Axboe /* 246cf43e6beSJens Axboe * Enable stat tracking, return whether it was enabled 247cf43e6beSJens Axboe */ 248cf43e6beSJens Axboe bool blk_stat_enable(struct request_queue *q) 249cf43e6beSJens Axboe { 250cf43e6beSJens Axboe if (!test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) { 251cf43e6beSJens Axboe set_bit(QUEUE_FLAG_STATS, &q->queue_flags); 252cf43e6beSJens Axboe return false; 253cf43e6beSJens Axboe } 254cf43e6beSJens Axboe 255cf43e6beSJens Axboe return true; 256cf43e6beSJens Axboe } 257