xref: /aosp_15_r20/external/bcc/examples/tracing/biolatpcts.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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