blob: 46bebc4ad0e2e67843c8173d041b7c7f2ac3f628 [file] [log] [blame]
Brendan Gregg9fa15622015-09-21 15:51:11 -07001#!/usr/bin/python
Alexei Starovoitova79da0a2016-01-09 12:06:40 -08002# @lint-avoid-python-3-compatibility-imports
Brendan Gregg9fa15622015-09-21 15:51:11 -07003#
Alexei Starovoitova79da0a2016-01-09 12:06:40 -08004# biolatency Summarize block device I/O latency as a histogram.
5# For Linux, uses BCC, eBPF.
Brendan Gregg9fa15622015-09-21 15:51:11 -07006#
Brendan Gregg44e68772015-09-25 13:20:16 -07007# USAGE: biolatency [-h] [-T] [-Q] [-m] [-D] [interval] [count]
Brendan Gregg9fa15622015-09-21 15:51:11 -07008#
9# Copyright (c) 2015 Brendan Gregg.
10# Licensed under the Apache License, Version 2.0 (the "License")
11#
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080012# 20-Sep-2015 Brendan Gregg Created this.
Brendan Gregg9fa15622015-09-21 15:51:11 -070013
14from __future__ import print_function
15from bcc import BPF
16from time import sleep, strftime
17import argparse
18
19# arguments
20examples = """examples:
21 ./biolatency # summarize block I/O latency as a histogram
22 ./biolatency 1 10 # print 1 second summaries, 10 times
23 ./biolatency -mT 1 # 1s summaries, milliseconds, and timestamps
24 ./biolatency -Q # include OS queued time in I/O time
Brendan Gregg44e68772015-09-25 13:20:16 -070025 ./biolatency -D # show each disk device separately
Brendan Gregg9fa15622015-09-21 15:51:11 -070026"""
27parser = argparse.ArgumentParser(
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080028 description="Summarize block device I/O latency as a histogram",
29 formatter_class=argparse.RawDescriptionHelpFormatter,
30 epilog=examples)
Brendan Gregg9fa15622015-09-21 15:51:11 -070031parser.add_argument("-T", "--timestamp", action="store_true",
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080032 help="include timestamp on output")
Brendan Gregg9fa15622015-09-21 15:51:11 -070033parser.add_argument("-Q", "--queued", action="store_true",
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080034 help="include OS queued time in I/O time")
Brendan Gregg9fa15622015-09-21 15:51:11 -070035parser.add_argument("-m", "--milliseconds", action="store_true",
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080036 help="millisecond histogram")
Brendan Gregg44e68772015-09-25 13:20:16 -070037parser.add_argument("-D", "--disks", action="store_true",
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080038 help="print a histogram per disk device")
Brendan Gregg9fa15622015-09-21 15:51:11 -070039parser.add_argument("interval", nargs="?", default=99999999,
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080040 help="output interval, in seconds")
Brendan Gregg9fa15622015-09-21 15:51:11 -070041parser.add_argument("count", nargs="?", default=99999999,
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080042 help="number of outputs")
Brendan Gregg9fa15622015-09-21 15:51:11 -070043args = parser.parse_args()
44countdown = int(args.count)
45debug = 0
46
Brendan Gregg44e68772015-09-25 13:20:16 -070047# define BPF program
Brendan Gregg9fa15622015-09-21 15:51:11 -070048bpf_text = """
49#include <uapi/linux/ptrace.h>
50#include <linux/blkdev.h>
51
Brendan Gregg44e68772015-09-25 13:20:16 -070052typedef struct disk_key {
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080053 char disk[DISK_NAME_LEN];
54 u64 slot;
Brendan Gregg44e68772015-09-25 13:20:16 -070055} disk_key_t;
Brendan Gregg9fa15622015-09-21 15:51:11 -070056BPF_HASH(start, struct request *);
Brendan Gregg44e68772015-09-25 13:20:16 -070057STORAGE
Brendan Gregg9fa15622015-09-21 15:51:11 -070058
59// time block I/O
60int trace_req_start(struct pt_regs *ctx, struct request *req)
61{
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080062 u64 ts = bpf_ktime_get_ns();
63 start.update(&req, &ts);
64 return 0;
Brendan Gregg9fa15622015-09-21 15:51:11 -070065}
66
67// output
68int trace_req_completion(struct pt_regs *ctx, struct request *req)
69{
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080070 u64 *tsp, delta;
Brendan Gregg9fa15622015-09-21 15:51:11 -070071
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080072 // fetch timestamp and calculate delta
73 tsp = start.lookup(&req);
74 if (tsp == 0) {
75 return 0; // missed issue
76 }
77 delta = bpf_ktime_get_ns() - *tsp;
78 FACTOR
Brendan Gregg9fa15622015-09-21 15:51:11 -070079
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080080 // store as histogram
81 STORE
Brendan Gregg9fa15622015-09-21 15:51:11 -070082
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080083 start.delete(&req);
84 return 0;
Brendan Gregg9fa15622015-09-21 15:51:11 -070085}
86"""
Brendan Gregg44e68772015-09-25 13:20:16 -070087
88# code substitutions
Brendan Gregg9fa15622015-09-21 15:51:11 -070089if args.milliseconds:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080090 bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000000;')
91 label = "msecs"
Brendan Gregg9fa15622015-09-21 15:51:11 -070092else:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080093 bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000;')
94 label = "usecs"
Brendan Gregg44e68772015-09-25 13:20:16 -070095if args.disks:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -080096 bpf_text = bpf_text.replace('STORAGE',
97 'BPF_HISTOGRAM(dist, disk_key_t);')
98 bpf_text = bpf_text.replace('STORE',
99 'disk_key_t key = {.slot = bpf_log2l(delta)}; ' +
100 'bpf_probe_read(&key.disk, sizeof(key.disk), ' +
101 'req->rq_disk->disk_name); dist.increment(key);')
Brendan Gregg44e68772015-09-25 13:20:16 -0700102else:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800103 bpf_text = bpf_text.replace('STORAGE', 'BPF_HISTOGRAM(dist);')
104 bpf_text = bpf_text.replace('STORE',
105 'dist.increment(bpf_log2l(delta));')
Brendan Gregg9fa15622015-09-21 15:51:11 -0700106if debug:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800107 print(bpf_text)
Brendan Gregg9fa15622015-09-21 15:51:11 -0700108
109# load BPF program
110b = BPF(text=bpf_text)
111if args.queued:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800112 b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start")
Brendan Gregg9fa15622015-09-21 15:51:11 -0700113else:
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800114 b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
115 b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
Brendan Gregg9fa15622015-09-21 15:51:11 -0700116b.attach_kprobe(event="blk_account_io_completion",
117 fn_name="trace_req_completion")
118
119print("Tracing block device I/O... Hit Ctrl-C to end.")
120
121# output
122exiting = 0 if args.interval else 1
123dist = b.get_table("dist")
124while (1):
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800125 try:
126 sleep(int(args.interval))
127 except KeyboardInterrupt:
128 exiting = 1
Brendan Gregg9fa15622015-09-21 15:51:11 -0700129
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800130 print()
131 if args.timestamp:
132 print("%-8s\n" % strftime("%H:%M:%S"), end="")
Brendan Gregg9fa15622015-09-21 15:51:11 -0700133
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800134 dist.print_log2_hist(label, "disk")
135 dist.clear()
Brendan Gregg9fa15622015-09-21 15:51:11 -0700136
Alexei Starovoitova79da0a2016-01-09 12:06:40 -0800137 countdown -= 1
138 if exiting or countdown == 0:
139 exit()