Created
March 3, 2017 20:56
-
-
Save postwait/95362773f2c13588abfd4c4eb95bba1c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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