xref: /aosp_15_r20/external/bcc/tools/old/stackcount.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# stackcount    Count kernel function calls and their stack traces.
4*387f9dfdSAndroid Build Coastguard Worker#               For Linux, uses BCC, eBPF.
5*387f9dfdSAndroid Build Coastguard Worker#
6*387f9dfdSAndroid Build Coastguard Worker# USAGE: stackcount [-h] [-p PID] [-i INTERVAL] [-T] [-r] pattern
7*387f9dfdSAndroid Build Coastguard Worker#
8*387f9dfdSAndroid Build Coastguard Worker# The pattern is a string with optional '*' wildcards, similar to file
9*387f9dfdSAndroid Build Coastguard Worker# globbing. If you'd prefer to use regular expressions, use the -r option.
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# The current implementation uses an unrolled loop for x86_64, and was written
12*387f9dfdSAndroid Build Coastguard Worker# as a proof of concept. This implementation should be replaced in the future
13*387f9dfdSAndroid Build Coastguard Worker# with an appropriate bpf_ call, when available.
14*387f9dfdSAndroid Build Coastguard Worker#
15*387f9dfdSAndroid Build Coastguard Worker# Currently limited to a stack trace depth of 11 (maxdepth + 1).
16*387f9dfdSAndroid Build Coastguard Worker#
17*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
18*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
19*387f9dfdSAndroid Build Coastguard Worker#
20*387f9dfdSAndroid Build Coastguard Worker# 12-Jan-2016	Brendan Gregg	Created this.
21*387f9dfdSAndroid Build Coastguard Worker
22*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
23*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
24*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime
25*387f9dfdSAndroid Build Coastguard Workerimport argparse
26*387f9dfdSAndroid Build Coastguard Workerimport signal
27*387f9dfdSAndroid Build Coastguard Worker
28*387f9dfdSAndroid Build Coastguard Worker# arguments
29*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
30*387f9dfdSAndroid Build Coastguard Worker    ./stackcount submit_bio       # count kernel stack traces for submit_bio
31*387f9dfdSAndroid Build Coastguard Worker    ./stackcount ip_output        # count kernel stack traces for ip_output
32*387f9dfdSAndroid Build Coastguard Worker    ./stackcount -s ip_output     # show symbol offsets
33*387f9dfdSAndroid Build Coastguard Worker    ./stackcount -sv ip_output    # show offsets and raw addresses (verbose)
34*387f9dfdSAndroid Build Coastguard Worker    ./stackcount 'tcp_send*'      # count stacks for funcs matching tcp_send*
35*387f9dfdSAndroid Build Coastguard Worker    ./stackcount -r '^tcp_send.*' # same as above, using regular expressions
36*387f9dfdSAndroid Build Coastguard Worker    ./stackcount -Ti 5 ip_output  # output every 5 seconds, with timestamps
37*387f9dfdSAndroid Build Coastguard Worker    ./stackcount -p 185 ip_output # count ip_output stacks for PID 185 only
38*387f9dfdSAndroid Build Coastguard Worker"""
39*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
40*387f9dfdSAndroid Build Coastguard Worker    description="Count kernel function calls and their stack traces",
41*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
42*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
44*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-i", "--interval", default=99999999,
46*387f9dfdSAndroid Build Coastguard Worker    help="summary interval, seconds")
47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true",
48*387f9dfdSAndroid Build Coastguard Worker    help="include timestamp on output")
49*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-r", "--regexp", action="store_true",
50*387f9dfdSAndroid Build Coastguard Worker    help="use regular expressions. Default is \"*\" wildcards only.")
51*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--offset", action="store_true",
52*387f9dfdSAndroid Build Coastguard Worker    help="show address offsets")
53*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true",
54*387f9dfdSAndroid Build Coastguard Worker    help="show raw addresses")
55*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("pattern",
56*387f9dfdSAndroid Build Coastguard Worker    help="search expression for kernel functions")
57*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
58*387f9dfdSAndroid Build Coastguard Workerpattern = args.pattern
59*387f9dfdSAndroid Build Coastguard Workerif not args.regexp:
60*387f9dfdSAndroid Build Coastguard Worker    pattern = pattern.replace('*', '.*')
61*387f9dfdSAndroid Build Coastguard Worker    pattern = '^' + pattern + '$'
62*387f9dfdSAndroid Build Coastguard Workeroffset = args.offset
63*387f9dfdSAndroid Build Coastguard Workerverbose = args.verbose
64*387f9dfdSAndroid Build Coastguard Workerdebug = 0
65*387f9dfdSAndroid Build Coastguard Workermaxdepth = 10    # and MAXDEPTH
66*387f9dfdSAndroid Build Coastguard Worker
67*387f9dfdSAndroid Build Coastguard Worker# signal handler
68*387f9dfdSAndroid Build Coastguard Workerdef signal_ignore(signal, frame):
69*387f9dfdSAndroid Build Coastguard Worker    print()
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker# load BPF program
72*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
73*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
74*387f9dfdSAndroid Build Coastguard Worker
75*387f9dfdSAndroid Build Coastguard Worker#define MAXDEPTH	10
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Workerstruct key_t {
78*387f9dfdSAndroid Build Coastguard Worker    u64 ip;
79*387f9dfdSAndroid Build Coastguard Worker    u64 ret[MAXDEPTH];
80*387f9dfdSAndroid Build Coastguard Worker};
81*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(counts, struct key_t);
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Workerstatic u64 get_frame(u64 *bp) {
84*387f9dfdSAndroid Build Coastguard Worker    if (*bp) {
85*387f9dfdSAndroid Build Coastguard Worker        // The following stack walker is x86_64 specific
86*387f9dfdSAndroid Build Coastguard Worker        u64 ret = 0;
87*387f9dfdSAndroid Build Coastguard Worker        if (bpf_probe_read(&ret, sizeof(ret), (void *)(*bp+8)))
88*387f9dfdSAndroid Build Coastguard Worker            return 0;
89*387f9dfdSAndroid Build Coastguard Worker        if (bpf_probe_read(bp, sizeof(*bp), (void *)*bp))
90*387f9dfdSAndroid Build Coastguard Worker            *bp = 0;
91*387f9dfdSAndroid Build Coastguard Worker        if (ret < __START_KERNEL_map)
92*387f9dfdSAndroid Build Coastguard Worker            return 0;
93*387f9dfdSAndroid Build Coastguard Worker        return ret;
94*387f9dfdSAndroid Build Coastguard Worker    }
95*387f9dfdSAndroid Build Coastguard Worker    return 0;
96*387f9dfdSAndroid Build Coastguard Worker}
97*387f9dfdSAndroid Build Coastguard Worker
98*387f9dfdSAndroid Build Coastguard Workerint trace_count(struct pt_regs *ctx) {
99*387f9dfdSAndroid Build Coastguard Worker    FILTER
100*387f9dfdSAndroid Build Coastguard Worker    struct key_t key = {};
101*387f9dfdSAndroid Build Coastguard Worker    u64 zero = 0, *val, bp = 0;
102*387f9dfdSAndroid Build Coastguard Worker    int depth = 0;
103*387f9dfdSAndroid Build Coastguard Worker
104*387f9dfdSAndroid Build Coastguard Worker    key.ip = ctx->ip;
105*387f9dfdSAndroid Build Coastguard Worker    bp = ctx->bp;
106*387f9dfdSAndroid Build Coastguard Worker
107*387f9dfdSAndroid Build Coastguard Worker    // unrolled loop, 10 (MAXDEPTH) frames deep:
108*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
109*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
110*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
111*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
112*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
113*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
114*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
115*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
116*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
117*387f9dfdSAndroid Build Coastguard Worker    if (!(key.ret[depth++] = get_frame(&bp))) goto out;
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Workerout:
120*387f9dfdSAndroid Build Coastguard Worker    val = counts.lookup_or_init(&key, &zero);
121*387f9dfdSAndroid Build Coastguard Worker    if (val) {
122*387f9dfdSAndroid Build Coastguard Worker        (*val)++;
123*387f9dfdSAndroid Build Coastguard Worker    }
124*387f9dfdSAndroid Build Coastguard Worker    return 0;
125*387f9dfdSAndroid Build Coastguard Worker}
126*387f9dfdSAndroid Build Coastguard Worker"""
127*387f9dfdSAndroid Build Coastguard Workerif args.pid:
128*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER',
129*387f9dfdSAndroid Build Coastguard Worker        ('u32 pid; pid = bpf_get_current_pid_tgid(); ' +
130*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }') % (args.pid))
131*387f9dfdSAndroid Build Coastguard Workerelse:
132*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER', '')
133*387f9dfdSAndroid Build Coastguard Workerif debug:
134*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
135*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
136*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event_re=pattern, fn_name="trace_count")
137*387f9dfdSAndroid Build Coastguard Workermatched = b.num_open_kprobes()
138*387f9dfdSAndroid Build Coastguard Workerif matched == 0:
139*387f9dfdSAndroid Build Coastguard Worker    print("0 functions matched by \"%s\". Exiting." % args.pattern)
140*387f9dfdSAndroid Build Coastguard Worker    exit()
141*387f9dfdSAndroid Build Coastguard Worker
142*387f9dfdSAndroid Build Coastguard Worker# header
143*387f9dfdSAndroid Build Coastguard Workerprint("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
144*387f9dfdSAndroid Build Coastguard Worker    (matched, args.pattern))
145*387f9dfdSAndroid Build Coastguard Worker
146*387f9dfdSAndroid Build Coastguard Workerdef print_frame(addr):
147*387f9dfdSAndroid Build Coastguard Worker    print("  ", end="")
148*387f9dfdSAndroid Build Coastguard Worker    if verbose:
149*387f9dfdSAndroid Build Coastguard Worker        print("%-16x " % addr, end="")
150*387f9dfdSAndroid Build Coastguard Worker    print(b.ksym(addr, show_offset=offset))
151*387f9dfdSAndroid Build Coastguard Worker
152*387f9dfdSAndroid Build Coastguard Worker# output
153*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1
154*387f9dfdSAndroid Build Coastguard Workerwhile (1):
155*387f9dfdSAndroid Build Coastguard Worker    try:
156*387f9dfdSAndroid Build Coastguard Worker        sleep(int(args.interval))
157*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
158*387f9dfdSAndroid Build Coastguard Worker        exiting = 1
159*387f9dfdSAndroid Build Coastguard Worker        # as cleanup can take many seconds, trap Ctrl-C:
160*387f9dfdSAndroid Build Coastguard Worker        signal.signal(signal.SIGINT, signal_ignore)
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker    print()
163*387f9dfdSAndroid Build Coastguard Worker    if args.timestamp:
164*387f9dfdSAndroid Build Coastguard Worker        print("%-8s\n" % strftime("%H:%M:%S"), end="")
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Worker    counts = b.get_table("counts")
167*387f9dfdSAndroid Build Coastguard Worker    for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
168*387f9dfdSAndroid Build Coastguard Worker        print_frame(k.ip)
169*387f9dfdSAndroid Build Coastguard Worker        for i in range(0, maxdepth):
170*387f9dfdSAndroid Build Coastguard Worker            if k.ret[i] == 0:
171*387f9dfdSAndroid Build Coastguard Worker                break
172*387f9dfdSAndroid Build Coastguard Worker            print_frame(k.ret[i])
173*387f9dfdSAndroid Build Coastguard Worker        print("    %d\n" % v.value)
174*387f9dfdSAndroid Build Coastguard Worker    counts.clear()
175*387f9dfdSAndroid Build Coastguard Worker
176*387f9dfdSAndroid Build Coastguard Worker    if exiting:
177*387f9dfdSAndroid Build Coastguard Worker        print("Detaching...")
178*387f9dfdSAndroid Build Coastguard Worker        exit()
179