Skip to content

Commit

Permalink
Add support for multiple PID/TID for offwaketime (#2951)
Browse files Browse the repository at this point in the history
Instead of filtering on a single process allow up to 5 pid/tgid to be
used for filtering. The limit of 5 is arbitrary and can be increased
should the need arise. Also remove unnecessary thread_context variable.

Co-authored-by: Nikolay Borisov <nborisov@suse.com>
  • Loading branch information
lorddoskias and lorddoskias committed Jun 8, 2020
1 parent 0bcf238 commit 263411b
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 18 deletions.
6 changes: 4 additions & 2 deletions man/man8/offwaketime.8
Expand Up @@ -36,10 +36,12 @@ Print usage message.
Print output in folded stack format.
.TP
\-p PID
Trace this process ID only (filtered in-kernel).
Trace this process ID only (filtered in-kernel). Can be a comma separated list
of PIDS.
.TP
\-t TID
Trace this thread ID only (filtered in-kernel).
Trace this thread ID only (filtered in-kernel). Can be a comma separated list
of TIDS.
.TP
\-u
Only trace user threads (no kernel threads).
Expand Down
44 changes: 30 additions & 14 deletions tools/offwaketime.py
Expand Up @@ -20,6 +20,16 @@

# arg validation
def positive_int(val):
dest = []
# Filter up to 5 pids, arbitrary
args_list = val.split(",", 5)
pids_to_add = min(len(args_list), 5)
for i in range(pids_to_add):
dest.append(_positive_int(args_list[i]))

return dest

def _positive_int(val):
try:
ival = int(val)
except ValueError:
Expand All @@ -30,11 +40,21 @@ def positive_int(val):
return ival

def positive_nonzero_int(val):
ival = positive_int(val)
ival = _positive_int(val)
if ival == 0:
raise argparse.ArgumentTypeError("must be nonzero")
return ival

def build_filter(filter_name, values):
filter_string = "((%s == %d)" % (filter_name, values[0])

for val in values[1:]:
filter_string += " || (%s == %d )" % (filter_name , val)

filter_string += ")"

return filter_string

def stack_id_err(stack_id):
# -EFAULT in get_stackid normally means the stack-trace is not available,
# Such as getting kernel stack trace in userspace code
Expand All @@ -61,10 +81,12 @@ 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="PIDS", dest="tgid",
type=positive_int,
help="trace these PIDS only. Can be a comma separated list of PIDS.")
thread_group.add_argument("-t", "--tid", metavar="TIDS", dest="pid",
type=positive_int,
help="trace these TIDS only. Can be a comma separated list of TIDS.")
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 @@ -93,7 +115,7 @@ def stack_id_err(stack_id):
type=positive_nonzero_int,
help="the amount of time in microseconds under which we " +
"store traces (default U64_MAX)")
parser.add_argument("--state", type=positive_int,
parser.add_argument("--state", type=_positive_int,
help="filter on this thread state bitmask (eg, 2 == TASK_UNINTERRUPTIBLE" +
") see include/linux/sched.h")
parser.add_argument("--ebpf", action="store_true",
Expand Down Expand Up @@ -221,21 +243,15 @@ 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
thread_filter = build_filter("tgid", args.tgid)
elif args.pid is not None:
thread_context = "TID %d" % args.pid
thread_filter = 'pid == %d' % args.pid
thread_filter = build_filter("pid", args.pid)
elif args.user_threads_only:
thread_context = "user threads"
thread_filter = '!(p->flags & PF_KTHREAD)'
elif args.kernel_threads_only:
thread_context = "kernel threads"
thread_filter = 'p->flags & PF_KTHREAD'
else:
thread_context = "all threads"
thread_filter = '1'
if args.state == 0:
state_filter = 'p->state == 0'
Expand Down
6 changes: 4 additions & 2 deletions tools/offwaketime_example.txt
Expand Up @@ -317,8 +317,10 @@ positional arguments:

optional arguments:
-h, --help show this help message and exit
-p PID, --pid PID trace this PID only
-t TID, --tid TID trace this TID only
-p PID, --pid PID trace these PIDS only. Can be a comma separated list of
PID.
-t TID, --tid TID trace these TIDS only. Can be a comma separated list of
TIDS.
-u, --user-threads-only
user threads only (no kernel threads)
-k, --kernel-threads-only
Expand Down

0 comments on commit 263411b

Please sign in to comment.