From 6b1979037b5fc526224c627537df34b0d7f9ed17 Mon Sep 17 00:00:00 2001 From: Xiaozhou Liu Date: Tue, 16 Apr 2019 05:41:18 +0800 Subject: [PATCH] tools/profile: add -L option to support filtering on TID (#2315) 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). --- man/man8/profile.8 | 14 ++++++++++---- tools/profile.py | 24 +++++++++++++++--------- tools/profile_example.txt | 8 +++++--- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/man/man8/profile.8 b/man/man8/profile.8 index e2b6a8438ae6..88311e7e2f0b 100644 --- a/man/man8/profile.8 +++ b/man/man8/profile.8 @@ -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 @@ -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. @@ -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 diff --git a/tools/profile.py b/tools/profile.py index 958b6323eb79..dfbced6aa841 100755 --- a/tools/profile.py +++ b/tools/profile.py @@ -34,7 +34,6 @@ import signal import os import errno -import multiprocessing # # Process Arguments @@ -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) """ @@ -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", @@ -144,7 +146,10 @@ 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; @@ -152,7 +157,7 @@ def stack_id_err(stack_id): 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 @@ -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' diff --git a/tools/profile_example.txt b/tools/profile_example.txt index 7b1cc2683751..9b1e5c2b9d83 100644 --- a/tools/profile_example.txt +++ b/tools/profile_example.txt @@ -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] @@ -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) @@ -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)