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