Skip to content

Commit 74016c3

Browse files
committed
funclatency
1 parent 30abd81 commit 74016c3

4 files changed

Lines changed: 485 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Tools:
6666

6767
- tools/[biosnoop](tools/biosnoop): Trace block device I/O with PID and latency. [Examples](tools/biosnoop_example.txt).
6868
- tools/[funccount](tools/funccount): Count kernel function calls. [Examples](tools/funccount_example.txt).
69+
- tools/[funclatency](tools/funclatency): Time kernel functions and show their latency distribution. [Examples](tools/funclatency_example.txt).
6970
- tools/[killsnoop](tools/killsnoop): Trace signals issued by the kill() syscall. [Examples](tools/killsnoop_example.txt).
7071
- tools/[opensnoop](tools/opensnoop): Trace open() syscalls. [Examples](tools/opensnoop_example.txt).
7172
- tools/[pidpersec](tools/pidpersec): Count new processes (via fork). [Examples](tools/pidpersec_example.txt).

man/man8/funclatency.8

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
.TH funclatency 8 "2015-08-18" "USER COMMANDS"
2+
.SH NAME
3+
funclatency \- Time kernel funcitons and print latency as a histogram.
4+
.SH SYNOPSIS
5+
.B funclatency [\-h] [\-p PID] [\-i INTERVAL] [\-T] [\-u] [\-m] [\-r] pattern
6+
.SH DESCRIPTION
7+
This tool traces kernel function calls and times their duration (latency), and
8+
shows the latency distribution as a histogram. The time is measured from when
9+
the function is called to when it returns, and is inclusive of both on-CPU
10+
time and time spent blocked.
11+
12+
This tool uses in-kernel eBPF maps for storing timestamps and the histogram,
13+
for efficiency.
14+
15+
WARNING: This uses dynamic tracing of (what can be many) kernel functions, an
16+
activity that has had issues on some kernel versions (risk of panics or
17+
freezes). Test, and know what you are doing, before use.
18+
19+
Since this uses BPF, only the root user can use this tool.
20+
.SH REQUIREMENTS
21+
CONFIG_BPF and bcc.
22+
.SH OPTIONS
23+
pattern
24+
Function name or search pattern. Supports "*" wildcards. See EXAMPLES.
25+
You can also use \-r for regular expressions.
26+
\-h
27+
Print usage message.
28+
.TP
29+
\-p PID
30+
Trace this process ID only.
31+
.TP
32+
\-i INTERVAL
33+
Print output every interval seconds.
34+
.TP
35+
\-T
36+
Include timestamps on output.
37+
.TP
38+
\-u
39+
Output histogram in microseconds.
40+
.TP
41+
\-m
42+
Output histogram in milliseconds.
43+
.TP
44+
\-r
45+
Use regular expressions for the search pattern.
46+
.SH EXAMPLES
47+
.TP
48+
Time the do_sys_open() kernel function, and print the distribution as a histogram:
49+
#
50+
.B funclatency do_sys_open
51+
.TP
52+
Time vfs_read(), and print the histogram in units of microseconds:
53+
#
54+
.B funclatency \-u vfs_read
55+
.TP
56+
Time do_nanosleep(), and print the histogram in units of milliseconds:
57+
#
58+
.B funclatency \-m do_nanosleep
59+
.TP
60+
Time vfs_read(), and print output every 5 seconds, with timestamps:
61+
#
62+
.B funclatency \-mTi 5 vfs_read
63+
.TP
64+
Time vfs_read() for process ID 181 only:
65+
#
66+
.B funclatency \-p 181 vfs_read:
67+
.TP
68+
Time both vfs_fstat() and vfs_fstatat() calls, by use of a wildcard:
69+
#
70+
.B funclatency 'vfs_fstat*'
71+
.SH FIELDS
72+
.TP
73+
necs
74+
Nanosecond range
75+
.TP
76+
usecs
77+
Microsecond range
78+
.TP
79+
mecs
80+
Millisecond range
81+
.TP
82+
count
83+
How many calls fell into this range
84+
.TP
85+
distribution
86+
An ASCII bar chart to visualize the distribution (count column)
87+
.SH OVERHEAD
88+
This traces kernel functions and maintains in-kernel timestamps and a histgroam,
89+
which are asynchronously copied to user-space. While this method is very
90+
efficient, the rate of kernel functions can also be very high (>1M/sec), at
91+
which point the overhead is expected to be measurable. Measure in a test
92+
environment and understand overheads before use. You can also use funccount
93+
to measure the rate of kernel functions over a short duration, to set some
94+
expectations before use.
95+
.SH SOURCE
96+
This is from bcc.
97+
.IP
98+
https://github.com/iovisor/bcc
99+
.PP
100+
Also look in the bcc distribution for a companion _examples.txt file containing
101+
example usage, output, and commentary for this tool.
102+
.SH OS
103+
Linux
104+
.SH STABILITY
105+
Unstable - in development.
106+
.SH AUTHOR
107+
Brendan Gregg
108+
.SH SEE ALSO
109+
funccount(8)

