Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bcc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
bcc
Commits
a0aa7f28
Commit
a0aa7f28
authored
Jan 10, 2016
by
Brenden Blanco
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #310 from iovisor/ast_dev
fix pep8 lint errors in biolatency and biosnoop
parents
1ec515ee
a79da0a0
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
136 additions
and
134 deletions
+136
-134
tools/biolatency
tools/biolatency
+59
-58
tools/biosnoop
tools/biosnoop
+72
-71
tools/biosnoop_example.txt
tools/biosnoop_example.txt
+5
-5
No files found.
tools/biolatency
View file @
a0aa7f28
#!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
#
# biolatency
Summarize block device I/O latency as a histogram.
#
For Linux, uses BCC, eBPF.
# biolatency
Summarize block device I/O latency as a histogram.
#
For Linux, uses BCC, eBPF.
#
# USAGE: biolatency [-h] [-T] [-Q] [-m] [-D] [interval] [count]
#
# Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License")
#
# 20-Sep-2015
Brendan Gregg
Created this.
# 20-Sep-2015
Brendan Gregg
Created this.
from
__future__
import
print_function
from
bcc
import
BPF
...
...
@@ -24,21 +25,21 @@ examples = """examples:
./biolatency -D # show each disk device separately
"""
parser
=
argparse
.
ArgumentParser
(
description
=
"Summarize block device I/O latency as a histogram"
,
formatter_class
=
argparse
.
RawDescriptionHelpFormatter
,
epilog
=
examples
)
description
=
"Summarize block device I/O latency as a histogram"
,
formatter_class
=
argparse
.
RawDescriptionHelpFormatter
,
epilog
=
examples
)
parser
.
add_argument
(
"-T"
,
"--timestamp"
,
action
=
"store_true"
,
help
=
"include timestamp on output"
)
help
=
"include timestamp on output"
)
parser
.
add_argument
(
"-Q"
,
"--queued"
,
action
=
"store_true"
,
help
=
"include OS queued time in I/O time"
)
help
=
"include OS queued time in I/O time"
)
parser
.
add_argument
(
"-m"
,
"--milliseconds"
,
action
=
"store_true"
,
help
=
"millisecond histogram"
)
help
=
"millisecond histogram"
)
parser
.
add_argument
(
"-D"
,
"--disks"
,
action
=
"store_true"
,
help
=
"print a histogram per disk device"
)
help
=
"print a histogram per disk device"
)
parser
.
add_argument
(
"interval"
,
nargs
=
"?"
,
default
=
99999999
,
help
=
"output interval, in seconds"
)
help
=
"output interval, in seconds"
)
parser
.
add_argument
(
"count"
,
nargs
=
"?"
,
default
=
99999999
,
help
=
"number of outputs"
)
help
=
"number of outputs"
)
args
=
parser
.
parse_args
()
countdown
=
int
(
args
.
count
)
debug
=
0
...
...
@@ -49,8 +50,8 @@ bpf_text = """
#include <linux/blkdev.h>
typedef struct disk_key {
char disk[DISK_NAME_LEN];
u64 slot;
char disk[DISK_NAME_LEN];
u64 slot;
} disk_key_t;
BPF_HASH(start, struct request *);
STORAGE
...
...
@@ -58,60 +59,60 @@ STORAGE
// 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;
u64 ts = bpf_ktime_get_ns();
start.update(&req, &ts);
return 0;
}
// output
int trace_req_completion(struct pt_regs *ctx, struct request *req)
{
u64 *tsp, delta;
u64 *tsp, delta;
// fetch timestamp and calculate delta
tsp = start.lookup(&req);
if (tsp == 0) {
return 0;
// missed issue
}
delta = bpf_ktime_get_ns() - *tsp;
FACTOR
// fetch timestamp and calculate delta
tsp = start.lookup(&req);
if (tsp == 0) {
return 0;
// missed issue
}
delta = bpf_ktime_get_ns() - *tsp;
FACTOR
// store as histogram
STORE
// store as histogram
STORE
start.delete(&req);
return 0;
start.delete(&req);
return 0;
}
"""
# code substitutions
if
args
.
milliseconds
:
bpf_text
=
bpf_text
.
replace
(
'FACTOR'
,
'delta /= 1000000;'
)
label
=
"msecs"
bpf_text
=
bpf_text
.
replace
(
'FACTOR'
,
'delta /= 1000000;'
)
label
=
"msecs"
else
:
bpf_text
=
bpf_text
.
replace
(
'FACTOR'
,
'delta /= 1000;'
)
label
=
"usecs"
bpf_text
=
bpf_text
.
replace
(
'FACTOR'
,
'delta /= 1000;'
)
label
=
"usecs"
if
args
.
disks
:
bpf_text
=
bpf_text
.
replace
(
'STORAGE'
,
'BPF_HISTOGRAM(dist, disk_key_t);'
)
bpf_text
=
bpf_text
.
replace
(
'STORE'
,
'disk_key_t key = {.slot = bpf_log2l(delta)}; '
+
'bpf_probe_read(&key.disk, sizeof(key.disk), '
+
'req->rq_disk->disk_name); dist.increment(key);'
)
bpf_text
=
bpf_text
.
replace
(
'STORAGE'
,
'BPF_HISTOGRAM(dist, disk_key_t);'
)
bpf_text
=
bpf_text
.
replace
(
'STORE'
,
'disk_key_t key = {.slot = bpf_log2l(delta)}; '
+
'bpf_probe_read(&key.disk, sizeof(key.disk), '
+
'req->rq_disk->disk_name); dist.increment(key);'
)
else
:
bpf_text
=
bpf_text
.
replace
(
'STORAGE'
,
'BPF_HISTOGRAM(dist);'
)
bpf_text
=
bpf_text
.
replace
(
'STORE'
,
'dist.increment(bpf_log2l(delta));'
)
bpf_text
=
bpf_text
.
replace
(
'STORAGE'
,
'BPF_HISTOGRAM(dist);'
)
bpf_text
=
bpf_text
.
replace
(
'STORE'
,
'dist.increment(bpf_log2l(delta));'
)
if
debug
:
print
(
bpf_text
)
print
(
bpf_text
)
# load BPF program
b
=
BPF
(
text
=
bpf_text
)
if
args
.
queued
:
b
.
attach_kprobe
(
event
=
"blk_account_io_start"
,
fn_name
=
"trace_req_start"
)
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_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"
)
...
...
@@ -121,18 +122,18 @@ print("Tracing block device I/O... Hit Ctrl-C to end.")
exiting
=
0
if
args
.
interval
else
1
dist
=
b
.
get_table
(
"dist"
)
while
(
1
):
try
:
sleep
(
int
(
args
.
interval
))
except
KeyboardInterrupt
:
exiting
=
1
try
:
sleep
(
int
(
args
.
interval
))
except
KeyboardInterrupt
:
exiting
=
1
print
()
if
args
.
timestamp
:
print
(
"%-8s
\
n
"
%
strftime
(
"%H:%M:%S"
),
end
=
""
)
print
()
if
args
.
timestamp
:
print
(
"%-8s
\
n
"
%
strftime
(
"%H:%M:%S"
),
end
=
""
)
dist
.
print_log2_hist
(
label
,
"disk"
)
dist
.
clear
()
dist
.
print_log2_hist
(
label
,
"disk"
)
dist
.
clear
()
countdown
-=
1
if
exiting
or
countdown
==
0
:
exit
()
countdown
-=
1
if
exiting
or
countdown
==
0
:
exit
()
tools/biosnoop
View file @
a0aa7f28
#!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
#
# biosnoop
Trace block device I/O and print details including issuing PID.
#
For Linux, uses BCC, eBPF.
# biosnoop
Trace block device I/O and print details including issuing PID.
#
For Linux, uses BCC, eBPF.
#
# This uses in-kernel eBPF maps to cache process details (PID and comm) by I/O
# request, as well as a starting timestamp for calculating I/O latency.
...
...
@@ -9,7 +10,7 @@
# Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License")
#
# 16-Sep-2015
Brendan Gregg
Created this.
# 16-Sep-2015
Brendan Gregg
Created this.
from
__future__
import
print_function
from
bcc
import
BPF
...
...
@@ -20,7 +21,7 @@ b = BPF(text="""
#include <linux/blkdev.h>
struct val_t {
char name[TASK_COMM_LEN];
char name[TASK_COMM_LEN];
};
BPF_HASH(start, struct request *);
...
...
@@ -30,74 +31,74 @@ BPF_HASH(commbyreq, struct request *, struct val_t);
// cache PID and comm by-req
int trace_pid_start(struct pt_regs *ctx, struct request *req)
{
u32 pid;
struct val_t val = {};
u32 pid;
struct val_t val = {};
pid = bpf_get_current_pid_tgid();
pidbyreq.update(&req, &pid);
if (bpf_get_current_comm(&val.name, sizeof(val.name)) == 0) {
commbyreq.update(&req, &val);
}
pid = bpf_get_current_pid_tgid();
pidbyreq.update(&req, &pid);
if (bpf_get_current_comm(&val.name, sizeof(val.name)) == 0) {
commbyreq.update(&req, &val);
}
return 0;
return 0;
}
// time block I/O
int trace_req_start(struct pt_regs *ctx, struct request *req)
{
u64 ts;
u64 ts;
ts = bpf_ktime_get_ns();
start.update(&req, &ts);
ts = bpf_ktime_get_ns();
start.update(&req, &ts);
return 0;
return 0;
}
// output
int trace_req_completion(struct pt_regs *ctx, struct request *req)
{
u64 *tsp, delta;
u32 *pidp = 0;
struct val_t *valp;
// fetch timestamp and calculate delta
tsp = start.lookup(&req);
if (tsp == 0) {
// missed tracing issue
return 0;
}
delta = bpf_ktime_get_ns() - *tsp;
//
// Fetch and output issuing pid and comm.
// As bpf_trace_prink() is limited to a maximum of 1 string and 2
// integers, we'll use more than one to output the data.
//
valp = commbyreq.lookup(&req);
pidp = pidbyreq.lookup(&req);
if (pidp == 0 || valp == 0) {
bpf_trace_printk("0 0 ? %d
\
\
n", req->__data_len);
} else {
bpf_trace_printk("0 %d %s %d
\
\
n", *pidp, valp->name,
req->__data_len);
}
// output remaining details
if (req->cmd_flags & REQ_WRITE) {
bpf_trace_printk("1 W %s %d %d ?
\
\
n", req->rq_disk->disk_name,
req->__sector, delta / 1000);
} else {
bpf_trace_printk("1 R %s %d %d ?
\
\
n", req->rq_disk->disk_name,
req->__sector, delta / 1000);
}
start.delete(&req);
pidbyreq.delete(&req);
commbyreq.delete(&req);
return 0;
u64 *tsp, delta;
u32 *pidp = 0;
struct val_t *valp;
// fetch timestamp and calculate delta
tsp = start.lookup(&req);
if (tsp == 0) {
// missed tracing issue
return 0;
}
delta = bpf_ktime_get_ns() - *tsp;
//
// Fetch and output issuing pid and comm.
// As bpf_trace_prink() is limited to a maximum of 1 string and 2
// integers, we'll use more than one to output the data.
//
valp = commbyreq.lookup(&req);
pidp = pidbyreq.lookup(&req);
if (pidp == 0 || valp == 0) {
bpf_trace_printk("0 0 ? %d
\
\
n", req->__data_len);
} else {
bpf_trace_printk("0 %d %s %d
\
\
n", *pidp, valp->name,
req->__data_len);
}
// output remaining details
if (req->cmd_flags & REQ_WRITE) {
bpf_trace_printk("1 W %s %d %d ?
\
\
n", req->rq_disk->disk_name,
req->__sector, delta / 1000);
} else {
bpf_trace_printk("1 R %s %d %d ?
\
\
n", req->rq_disk->disk_name,
req->__sector, delta / 1000);
}
start.delete(&req);
pidbyreq.delete(&req);
commbyreq.delete(&req);
return 0;
}
"""
)
"""
,
debug
=
0
)
b
.
attach_kprobe
(
event
=
"blk_account_io_start"
,
fn_name
=
"trace_pid_start"
)
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"
)
...
...
@@ -112,21 +113,21 @@ start_ts = 0
# format output
while
1
:
(
task
,
pid
,
cpu
,
flags
,
ts
,
msg
)
=
b
.
trace_fields
()
args
=
msg
.
split
(
" "
)
(
task
,
pid
,
cpu
,
flags
,
ts
,
msg
)
=
b
.
trace_fields
()
args
=
msg
.
split
(
" "
)
if
start_ts
==
0
:
start_ts
=
ts
if
start_ts
==
0
:
start_ts
=
ts
if
args
[
0
]
==
"0"
:
(
real_pid
,
real_comm
,
bytes_s
)
=
(
args
[
1
],
args
[
2
],
args
[
3
])
continue
else
:
(
type_s
,
disk_s
,
sector_s
,
us_s
)
=
(
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
])
if
args
[
0
]
==
"0"
:
(
real_pid
,
real_comm
,
bytes_s
)
=
(
args
[
1
],
args
[
2
],
args
[
3
])
continue
else
:
(
type_s
,
disk_s
,
sector_s
,
us_s
)
=
(
args
[
1
],
args
[
2
],
args
[
3
],
args
[
4
])
ms
=
float
(
int
(
us_s
,
10
))
/
1000
ms
=
float
(
int
(
us_s
,
10
))
/
1000
print
(
"%-14.9f %-14.14s %-6s %-7s %-2s %-9s %-7s %7.2f"
%
(
ts
-
start_ts
,
real_comm
,
real_pid
,
disk_s
,
type_s
,
sector_s
,
bytes_s
,
ms
))
print
(
"%-14.9f %-14.14s %-6s %-7s %-2s %-9s %-7s %7.2f"
%
(
ts
-
start_ts
,
real_comm
,
real_pid
,
disk_s
,
type_s
,
sector_s
,
bytes_s
,
ms
))
tools/biosnoop_example.txt
View file @
a0aa7f28
...
...
@@ -36,11 +36,11 @@ $ iostat -x 1
avg-cpu: %user %nice %system %iowait %steal %idle
0.12 0.00 0.12 0.00 0.00 99.75
Device:
rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_
await svctm %util
xvda
0.00 0.00 0.00 4.00 0.00 16.00 8.00 0.00 0.00 0.00
0.00 0.00 0.00
xvdb
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00
xvdc
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00
md0
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00
Device:
rrqm/s wrqm/s r/s w/s rkB/s wkB/s
await svctm %util
xvda
0.00 0.00 0.00 4.00 0.00 16.00
0.00 0.00 0.00
xvdb
0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00
xvdc
0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00
md0
0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00
There are 4 write IOPS.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment