Skip to content

Commit

Permalink
tools/syscount: Add syscall filter support (iovisor#4132)
Browse files Browse the repository at this point in the history
Sometimes, I'd only care about a single syscall rather than all syscalls. Use the --syscall option for this.

# syscount -i 1 -p $(pgrep -nx mysqld) --syscall fsync -L

Tracing syscall 'fsync'... Ctrl+C to quit.
[13:02:24]
SYSCALL                   COUNT        TIME (us)
fsync                       956      2448760.979

[13:02:25]
SYSCALL                   COUNT        TIME (us)
fsync                       979      2387591.025

[13:02:26]
SYSCALL                   COUNT        TIME (us)
fsync                       845      2488404.454
  • Loading branch information
xingfeng2510 committed Jul 29, 2022
1 parent 4a60443 commit 8528919
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 6 deletions.
7 changes: 5 additions & 2 deletions man/man8/syscount.8
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.SH NAME
syscount \- Summarize syscall counts and latencies.
.SH SYNOPSIS
.B syscount [-h] [-p PID] [-t TID] [-i INTERVAL] [-d DURATION] [-T TOP] [-x] [-e ERRNO] [-L] [-m] [-P] [-l]
.B syscount [-h] [-p PID] [-t TID] [-i INTERVAL] [-d DURATION] [-T TOP] [-x] [-e ERRNO] [-L] [-m] [-P] [-l] [--syscall SYSCALL]
.SH DESCRIPTION
This tool traces syscall entry and exit tracepoints and summarizes either the
number of syscalls of each type, or the number of syscalls per process. It can
Expand Down Expand Up @@ -48,6 +48,9 @@ Summarize by process and not by syscall.
List the syscalls recognized by the tool (hard-coded list). Syscalls beyond this
list will still be displayed, as "[unknown: nnn]" where nnn is the syscall
number.
.TP
\--syscall SYSCALL
Trace this syscall only (use option -l to get all recognized syscalls).
.SH EXAMPLES
.TP
Summarize all syscalls by syscall:
Expand Down Expand Up @@ -108,6 +111,6 @@ Linux
.SH STABILITY
Unstable - in development.
.SH AUTHOR
Sasha Goldshtein
Sasha Goldshtein, Rocky Xing
.SH SEE ALSO
funccount(8), ucalls(8), argdist(8), trace(8), funclatency(8)
36 changes: 33 additions & 3 deletions tools/syscount.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
# syscount Summarize syscall counts and latencies.
#
# USAGE: syscount [-h] [-p PID] [-t TID] [-i INTERVAL] [-d DURATION] [-T TOP]
# [-x] [-e ERRNO] [-L] [-m] [-P] [-l]
# [-x] [-e ERRNO] [-L] [-m] [-P] [-l] [--syscall SYSCALL]
#
# Copyright 2017, Sasha Goldshtein.
# Licensed under the Apache License, Version 2.0 (the "License")
#
# 15-Feb-2017 Sasha Goldshtein Created this.
# 16-May-2022 Rocky Xing Added TID filter support.
# 26-Jul-2022 Rocky Xing Added syscall filter support.

from time import sleep, strftime
import argparse
Expand Down Expand Up @@ -66,6 +67,8 @@ def handle_errno(errstr):
help="count by process and not by syscall")
parser.add_argument("-l", "--list", action="store_true",
help="print list of recognized syscalls and exit")
parser.add_argument("--syscall", type=str,
help="trace this syscall only (use option -l to get all recognized syscalls)")
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()
Expand All @@ -74,6 +77,17 @@ def handle_errno(errstr):
if not args.interval:
args.interval = 99999999

syscall_nr = -1
if args.syscall is not None:
syscall = bytes(args.syscall, 'utf-8')
for key, value in syscalls.items():
if syscall == value:
syscall_nr = key
break
if syscall_nr == -1:
print("Error: syscall '%s' not found. Exiting." % args.syscall)
sys.exit(1)

if args.list:
for grp in izip_longest(*(iter(sorted(syscalls.values())),) * 4):
print(" ".join(["%-22s" % s.decode() for s in grp if s is not None]))
Expand All @@ -98,6 +112,11 @@ def handle_errno(errstr):
u32 pid = pid_tgid >> 32;
u32 tid = (u32)pid_tgid;
#ifdef FILTER_SYSCALL_NR
if (args->id != FILTER_SYSCALL_NR)
return 0;
#endif
#ifdef FILTER_PID
if (pid != FILTER_PID)
return 0;
Expand All @@ -119,6 +138,11 @@ def handle_errno(errstr):
u32 pid = pid_tgid >> 32;
u32 tid = (u32)pid_tgid;
#ifdef FILTER_SYSCALL_NR
if (args->id != FILTER_SYSCALL_NR)
return 0;
#endif
#ifdef FILTER_PID
if (pid != FILTER_PID)
return 0;
Expand Down Expand Up @@ -179,6 +203,8 @@ def handle_errno(errstr):
text = "#define LATENCY\n" + text
if args.process:
text = "#define BY_PROCESS\n" + text
if args.syscall is not None:
text = ("#define FILTER_SYSCALL_NR %d\n" % syscall_nr) + text
if args.ebpf:
print(text)
exit()
Expand Down Expand Up @@ -231,8 +257,12 @@ def print_latency_stats():
print("")
data.clear()

print("Tracing %ssyscalls, printing top %d... Ctrl+C to quit." %
("failed " if args.failures else "", args.top))
if args.syscall is not None:
print("Tracing %ssyscall '%s'... Ctrl+C to quit." %
("failed " if args.failures else "", args.syscall))
else:
print("Tracing %ssyscalls, printing top %d... Ctrl+C to quit." %
("failed " if args.failures else "", args.top))
exiting = 0 if args.interval else 1
seconds = 0
while True:
Expand Down
19 changes: 18 additions & 1 deletion tools/syscount_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,25 @@ unlink 1
rmdir 1
^C

Sometimes, you'd only care about a single syscall rather than all syscalls.
Use the --syscall option for this; the following example also demonstrates
the --syscall option, for printing at predefined intervals:

# syscount --syscall stat -i 1
Tracing syscall 'stat'... Ctrl+C to quit.
[12:51:06]
SYSCALL COUNT
stat 310

[12:51:07]
SYSCALL COUNT
stat 316
^C

USAGE:
# syscount -h
usage: syscount.py [-h] [-p PID] [-t TID] [-i INTERVAL] [-d DURATION] [-T TOP]
[-x] [-e ERRNO] [-L] [-m] [-P] [-l]
[-x] [-e ERRNO] [-L] [-m] [-P] [-l] [--syscall SYSCALL]

Summarize syscall counts and latencies.

Expand All @@ -164,3 +179,5 @@ optional arguments:
microseconds)
-P, --process count by process and not by syscall
-l, --list print list of recognized syscalls and exit
--syscall SYSCALL trace this syscall only (use option -l to get all
recognized syscalls)

0 comments on commit 8528919

Please sign in to comment.