tools/funclatency

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/python
2+
#
3+
# funclatency Time kernel funcitons and print latency as a histogram.
4+
# For Linux, uses BCC, eBPF.
5+
#
6+
# USAGE: funclatency [-h] [-p PID] [-i INTERVAL] [-T] [-u] [-m] [-r] pattern
7+
#
8+
# Run "funclatency -h" for full usage.
9+
#
10+
# The pattern is a string with optional '*' wildcards, similar to file globbing.
11+
# If you'd prefer to use regular expressions, use the -r option. Matching
12+
# multiple functions is of limited use, since the output has one histogram for
13+
# everything. Future versions should split the output histogram by the function.
14+
#
15+
# Copyright (c) 2015 Brendan Gregg.
16+
# Licensed under the Apache License, Version 2.0 (the "License")
17+
#
18+
# 20-Sep-2015 Brendan Gregg Created this.
19+
20+
from __future__ import print_function
21+
from bcc import BPF
22+
from time import sleep, strftime
23+
import argparse
24+
import signal
25+
26+
# arguments
27+
examples = """examples:
28+
./funclatency do_sys_open # time the do_sys_open() kenel function
29+
./funclatency -u vfs_read # time vfs_read(), in microseconds
30+
./funclatency -m do_nanosleep # time do_nanosleep(), in milliseconds
31+
./funclatency -mTi 5 vfs_read # output every 5 seconds, with timestamps
32+
./funclatency -p 181 vfs_read # time process 181 only
33+
./funclatency 'vfs_fstat*' # time both vfs_fstat() and vfs_fstatat()
34+
"""
35+
parser = argparse.ArgumentParser(
36+
description="Time kernel funcitons and print latency as a histogram",
37+
formatter_class=argparse.RawDescriptionHelpFormatter,
38+
epilog=examples)
39+
parser.add_argument("-p", "--pid",
40+
help="trace this PID only")
41+
parser.add_argument("-i", "--interval", default=99999999,
42+
help="summary interval, seconds")
43+
parser.add_argument("-T", "--timestamp", action="store_true",
44+
help="include timestamp on output")
45+
parser.add_argument("-u", "--microseconds", action="store_true",
46+
help="microsecond histogram")
47+
parser.add_argument("-m", "--milliseconds", action="store_true",
48+
help="millisecond histogram")
49+
parser.add_argument("-r", "--regexp", action="store_true",
50+
help="use regular expressions. Default is \"*\" wildcards only.")
51+
parser.add_argument("pattern",
52+
help="search expression for kernel functions")
53+
args = parser.parse_args()
54+
pattern = args.pattern
55+
if not args.regexp:
56+
pattern = pattern.replace('*', '.*')
57+
pattern = '^' + pattern + '$'
58+
debug = 0
59+
60+
# define BPF program
61+
bpf_text = """
62+
#include <uapi/linux/ptrace.h>
63+
#include <linux/blkdev.h>
64+
65+
BPF_TABLE(\"array\", int, u64, dist, 64);
66+
BPF_HASH(start, u32);
67+
68+
int trace_func_entry(struct pt_regs *ctx)
69+
{
70+
u32 pid = bpf_get_current_pid_tgid();
71+
u64 ts = bpf_ktime_get_ns();
72+
73+
FILTER
74+
start.update(&pid, &ts);
75+
76+
return 0;
77+
}
78+
79+
int trace_func_return(struct pt_regs *ctx)
80+
{
81+
u64 *tsp, delta;
82+
u32 pid = bpf_get_current_pid_tgid();
83+
84+
// calculate delta time
85+
tsp = start.lookup(&pid);
86+
if (tsp == 0) {
87+
return 0; // missed start
88+
}
89+
start.delete(&pid);
90+
delta = bpf_ktime_get_ns() - *tsp;
91+
FACTOR
92+
93+
// store as histogram
94+
int index = bpf_log2l(delta);
95+
u64 *leaf = dist.lookup(&index);
96+
if (leaf) (*leaf)++;
97+
98+
return 0;
99+
}
100+
"""
101+
if args.pid:
102+
bpf_text = bpf_text.replace('FILTER',
103+
'if (pid != %s) { return 0; }' % args.pid)
104+
else:
105+
bpf_text = bpf_text.replace('FILTER', '')
106+
if args.milliseconds:
107+
bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000000;')
108+
label = "msecs"
109+
elif args.microseconds:
110+
bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000;')
111+
label = "usecs"
112+
else:
113+
bpf_text = bpf_text.replace('FACTOR', '')
114+
label = "nsecs"
115+
if debug:
116+
print(bpf_text)
117+
118+
# signal handler
119+
def signal_ignore(signal, frame):
120+
print()
121+
122+
# load BPF program
123+
b = BPF(text=bpf_text)
124+
b.attach_kprobe(event_re=pattern, fn_name="trace_func_entry")
125+
b.attach_kretprobe(event_re=pattern, fn_name="trace_func_return")
126+
127+
# header
128+
print("Tracing %s... Hit Ctrl-C to end." % args.pattern)
129+
130+
# output
131+
exiting = 0 if args.interval else 1
132+
dist = b.get_table("dist")
133+
while (1):
134+
try:
135+
sleep(int(args.interval))
136+
except KeyboardInterrupt:
137+
exiting=1
138+
# as cleanup can take many seconds, trap Ctrl-C:
139+
signal.signal(signal.SIGINT, signal_ignore)
140+
141+
print()
142+
if args.timestamp:
143+
print("%-8s\n" % strftime("%H:%M:%S"), end="")
144+
145+
dist.print_log2_hist(label)
146+
dist.clear()
147+
148+
if exiting:
149+
print("Detaching...")
150+
exit()

0 commit comments

Comments
 (0)