Skip to content

Commit

Permalink
offcputime: Support tracking specified processes and threads
Browse files Browse the repository at this point in the history
Inspired by the perf-top command, the offcputime tool is
enhanced to support tracking multiple processes and threads.

$ man perf-top
       -p <pid>, --pid=<pid>
           Profile events on existing Process ID (comma separated list).
       -t <tid>, --tid=<tid>
           Profile events on existing thread ID (comma separated list).
Before:
$ offcputime  -h
optional arguments:
  -p PID, --pid PID     trace this PID only
  -t TID, --tid TID     trace this TID only
examples:
    ./offcputime -p 185      # only trace threads for PID 185
    ./offcputime -t 188      # only trace thread 188

After:
$ offcputime -h
optional arguments:
  -p PID, --pid PID     trace these PIDs only, comma separated list
  -t TID, --tid TID     trace these TIDs only, comma separated list
examples:
    ./offcputime -p 185,175,165 # only trace threads for PID 185,175,165
    ./offcputime -t 188,120,134 # only trace threads 188,120,134

Signed-off-by: Yingming Mao <[email protected]>
Reviewed-by: Shuo Li <[email protected]>
  • Loading branch information
Yingming Mao authored and yonghong-song committed Sep 3, 2024
1 parent 0b2b116 commit ebdd760
Showing 1 changed file with 22 additions and 12 deletions.
34 changes: 22 additions & 12 deletions tools/offcputime.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@
import signal

# arg validation
def positive_ints(val):
try:
ivals = [int(i) for i in val.split(',')]
for i in ivals:
if i < 0:
raise argparse.ArgumentTypeError("must be positive ingegers")
except ValueError:
raise argparse.ArgumentTypeError(f"must be integers")
return ivals

def positive_int(val):
try:
ival = int(val)
Expand Down Expand Up @@ -52,8 +62,8 @@ def stack_id_err(stack_id):
./offcputime -s 5 # 5 seconds, and show symbol offsets
./offcputime -m 1000 # trace only events that last more than 1000 usec
./offcputime -M 10000 # trace only events that last less than 10000 usec
./offcputime -p 185 # only trace threads for PID 185
./offcputime -t 188 # only trace thread 188
./offcputime -p 185,175,165 # only trace threads for PID 185,175,165
./offcputime -t 188,120,134 # only trace threads 188,120,134
./offcputime -u # only trace user threads (no kernel)
./offcputime -k # only trace kernel threads (no user)
./offcputime -U # only show user space stacks (no kernel)
Expand All @@ -66,10 +76,10 @@ def stack_id_err(stack_id):
thread_group = parser.add_mutually_exclusive_group()
# Note: this script provides --pid and --tid flags but their arguments are
# referred to internally using kernel nomenclature: TGID and PID.
thread_group.add_argument("-p", "--pid", metavar="PID", dest="tgid",
help="trace this PID only", type=positive_int)
thread_group.add_argument("-t", "--tid", metavar="TID", dest="pid",
help="trace this TID only", type=positive_int)
thread_group.add_argument("-p", "--pid", metavar="PID", dest="tgids",
help="trace these PIDs only, comma separated list", type=positive_ints)
thread_group.add_argument("-t", "--tid", metavar="TID", dest="pids",
help="trace these TIDs only, comma separated list", type=positive_ints)
thread_group.add_argument("-u", "--user-threads-only", action="store_true",
help="user threads only (no kernel threads)")
thread_group.add_argument("-k", "--kernel-threads-only", action="store_true",
Expand Down Expand Up @@ -200,12 +210,12 @@ def signal_ignore(signal, frame):

# set thread filter
thread_context = ""
if args.tgid is not None:
thread_context = "PID %d" % args.tgid
thread_filter = 'tgid == %d' % args.tgid
elif args.pid is not None:
thread_context = "TID %d" % args.pid
thread_filter = 'pid == %d' % args.pid
if args.tgids is not None:
thread_context = "PIDs %s" % ','.join([str(tgid) for tgid in args.tgids])
thread_filter = ' || '.join(['tgid == %d' % tgid for tgid in args.tgids])
elif args.pids is not None:
thread_context = "TIDs %s" % ','.join([str(pid) for pid in args.pids])
thread_filter = ' || '.join(['pid == %d' % pid for pid in args.pids])
elif args.user_threads_only:
thread_context = "user threads"
thread_filter = '!(prev->flags & PF_KTHREAD)'
Expand Down

0 comments on commit ebdd760

Please sign in to comment.