Skip to content

Commit

Permalink
tools/profile: add -L option to support filtering on TID (iovisor#2315)
Browse files Browse the repository at this point in the history
tools/profile already supports "-p PID" to filter on PID (tgid in kernel).
Now add "-L TID" to profile thread with this TID only (pid in kernel).
  • Loading branch information
boat0 authored and yonghong-song committed Apr 15, 2019
1 parent 2a9436d commit 6b19790
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 16 deletions.
14 changes: 10 additions & 4 deletions man/man8/profile.8
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.SH NAME
profile \- Profile CPU usage by sampling stack traces. Uses Linux eBPF/bcc.
.SH SYNOPSIS
.B profile [\-adfh] [\-p PID] [\-U | \-K] [\-F FREQUENCY | \-c COUNT]
.B profile [\-adfh] [\-p PID | \-L TID] [\-U | \-K] [\-F FREQUENCY | \-c COUNT]
.B [\-\-stack\-storage\-size COUNT] [duration]
.SH DESCRIPTION
This is a CPU profiler. It works by taking samples of stack traces at timed
Expand All @@ -28,8 +28,10 @@ for an older version that may work on Linux 4.6 - 4.8.
Print usage message.
.TP
\-p PID
Trace this process ID only (filtered in-kernel). Without this, all CPUs are
profiled.
Trace this process ID only (filtered in-kernel).
.TP
\-L TID
Trace this thread ID only (filtered in-kernel).
.TP
\-F frequency
Frequency to sample stacks.
Expand Down Expand Up @@ -80,10 +82,14 @@ Profile 1 in a million events for 5 seconds only:
#
.B profile -c 1000000 5
.TP
Profile PID 181 only:
Profile process with PID 181 only:
#
.B profile -p 181
.TP
Profile thread with TID 181 only:
#
.B profile -L 181
.TP
Profile for 5 seconds and output in folded stack format (suitable as input for flame graphs), including a delimiter between kernel and user stacks:
#
.B profile -df 5
Expand Down
24 changes: 15 additions & 9 deletions tools/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import signal
import os
import errno
import multiprocessing

#
# Process Arguments
Expand Down Expand Up @@ -69,7 +68,8 @@ def stack_id_err(stack_id):
./profile -c 1000000 # profile stack traces every 1 in a million events
./profile 5 # profile at 49 Hertz for 5 seconds only
./profile -f 5 # output in folded format for flame graphs
./profile -p 185 # only profile threads for PID 185
./profile -p 185 # only profile process with PID 185
./profile -L 185 # only profile thread with TID 185
./profile -U # only show user space stacks (no kernel)
./profile -K # only show kernel space stacks (no user)
"""
Expand All @@ -79,7 +79,9 @@ def stack_id_err(stack_id):
epilog=examples)
thread_group = parser.add_mutually_exclusive_group()
thread_group.add_argument("-p", "--pid", type=positive_int,
help="profile this PID only")
help="profile process with this PID only")
thread_group.add_argument("-L", "--tid", type=positive_int,
help="profile thread with this TID only")
# TODO: add options for user/kernel threads only
stack_group = parser.add_mutually_exclusive_group()
stack_group.add_argument("-U", "--user-stacks-only", action="store_true",
Expand Down Expand Up @@ -144,15 +146,18 @@ def stack_id_err(stack_id):
// This code gets a bit complex. Probably not suitable for casual hacking.
int do_perf_event(struct bpf_perf_event_data *ctx) {
u32 pid = bpf_get_current_pid_tgid() >> 32;
u64 id = bpf_get_current_pid_tgid();
u32 tgid = id >> 32;
u32 pid = id;
if (IDLE_FILTER)
return 0;
if (!(THREAD_FILTER))
return 0;
// create map key
struct key_t key = {.pid = pid};
struct key_t key = {.pid = tgid};
bpf_get_current_comm(&key.name, sizeof(key.name));
// get stacks
Expand Down Expand Up @@ -197,13 +202,14 @@ def stack_id_err(stack_id):
idle_filter = "0"
bpf_text = bpf_text.replace('IDLE_FILTER', idle_filter)

# set thread filter
# set process/thread filter
thread_context = ""
perf_filter = "-a"
if args.pid is not None:
thread_context = "PID %s" % args.pid
thread_filter = 'pid == %s' % args.pid
perf_filter = '-p %s' % args.pid
thread_filter = 'tgid == %s' % args.pid
elif args.tid is not None:
thread_context = "TID %s" % args.tid
thread_filter = 'pid == %s' % args.tid
else:
thread_context = "all threads"
thread_filter = '1'
Expand Down
8 changes: 5 additions & 3 deletions tools/profile_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ Run ./profile -h to see the default.
USAGE message:

# ./profile -h
usage: profile.py [-h] [-p PID] [-U | -K] [-F FREQUENCY | -c COUNT] [-d] [-a]
usage: profile.py [-h] [-p PID | -L TID] [-U | -K] [-F FREQUENCY | -c COUNT] [-d] [-a]
[-I] [-f] [--stack-storage-size STACK_STORAGE_SIZE] [-C CPU]
[duration]

Expand All @@ -718,7 +718,8 @@ positional arguments:

optional arguments:
-h, --help show this help message and exit
-p PID, --pid PID profile this PID only
-p PID, --pid PID profile process with this PID only
-L TID, --tid TID profile thread with this TID only
-U, --user-stacks-only
show stacks from user space only (no kernel space
stacks)
Expand All @@ -745,6 +746,7 @@ examples:
./profile -c 1000000 # profile stack traces every 1 in a million events
./profile 5 # profile at 49 Hertz for 5 seconds only
./profile -f 5 # output in folded format for flame graphs
./profile -p 185 # only profile threads for PID 185
./profile -p 185 # only profile process with PID 185
./profile -L 185 # only profile thread with TID 185
./profile -U # only show user space stacks (no kernel)
./profile -K # only show kernel space stacks (no user)

0 comments on commit 6b19790

Please sign in to comment.