Skip to content

Commit

Permalink
funccount: add -d for duration
Browse files Browse the repository at this point in the history
  • Loading branch information
brendangregg authored and drzaeus77 committed Aug 24, 2017
1 parent 75e2f37 commit b03d9eb
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 6 deletions.
7 changes: 7 additions & 0 deletions man/man8/funccount.8
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Trace this process ID only.
\-i INTERVAL
Print output every interval seconds.
.TP
\-d DURATION
Total duration of trace in seconds.
.TP
\-T
Include timestamps on output.
.TP
Expand All @@ -49,6 +52,10 @@ Print kernel functions beginning with "vfs_", every second:
#
.B funccount \-i 1 'vfs_*'
.TP
Print kernel functions beginning with "vfs_", for ten seconds only:
#
.B funccount \-d 10 'vfs_*'
.TP
Match kernel functions beginning with "vfs_", using regular expressions:
#
.B funccount \-r '^vfs_.*'
Expand Down
17 changes: 14 additions & 3 deletions tools/funccount.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# funccount Count functions, tracepoints, and USDT probes.
# For Linux, uses BCC, eBPF.
#
# USAGE: funccount [-h] [-p PID] [-i INTERVAL] [-T] [-r] pattern
# USAGE: funccount [-h] [-p PID] [-i INTERVAL] [-d DURATION] [-T] [-r] pattern
#
# The pattern is a string with optional '*' wildcards, similar to file
# globbing. If you'd prefer to use regular expressions, use the -r option.
Expand Down Expand Up @@ -218,6 +218,7 @@ def __init__(self):
./funccount 'vfs_*' # count kernel fns starting with "vfs"
./funccount -r '^vfs.*' # same as above, using regular expressions
./funccount -Ti 5 'vfs_*' # output every 5 seconds, with timestamps
./funccount -d 10 'vfs_*' # trace for 10 seconds only
./funccount -p 185 'vfs_*' # count vfs calls for PID 181 only
./funccount t:sched:sched_fork # count calls to the sched_fork tracepoint
./funccount -p 185 u:node:gc* # count all GC USDT probes in node, PID 185
Expand All @@ -232,20 +233,26 @@ def __init__(self):
epilog=examples)
parser.add_argument("-p", "--pid", type=int,
help="trace this PID only")
parser.add_argument("-i", "--interval", default=99999999,
parser.add_argument("-i", "--interval",
help="summary interval, seconds")
parser.add_argument("-d", "--duration",
help="total duration of trace, seconds")
parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output")
parser.add_argument("-r", "--regexp", action="store_true",
help="use regular expressions. Default is \"*\" wildcards only.")
parser.add_argument("-d", "--debug", action="store_true",
parser.add_argument("-D", "--debug", action="store_true",
help="print BPF program before starting (for debugging purposes)")
parser.add_argument("pattern",
help="search expression for events")
self.args = parser.parse_args()
global debug
debug = self.args.debug
self.probe = Probe(self.args.pattern, self.args.regexp, self.args.pid)
if self.args.duration and not self.args.interval:
self.args.interval = self.args.duration
if not self.args.interval:
self.args.interval = 99999999

@staticmethod
def _signal_ignore(signal, frame):
Expand All @@ -257,13 +264,17 @@ def run(self):
print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
(self.probe.matched, self.args.pattern))
exiting = 0 if self.args.interval else 1
seconds = 0
while True:
try:
sleep(int(self.args.interval))
seconds += int(self.args.interval)
except KeyboardInterrupt:
exiting = 1
# as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, Tool._signal_ignore)
if self.args.duration and seconds >= int(self.args.duration):
exiting = 1

print()
if self.args.timestamp:
Expand Down
45 changes: 42 additions & 3 deletions tools/funccount_example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,41 @@ kernel activity that aren't visible in other metrics.
Include -T to print timestamps on output.


A maximum duration can be set. For example, to print 5 x 1 second summaries
of vfs_read() calls:

# ./funccount -i 1 -d 5 vfs_read
Tracing 1 functions for "vfs_read"... Hit Ctrl-C to end.

FUNC COUNT
vfs_read 30

FUNC COUNT
vfs_read 26

FUNC COUNT
vfs_read 54

FUNC COUNT
vfs_read 25

FUNC COUNT
vfs_read 31
Detaching...

By leaving off the "-i 1", this will print a single 5 second summary:

# funccount.py -d 5 vfs_read
Tracing 1 functions for "vfs_read"... Hit Ctrl-C to end.

FUNC COUNT
vfs_read 167
Detaching...

This can be useful for finding out rates: trace all functions for ten seconds
and then divide by ten for the per-second rate.


The "*" wildcard can be used multiple times. Eg, matching functions that contain
the word "readdir":

Expand Down Expand Up @@ -293,8 +328,9 @@ Detaching...

Full USAGE:

# ./funccount -h
usage: funccount.py [-h] [-p PID] [-i INTERVAL] [-T] [-r] [-d] pattern
# ./funccount -h
usage: funccount [-h] [-p PID] [-i INTERVAL] [-d DURATION] [-T] [-r] [-D]
pattern

Count functions, tracepoints, and USDT probes

Expand All @@ -306,16 +342,19 @@ optional arguments:
-p PID, --pid PID trace this PID only
-i INTERVAL, --interval INTERVAL
summary interval, seconds
-d DURATION, --duration DURATION
total duration of trace, seconds
-T, --timestamp include timestamp on output
-r, --regexp use regular expressions. Default is "*" wildcards
only.
-d, --debug print BPF program before starting (for debugging
-D, --debug print BPF program before starting (for debugging
purposes)

examples:
./funccount 'vfs_*' # count kernel fns starting with "vfs"
./funccount -r '^vfs.*' # same as above, using regular expressions
./funccount -Ti 5 'vfs_*' # output every 5 seconds, with timestamps
./funccount -d 10 'vfs_*' # trace for 10 seconds only
./funccount -p 185 'vfs_*' # count vfs calls for PID 181 only
./funccount t:sched:sched_fork # count calls to the sched_fork tracepoint
./funccount -p 185 u:node:gc* # count all GC USDT probes in node, PID 185
Expand Down

0 comments on commit b03d9eb

Please sign in to comment.