1#!/usr/bin/python 2# 3# biolatpcts.py IO latency percentile calculation example 4# 5# Copyright (C) 2020 Tejun Heo <tj@kernel.org> 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 22void kprobe_blk_account_io_done(struct pt_regs *ctx, struct request *rq, u64 now) 23{ 24 unsigned int cmd_flags; 25 u64 dur; 26 size_t base, slot; 27 28 if (!rq->io_start_time_ns) 29 return; 30 31 dur = now - rq->io_start_time_ns; 32 33 slot = min_t(size_t, div_u64(dur, 100 * NSEC_PER_MSEC), 99); 34 lat_100ms.increment(slot); 35 if (slot) 36 return; 37 38 slot = min_t(size_t, div_u64(dur, NSEC_PER_MSEC), 99); 39 lat_1ms.increment(slot); 40 if (slot) 41 return; 42 43 slot = min_t(size_t, div_u64(dur, 10 * NSEC_PER_USEC), 99); 44 lat_10us.increment(slot); 45} 46""" 47 48bpf = BPF(text=bpf_source) 49if BPF.get_kprobe_functions(b'__blk_account_io_done'): 50 bpf.attach_kprobe(event="__blk_account_io_done", fn_name="kprobe_blk_account_io_done") 51else: 52 bpf.attach_kprobe(event="blk_account_io_done", fn_name="kprobe_blk_account_io_done") 53 54cur_lat_100ms = bpf['lat_100ms'] 55cur_lat_1ms = bpf['lat_1ms'] 56cur_lat_10us = bpf['lat_10us'] 57 58last_lat_100ms = [0] * 100 59last_lat_1ms = [0] * 100 60last_lat_10us = [0] * 100 61 62lat_100ms = [0] * 100 63lat_1ms = [0] * 100 64lat_10us = [0] * 100 65 66def find_pct(req, total, slots, idx, counted): 67 while idx > 0: 68 idx -= 1 69 if slots[idx] > 0: 70 counted += slots[idx] 71 if (counted / total) * 100 >= 100 - req: 72 break 73 return (idx, counted) 74 75def calc_lat_pct(req_pcts, total, lat_100ms, lat_1ms, lat_10us): 76 pcts = [0] * len(req_pcts) 77 78 if total == 0: 79 return pcts 80 81 data = [(100 * 1000, lat_100ms), (1000, lat_1ms), (10, lat_10us)] 82 data_sel = 0 83 idx = 100 84 counted = 0 85 86 for pct_idx in reversed(range(len(req_pcts))): 87 req = float(req_pcts[pct_idx]) 88 while True: 89 last_counted = counted 90 (gran, slots) = data[data_sel] 91 (idx, counted) = find_pct(req, total, slots, idx, counted) 92 if idx > 0 or data_sel == len(data) - 1: 93 break 94 counted = last_counted 95 data_sel += 1 96 idx = 100 97 98 pcts[pct_idx] = gran * idx + gran / 2 99 100 return pcts 101 102print('Block I/O latency percentile example. See tools/biolatpcts.py for the full utility.') 103 104while True: 105 sleep(3) 106 107 lat_total = 0; 108 109 for i in range(100): 110 v = cur_lat_100ms.sum(i).value 111 lat_100ms[i] = max(v - last_lat_100ms[i], 0) 112 last_lat_100ms[i] = v 113 114 v = cur_lat_1ms.sum(i).value 115 lat_1ms[i] = max(v - last_lat_1ms[i], 0) 116 last_lat_1ms[i] = v 117 118 v = cur_lat_10us.sum(i).value 119 lat_10us[i] = max(v - last_lat_10us[i], 0) 120 last_lat_10us[i] = v 121 122 lat_total += lat_100ms[i] 123 124 target_pcts = [50, 75, 90, 99] 125 pcts = calc_lat_pct(target_pcts, lat_total, lat_100ms, lat_1ms, lat_10us); 126 for i in range(len(target_pcts)): 127 print('p{}={}us '.format(target_pcts[i], int(pcts[i])), end='') 128 print() 129