• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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