Add -d (duration) option to argdist, funclatency and syscount (#1768)
* Add -d (duration) option to argdist, funclatency and syscount
* Add -d option to man pages and _example.txt
diff --git a/man/man8/argdist.8 b/man/man8/argdist.8
index b0a539f..4116cd4 100644
--- a/man/man8/argdist.8
+++ b/man/man8/argdist.8
@@ -2,7 +2,7 @@
.SH NAME
argdist \- Trace a function and display a histogram or frequency count of its parameter values. Uses Linux eBPF/bcc.
.SH SYNOPSIS
-.B argdist [-h] [-p PID] [-z STRING_SIZE] [-i INTERVAL] [-n COUNT] [-v] [-T TOP] [-H specifier] [-C specifier] [-I header]
+.B argdist [-h] [-p PID] [-z STRING_SIZE] [-i INTERVAL] [-d DURATION] [-n COUNT] [-v] [-T TOP] [-H specifier] [-C specifier] [-I header]
.SH DESCRIPTION
argdist attaches to function entry and exit points, collects specified parameter
values, and stores them in a histogram or a frequency collection that counts
@@ -27,6 +27,9 @@
\-i INTERVAL
Print the collected data every INTERVAL seconds. The default is 1 second.
.TP
+\-d DURATION
+Total duration of trace in seconds.
+.TP
\-n NUMBER
Print the collected data COUNT times and then exit.
.TP
diff --git a/man/man8/funclatency.8 b/man/man8/funclatency.8
index 7b7771b..b82626c 100644
--- a/man/man8/funclatency.8
+++ b/man/man8/funclatency.8
@@ -2,7 +2,7 @@
.SH NAME
funclatency \- Time functions and print latency as a histogram.
.SH SYNOPSIS
-.B funclatency [\-h] [\-p PID] [\-i INTERVAL] [\-T] [\-u] [\-m] [\-F] [\-r] [\-v] pattern
+.B funclatency [\-h] [\-p PID] [\-i INTERVAL] [\-d DURATION] [\-T] [\-u] [\-m] [\-F] [\-r] [\-v] pattern
.SH DESCRIPTION
This tool traces function calls and times their duration (latency), and
shows the latency distribution as a histogram. The time is measured from when
@@ -37,6 +37,9 @@
\-i INTERVAL
Print output every interval seconds.
.TP
+\-d DURATION
+Total duration of trace, in seconds.
+.TP
\-T
Include timestamps on output.
.TP
@@ -72,6 +75,10 @@
#
.B funclatency \-m do_nanosleep
.TP
+Time libc open(), and print output every 2 seconds, for duration 10 seconds:
+#
+.B funclatency \-i 2 -d 10 c:read
+.TP
Time vfs_read(), and print output every 5 seconds, with timestamps:
#
.B funclatency \-mTi 5 vfs_read
diff --git a/man/man8/syscount.8 b/man/man8/syscount.8
index 2a47240..d13793b 100644
--- a/man/man8/syscount.8
+++ b/man/man8/syscount.8
@@ -2,7 +2,7 @@
.SH NAME
syscount \- Summarize syscall counts and latencies.
.SH SYNOPSIS
-.B syscount [-h] [-p PID] [-i INTERVAL] [-T TOP] [-x] [-e ERRNO] [-L] [-m] [-P] [-l]
+.B syscount [-h] [-p PID] [-i INTERVAL] [-d DURATION] [-T TOP] [-x] [-e ERRNO] [-L] [-m] [-P] [-l]
.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
@@ -23,6 +23,9 @@
\-i INTERVAL
Print the summary at the specified interval (in seconds).
.TP
+\-d DURATION
+Total duration of trace (in seconds).
+.TP
\-T TOP
Print only this many entries. Default: 10.
.TP
diff --git a/tools/argdist.py b/tools/argdist.py
index 9724073..dfb06b4 100755
--- a/tools/argdist.py
+++ b/tools/argdist.py
@@ -610,7 +610,9 @@
type=int,
help="maximum string size to read from char* arguments")
parser.add_argument("-i", "--interval", default=1, type=int,
- help="output interval, in seconds")
+ help="output interval, in seconds (default 1 second)")
+ parser.add_argument("-d", "--duration", type=int,
+ help="total duration of trace, in seconds")
parser.add_argument("-n", "--number", type=int, dest="count",
help="number of outputs")
parser.add_argument("-v", "--verbose", action="store_true",
@@ -684,9 +686,11 @@
def _main_loop(self):
count_so_far = 0
+ seconds = 0
while True:
try:
sleep(self.args.interval)
+ seconds += self.args.interval
except KeyboardInterrupt:
exit()
print("[%s]" % strftime("%H:%M:%S"))
@@ -696,6 +700,9 @@
if self.args.count is not None and \
count_so_far >= self.args.count:
exit()
+ if self.args.duration and \
+ seconds >= self.args.duration:
+ exit()
def run(self):
try:
diff --git a/tools/argdist_example.txt b/tools/argdist_example.txt
index dec9e6f..7098e56 100644
--- a/tools/argdist_example.txt
+++ b/tools/argdist_example.txt
@@ -348,7 +348,9 @@
-z STRING_SIZE, --string-size STRING_SIZE
maximum string size to read from char* arguments
-i INTERVAL, --interval INTERVAL
- output interval, in seconds
+ output interval, in seconds (default 1 second)
+ -d DURATION, --duration DURATION
+ total duration of trace, in seconds
-n COUNT, --number COUNT
number of outputs
-v, --verbose print resulting BPF program code before executing
diff --git a/tools/funclatency.py b/tools/funclatency.py
index fe06d1b..3f08a7e 100755
--- a/tools/funclatency.py
+++ b/tools/funclatency.py
@@ -35,6 +35,7 @@
./funclatency c:read # time the read() C library function
./funclatency -u vfs_read # time vfs_read(), in microseconds
./funclatency -m do_nanosleep # time do_nanosleep(), in milliseconds
+ ./funclatency -i 2 -d 10 c:open # output every 2 seconds, for duration 10s
./funclatency -mTi 5 vfs_read # output every 5 seconds, with timestamps
./funclatency -p 181 vfs_read # time process 181 only
./funclatency 'vfs_fstat*' # time both vfs_fstat() and vfs_fstatat()
@@ -47,8 +48,10 @@
epilog=examples)
parser.add_argument("-p", "--pid", type=int,
help="trace this PID only")
-parser.add_argument("-i", "--interval", default=99999999,
- help="summary interval, seconds")
+parser.add_argument("-i", "--interval", type=int,
+ help="summary interval, in seconds")
+parser.add_argument("-d", "--duration", type=int,
+ help="total duration of trace, in seconds")
parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output")
parser.add_argument("-u", "--microseconds", action="store_true",
@@ -66,6 +69,10 @@
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()
+if args.duration and not args.interval:
+ args.interval = args.duration
+if not args.interval:
+ args.interval = 99999999
def bail(error):
print("Error: " + error)
@@ -226,14 +233,18 @@
return "%s [%d]" % (BPF.sym(key[0], key[1]), key[1])
exiting = 0 if args.interval else 1
+seconds = 0
dist = b.get_table("dist")
while (1):
try:
- sleep(int(args.interval))
+ sleep(args.interval)
+ seconds += args.interval
except KeyboardInterrupt:
exiting = 1
# as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, signal_ignore)
+ if args.duration and seconds >= args.duration:
+ exiting = 1
print()
if args.timestamp:
diff --git a/tools/funclatency_example.txt b/tools/funclatency_example.txt
index ee63a5b..d8217a2 100644
--- a/tools/funclatency_example.txt
+++ b/tools/funclatency_example.txt
@@ -343,7 +343,9 @@
-h, --help show this help message and exit
-p PID, --pid PID trace this PID only
-i INTERVAL, --interval INTERVAL
- summary interval, seconds
+ summary interval, in seconds
+ -d DURATION, --duration DURATION
+ total duration of trace, in seconds
-T, --timestamp include timestamp on output
-u, --microseconds microsecond histogram
-m, --milliseconds millisecond histogram
@@ -357,6 +359,7 @@
./funclatency c:read # time the read() C library function
./funclatency -u vfs_read # time vfs_read(), in microseconds
./funclatency -m do_nanosleep # time do_nanosleep(), in milliseconds
+ ./funclatency -i 2 -d 10 c:open # output every 2 seconds, for duration 10s
./funclatency -mTi 5 vfs_read # output every 5 seconds, with timestamps
./funclatency -p 181 vfs_read # time process 181 only
./funclatency 'vfs_fstat*' # time both vfs_fstat() and vfs_fstatat()
diff --git a/tools/syscount.py b/tools/syscount.py
index e219e91..a23abde 100755
--- a/tools/syscount.py
+++ b/tools/syscount.py
@@ -17,6 +17,7 @@
import itertools
import subprocess
import sys
+import signal
import platform
if sys.version_info.major < 3:
@@ -370,6 +371,9 @@
else:
raise Exception("ausyscall: command not found")
+# signal handler
+def signal_ignore(signal, frame):
+ print()
def handle_errno(errstr):
try:
@@ -388,6 +392,8 @@
parser.add_argument("-p", "--pid", type=int, help="trace only this pid")
parser.add_argument("-i", "--interval", type=int,
help="print summary at this interval (seconds)")
+parser.add_argument("-d", "--duration", type=int,
+ help="total duration of trace, in seconds")
parser.add_argument("-T", "--top", type=int, default=10,
help="print only the top syscalls by count or latency")
parser.add_argument("-x", "--failures", action="store_true",
@@ -405,6 +411,10 @@
parser.add_argument("--ebpf", action="store_true",
help=argparse.SUPPRESS)
args = parser.parse_args()
+if args.duration and not args.interval:
+ args.interval = args.duration
+if not args.interval:
+ args.interval = 99999999
if args.list:
for grp in izip_longest(*(iter(sorted(syscalls.values())),) * 4):
@@ -545,11 +555,20 @@
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:
try:
- sleep(args.interval or 999999999)
- print_stats()
+ sleep(args.interval)
+ seconds += args.interval
except KeyboardInterrupt:
- if not args.interval:
- print_stats()
- break
+ exiting = 1
+ signal.signal(signal.SIGINT, signal_ignore)
+ if args.duration and seconds >= args.duration:
+ exiting = 1
+
+ print_stats()
+
+ if exiting:
+ print("Detaching...")
+ exit()
diff --git a/tools/syscount_example.txt b/tools/syscount_example.txt
index be6d3e6..aad51c4 100644
--- a/tools/syscount_example.txt
+++ b/tools/syscount_example.txt
@@ -151,6 +151,8 @@
-p PID, --pid PID trace only this pid
-i INTERVAL, --interval INTERVAL
print summary at this interval (seconds)
+ -d DURATION, --duration DURATION
+ total duration of trace, in seconds
-T TOP, --top TOP print only the top syscalls by count or latency
-x, --failures trace only failed syscalls (return < 0)
-e ERRNO, --errno ERRNO