1#!/usr/bin/python 2# 3# biolatpcts.py IO latency percentile calculation example 4# 5# Copyright (C) 2020 Tejun Heo <[email protected]> 6# Copyright (C) 2020 Facebook 7 8from __future__ import print_function 9from bcc import BPF 10from time import sleep 11 12bpf_source = """ 13#include <linux/blk_types.h> 14#include <linux/blk-mq.h> 15#include <linux/blkdev.h> 16#include <linux/time64.h> 17 18BPF_PERCPU_ARRAY(lat_100ms, u64, 100); 19BPF_PERCPU_ARRAY(lat_1ms, u64, 100); 20BPF_PERCPU_ARRAY(lat_10us, u64, 100); 21 22RAW_TRACEPOINT_PROBE(block_rq_complete) 23{ 24 // TP_PROTO(struct request *rq, blk_status_t error, unsigned int nr_bytes) 25 struct request *rq = (void *)ctx->args[0]; 26 unsigned int cmd_flags; 27 u64 dur; 28 size_t base, slot; 29 30 if (!rq->io_start_time_ns) 31 return 0; 32 33 dur = bpf_ktime_get_ns() - rq->io_start_time_ns; 34 35 slot = min_t(size_t, div_u64(dur, 100 * NSEC_PER_MSEC), 99); 36 lat_100ms.increment(slot); 37 if (slot) 38 return 0; 39 40 slot = min_t(size_t, div_u64(dur, NSEC_PER_MSEC), 99); 41 lat_1ms.increment(slot); 42 if (slot) 43 return 0; 44 45 slot = min_t(size_t, div_u64(dur, 10 * NSEC_PER_USEC), 99); 46 lat_10us.increment(slot); 47 return 0; 48} 49""" 50 51bpf = BPF(text=bpf_source) 52 53cur_lat_100ms = bpf['lat_100ms'] 54cur_lat_1ms = bpf['lat_1ms'] 55cur_lat_10us = bpf['lat_10us'] 56 57last_lat_100ms = [0] * 100 58last_lat_1ms = [0] * 100 59last_lat_10us = [0] * 100 60 61lat_100ms = [0] * 100 62lat_1ms = [0] * 100 63lat_10us = [0] * 100 64 65def find_pct(req, total, slots, idx, counted): 66 while idx > 0: 67 idx -= 1 68 if slots[idx] > 0: 69 counted += slots[idx] 70 if (counted / total) * 100 >= 100 - req: 71 break 72 return (idx, counted) 73 74def calc_lat_pct(req_pcts, total, lat_100ms, lat_1ms, lat_10us): 75 pcts = [0] * len(req_pcts) 76 77 if total == 0: 78 return pcts 79 80 data = [(100 * 1000, lat_100ms), (1000, lat_1ms), (10, lat_10us)] 81 data_sel = 0 82 idx = 100 83 counted = 0 84 85 for pct_idx in reversed(range(len(req_pcts))): 86 req = float(req_pcts[pct_idx]) 87 while True: 88 last_counted = counted 89 (gran, slots) = data[data_sel] 90 (idx, counted) = find_pct(req, total, slots, idx, counted) 91 if idx > 0 or data_sel == len(data) - 1: 92 break 93 counted = last_counted 94 data_sel += 1 95 idx = 100 96 97 pcts[pct_idx] = gran * idx + gran / 2 98 99 return pcts 100 101print('Block I/O latency percentile example. See tools/biolatpcts.py for the full utility.') 102 103while True: 104 sleep(3) 105 106 lat_total = 0; 107 108 for i in range(100): 109 v = cur_lat_100ms.sum(i).value 110 lat_100ms[i] = max(v - last_lat_100ms[i], 0) 111 last_lat_100ms[i] = v 112 113 v = cur_lat_1ms.sum(i).value 114 lat_1ms[i] = max(v - last_lat_1ms[i], 0) 115 last_lat_1ms[i] = v 116 117 v = cur_lat_10us.sum(i).value 118 lat_10us[i] = max(v - last_lat_10us[i], 0) 119 last_lat_10us[i] = v 120 121 lat_total += lat_100ms[i] 122 123 target_pcts = [50, 75, 90, 99] 124 pcts = calc_lat_pct(target_pcts, lat_total, lat_100ms, lat_1ms, lat_10us); 125 for i in range(len(target_pcts)): 126 print('p{}={}us '.format(target_pcts[i], int(pcts[i])), end='') 127 print() 128