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); 15*209200efSShaohua 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 { 33cf43e6beSJens Axboe if (!src->nr_samples) 34cf43e6beSJens Axboe return; 35cf43e6beSJens Axboe 36cf43e6beSJens Axboe blk_stat_flush_batch(src); 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) { 67cf43e6beSJens Axboe if (!ctx->stat[BLK_STAT_READ].nr_samples && 68cf43e6beSJens Axboe !ctx->stat[BLK_STAT_WRITE].nr_samples) 69cf43e6beSJens Axboe continue; 70cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time > newest) 71cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_READ].time; 72cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time > newest) 73cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_WRITE].time; 74cf43e6beSJens Axboe } 75cf43e6beSJens Axboe } 76cf43e6beSJens Axboe 77cf43e6beSJens Axboe /* 78cf43e6beSJens Axboe * No samples 79cf43e6beSJens Axboe */ 80cf43e6beSJens Axboe if (!newest) 81cf43e6beSJens Axboe break; 82cf43e6beSJens Axboe 83cf43e6beSJens Axboe if (newest > latest) 84cf43e6beSJens Axboe latest = newest; 85cf43e6beSJens Axboe 86cf43e6beSJens Axboe queue_for_each_hw_ctx(q, hctx, i) { 87cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, j) { 88cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time == newest) { 89cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_READ], 90cf43e6beSJens Axboe &ctx->stat[BLK_STAT_READ]); 91cf43e6beSJens Axboe nr++; 92cf43e6beSJens Axboe } 93cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time == newest) { 94cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_WRITE], 95cf43e6beSJens Axboe &ctx->stat[BLK_STAT_WRITE]); 96cf43e6beSJens Axboe nr++; 97cf43e6beSJens Axboe } 98cf43e6beSJens Axboe } 99cf43e6beSJens Axboe } 100cf43e6beSJens Axboe /* 101cf43e6beSJens Axboe * If we race on finding an entry, just loop back again. 102cf43e6beSJens Axboe * Should be very rare. 103cf43e6beSJens Axboe */ 104cf43e6beSJens Axboe } while (!nr); 105cf43e6beSJens Axboe 106cf43e6beSJens Axboe dst[BLK_STAT_READ].time = dst[BLK_STAT_WRITE].time = latest; 107cf43e6beSJens Axboe } 108cf43e6beSJens Axboe 109cf43e6beSJens Axboe void blk_queue_stat_get(struct request_queue *q, struct blk_rq_stat *dst) 110cf43e6beSJens Axboe { 111cf43e6beSJens Axboe if (q->mq_ops) 112cf43e6beSJens Axboe blk_mq_stat_get(q, dst); 113cf43e6beSJens Axboe else { 114cf43e6beSJens Axboe memcpy(&dst[BLK_STAT_READ], &q->rq_stats[BLK_STAT_READ], 115cf43e6beSJens Axboe sizeof(struct blk_rq_stat)); 116cf43e6beSJens Axboe memcpy(&dst[BLK_STAT_WRITE], &q->rq_stats[BLK_STAT_WRITE], 117cf43e6beSJens Axboe sizeof(struct blk_rq_stat)); 118cf43e6beSJens Axboe } 119cf43e6beSJens Axboe } 120cf43e6beSJens Axboe 121cf43e6beSJens Axboe void blk_hctx_stat_get(struct blk_mq_hw_ctx *hctx, struct blk_rq_stat *dst) 122cf43e6beSJens Axboe { 123cf43e6beSJens Axboe struct blk_mq_ctx *ctx; 124cf43e6beSJens Axboe unsigned int i, nr; 125cf43e6beSJens Axboe 126cf43e6beSJens Axboe nr = 0; 127cf43e6beSJens Axboe do { 128cf43e6beSJens Axboe uint64_t newest = 0; 129cf43e6beSJens Axboe 130cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, i) { 131cf43e6beSJens Axboe if (!ctx->stat[BLK_STAT_READ].nr_samples && 132cf43e6beSJens Axboe !ctx->stat[BLK_STAT_WRITE].nr_samples) 133cf43e6beSJens Axboe continue; 134cf43e6beSJens Axboe 135cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time > newest) 136cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_READ].time; 137cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time > newest) 138cf43e6beSJens Axboe newest = ctx->stat[BLK_STAT_WRITE].time; 139cf43e6beSJens Axboe } 140cf43e6beSJens Axboe 141cf43e6beSJens Axboe if (!newest) 142cf43e6beSJens Axboe break; 143cf43e6beSJens Axboe 144cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, i) { 145cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_READ].time == newest) { 146cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_READ], 147cf43e6beSJens Axboe &ctx->stat[BLK_STAT_READ]); 148cf43e6beSJens Axboe nr++; 149cf43e6beSJens Axboe } 150cf43e6beSJens Axboe if (ctx->stat[BLK_STAT_WRITE].time == newest) { 151cf43e6beSJens Axboe blk_stat_sum(&dst[BLK_STAT_WRITE], 152cf43e6beSJens Axboe &ctx->stat[BLK_STAT_WRITE]); 153cf43e6beSJens Axboe nr++; 154cf43e6beSJens Axboe } 155cf43e6beSJens Axboe } 156cf43e6beSJens Axboe /* 157cf43e6beSJens Axboe * If we race on finding an entry, just loop back again. 158cf43e6beSJens Axboe * Should be very rare, as the window is only updated 159cf43e6beSJens Axboe * occasionally 160cf43e6beSJens Axboe */ 161cf43e6beSJens Axboe } while (!nr); 162cf43e6beSJens Axboe } 163cf43e6beSJens Axboe 164cf43e6beSJens Axboe static void __blk_stat_init(struct blk_rq_stat *stat, s64 time_now) 165cf43e6beSJens Axboe { 166cf43e6beSJens Axboe stat->min = -1ULL; 167cf43e6beSJens Axboe stat->max = stat->nr_samples = stat->mean = 0; 168cf43e6beSJens Axboe stat->batch = stat->nr_batch = 0; 169cf43e6beSJens Axboe stat->time = time_now & BLK_STAT_NSEC_MASK; 170cf43e6beSJens Axboe } 171cf43e6beSJens Axboe 172cf43e6beSJens Axboe void blk_stat_init(struct blk_rq_stat *stat) 173cf43e6beSJens Axboe { 174cf43e6beSJens Axboe __blk_stat_init(stat, ktime_to_ns(ktime_get())); 175cf43e6beSJens Axboe } 176cf43e6beSJens Axboe 177cf43e6beSJens Axboe static bool __blk_stat_is_current(struct blk_rq_stat *stat, s64 now) 178cf43e6beSJens Axboe { 179cf43e6beSJens Axboe return (now & BLK_STAT_NSEC_MASK) == (stat->time & BLK_STAT_NSEC_MASK); 180cf43e6beSJens Axboe } 181cf43e6beSJens Axboe 182cf43e6beSJens Axboe bool blk_stat_is_current(struct blk_rq_stat *stat) 183cf43e6beSJens Axboe { 184cf43e6beSJens Axboe return __blk_stat_is_current(stat, ktime_to_ns(ktime_get())); 185cf43e6beSJens Axboe } 186cf43e6beSJens Axboe 187cf43e6beSJens Axboe void blk_stat_add(struct blk_rq_stat *stat, struct request *rq) 188cf43e6beSJens Axboe { 189cf43e6beSJens Axboe s64 now, value; 190cf43e6beSJens Axboe 191cf43e6beSJens Axboe now = __blk_stat_time(ktime_to_ns(ktime_get())); 192cf43e6beSJens Axboe if (now < blk_stat_time(&rq->issue_stat)) 193cf43e6beSJens Axboe return; 194cf43e6beSJens Axboe 195cf43e6beSJens Axboe if (!__blk_stat_is_current(stat, now)) 196cf43e6beSJens Axboe __blk_stat_init(stat, now); 197cf43e6beSJens Axboe 198cf43e6beSJens Axboe value = now - blk_stat_time(&rq->issue_stat); 199cf43e6beSJens Axboe if (value > stat->max) 200cf43e6beSJens Axboe stat->max = value; 201cf43e6beSJens Axboe if (value < stat->min) 202cf43e6beSJens Axboe stat->min = value; 203cf43e6beSJens Axboe 204cf43e6beSJens Axboe if (stat->batch + value < stat->batch || 205cf43e6beSJens Axboe stat->nr_batch + 1 == BLK_RQ_STAT_BATCH) 206cf43e6beSJens Axboe blk_stat_flush_batch(stat); 207cf43e6beSJens Axboe 208cf43e6beSJens Axboe stat->batch += value; 209cf43e6beSJens Axboe stat->nr_batch++; 210cf43e6beSJens Axboe } 211cf43e6beSJens Axboe 212cf43e6beSJens Axboe void blk_stat_clear(struct request_queue *q) 213cf43e6beSJens Axboe { 214cf43e6beSJens Axboe if (q->mq_ops) { 215cf43e6beSJens Axboe struct blk_mq_hw_ctx *hctx; 216cf43e6beSJens Axboe struct blk_mq_ctx *ctx; 217cf43e6beSJens Axboe int i, j; 218cf43e6beSJens Axboe 219cf43e6beSJens Axboe queue_for_each_hw_ctx(q, hctx, i) { 220cf43e6beSJens Axboe hctx_for_each_ctx(hctx, ctx, j) { 221cf43e6beSJens Axboe blk_stat_init(&ctx->stat[BLK_STAT_READ]); 222cf43e6beSJens Axboe blk_stat_init(&ctx->stat[BLK_STAT_WRITE]); 223cf43e6beSJens Axboe } 224cf43e6beSJens Axboe } 225cf43e6beSJens Axboe } else { 226cf43e6beSJens Axboe blk_stat_init(&q->rq_stats[BLK_STAT_READ]); 227cf43e6beSJens Axboe blk_stat_init(&q->rq_stats[BLK_STAT_WRITE]); 228cf43e6beSJens Axboe } 229cf43e6beSJens Axboe } 230cf43e6beSJens Axboe 231cf43e6beSJens Axboe void blk_stat_set_issue_time(struct blk_issue_stat *stat) 232cf43e6beSJens Axboe { 233cf43e6beSJens Axboe stat->time = (stat->time & BLK_STAT_MASK) | 234cf43e6beSJens Axboe (ktime_to_ns(ktime_get()) & BLK_STAT_TIME_MASK); 235cf43e6beSJens Axboe } 236cf43e6beSJens Axboe 237cf43e6beSJens Axboe /* 238cf43e6beSJens Axboe * Enable stat tracking, return whether it was enabled 239cf43e6beSJens Axboe */ 240cf43e6beSJens Axboe bool blk_stat_enable(struct request_queue *q) 241cf43e6beSJens Axboe { 242cf43e6beSJens Axboe if (!test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) { 243cf43e6beSJens Axboe set_bit(QUEUE_FLAG_STATS, &q->queue_flags); 244cf43e6beSJens Axboe return false; 245cf43e6beSJens Axboe } 246cf43e6beSJens Axboe 247cf43e6beSJens Axboe return true; 248cf43e6beSJens Axboe } 249