Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/usr/bin/python
# This program was created as a modification to Brendan Gregg's
# biolatency script.
from __future__ import print_function
from bcc import BPF
from time import sleep, strftime
import argparse
# arguments
examples = """examples:
./iolat-bcc # summarize block I/O latency as a histogram
./iolat-bcc -Q # include OS queued time in I/O time
"""
parser = argparse.ArgumentParser(
description="Summarize block device I/O latency as a histogram",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples)
parser.add_argument("-Q", "--queued", action="store_true",
help="include OS queued time in I/O time")
args = parser.parse_args()
# define BPF program
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>
typedef struct disk_key {
char disk[DISK_NAME_LEN];
u64 slot;
} disk_key_t;
BPF_HASH(start, struct request *);
BPF_HASH(dist, disk_key_t);
// time block I/O
int trace_req_start(struct pt_regs *ctx, struct request *req)
{
u64 ts = bpf_ktime_get_ns();
start.update(&req, &ts);
return 0;
}
#define LLN() if(v > 100) { exp++; v /= 10; } else goto good;
#define LLN2() LLN() LLN()
#define LLN4() LLN2() LLN2()
#define LLN8() LLN4() LLN4()
#define LLN16() LLN8() LLN8()
#define LLN32() LLN16() LLN16()
#define LLN64() LLN32() LLN32()
#define LLN128() LLN64() LLN64()
static unsigned int bpf_circll(unsigned long v)
{
int exp = 1;
if(v == 0) return 0;
if(v < 10) return (v*10 << 8) | exp;
LLN128()
if(v > 100) return 0xff00;
good:
return (v << 8) | (exp & 0xff);
}
// output
int trace_req_completion(struct pt_regs *ctx, struct request *req)
{
u64 *old, *tsp, delta, zero = 0;
// fetch timestamp and calculate delta
tsp = start.lookup(&req);
if (tsp == 0) {
return 0; // missed issue
}
delta = bpf_ktime_get_ns() - *tsp;
delta /= 1000;
// store as histogram
disk_key_t key = {.slot = bpf_circll(delta)};
bpf_probe_read(&key.disk, sizeof(key.disk), req->rq_disk->disk_name);
old = dist.lookup_or_init(&key, &zero);
(*old)++;
memcpy(key.disk, "sd", 3);
old = dist.lookup_or_init(&key, &zero);
(*old)++;
start.delete(&req);
return 0;
}
"""
# load BPF program
b = BPF(text=bpf_text)
if args.queued:
b.attach_kprobe(event="blk_account_io_start", fn_name="trace_req_start")
else:
b.attach_kprobe(event="blk_start_request", fn_name="trace_req_start")
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_req_start")
b.attach_kprobe(event="blk_account_io_completion",
fn_name="trace_req_completion")
# output
interval = 5
dist = b.get_table("dist")
while (1):
sleep(int(interval))
for k,v in dist.items():
print(" [%-8s (%f)] %d" % (k.disk, ((0xff & (k.slot >> 8)) / 10.0) * 10.0 ** (k.slot & 0xff), v.value))
print()
dist.clear()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.