xref: /aosp_15_r20/external/bcc/tools/lib/uthreads.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# uthreads  Trace thread creation/destruction events in high-level languages.
5*387f9dfdSAndroid Build Coastguard Worker#           For Linux, uses BCC, eBPF.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: uthreads [-l {c,java,none}] [-v] pid
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Sasha Goldshtein
10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# 25-Oct-2016   Sasha Goldshtein   Created this.
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
15*387f9dfdSAndroid Build Coastguard Workerimport argparse
16*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT, utils
17*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct
18*387f9dfdSAndroid Build Coastguard Workerimport time
19*387f9dfdSAndroid Build Coastguard Workerimport os
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerlanguages = ["c", "java"]
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
24*387f9dfdSAndroid Build Coastguard Worker    ./uthreads -l java 185    # trace Java threads in process 185
25*387f9dfdSAndroid Build Coastguard Worker    ./uthreads -l none 12245  # trace only pthreads in process 12245
26*387f9dfdSAndroid Build Coastguard Worker"""
27*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
28*387f9dfdSAndroid Build Coastguard Worker    description="Trace thread creation/destruction events in " +
29*387f9dfdSAndroid Build Coastguard Worker                "high-level languages.",
30*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
31*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-l", "--language", choices=languages + ["none"],
33*387f9dfdSAndroid Build Coastguard Worker    help="language to trace (none for pthreads only)")
34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("pid", type=int, help="process id to attach to")
35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true",
36*387f9dfdSAndroid Build Coastguard Worker    help="verbose mode: print the BPF program (for debugging purposes)")
37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
38*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
39*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
40*387f9dfdSAndroid Build Coastguard Worker
41*387f9dfdSAndroid Build Coastguard Workerusdt = USDT(pid=args.pid)
42*387f9dfdSAndroid Build Coastguard Worker
43*387f9dfdSAndroid Build Coastguard Workerprogram = """
44*387f9dfdSAndroid Build Coastguard Workerstruct thread_event_t {
45*387f9dfdSAndroid Build Coastguard Worker    u64 runtime_id;
46*387f9dfdSAndroid Build Coastguard Worker    u64 native_id;
47*387f9dfdSAndroid Build Coastguard Worker    char type[8];
48*387f9dfdSAndroid Build Coastguard Worker    char name[80];
49*387f9dfdSAndroid Build Coastguard Worker};
50*387f9dfdSAndroid Build Coastguard Worker
51*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(threads);
52*387f9dfdSAndroid Build Coastguard Worker
53*387f9dfdSAndroid Build Coastguard Workerint trace_pthread(struct pt_regs *ctx) {
54*387f9dfdSAndroid Build Coastguard Worker    struct thread_event_t te = {};
55*387f9dfdSAndroid Build Coastguard Worker    u64 start_routine = 0;
56*387f9dfdSAndroid Build Coastguard Worker    char type[] = "pthread";
57*387f9dfdSAndroid Build Coastguard Worker    te.native_id = bpf_get_current_pid_tgid() & 0xFFFFFFFF;
58*387f9dfdSAndroid Build Coastguard Worker    bpf_usdt_readarg(2, ctx, &start_routine);
59*387f9dfdSAndroid Build Coastguard Worker    te.runtime_id = start_routine;  // This is really a function pointer
60*387f9dfdSAndroid Build Coastguard Worker    __builtin_memcpy(&te.type, type, sizeof(te.type));
61*387f9dfdSAndroid Build Coastguard Worker    threads.perf_submit(ctx, &te, sizeof(te));
62*387f9dfdSAndroid Build Coastguard Worker    return 0;
63*387f9dfdSAndroid Build Coastguard Worker}
64*387f9dfdSAndroid Build Coastguard Worker"""
65*387f9dfdSAndroid Build Coastguard Workerusdt.enable_probe_or_bail("pthread_start", "trace_pthread")
66*387f9dfdSAndroid Build Coastguard Worker
67*387f9dfdSAndroid Build Coastguard Workerlanguage = args.language
68*387f9dfdSAndroid Build Coastguard Workerif not language:
69*387f9dfdSAndroid Build Coastguard Worker    language = utils.detect_language(languages, args.pid)
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Workerif language == "c":
72*387f9dfdSAndroid Build Coastguard Worker    # Nothing to add
73*387f9dfdSAndroid Build Coastguard Worker    pass
74*387f9dfdSAndroid Build Coastguard Workerelif language == "java":
75*387f9dfdSAndroid Build Coastguard Worker    template = """
76*387f9dfdSAndroid Build Coastguard Workerint %s(struct pt_regs *ctx) {
77*387f9dfdSAndroid Build Coastguard Worker    char type[] = "%s";
78*387f9dfdSAndroid Build Coastguard Worker    struct thread_event_t te = {};
79*387f9dfdSAndroid Build Coastguard Worker    u64 nameptr = 0, id = 0, native_id = 0;
80*387f9dfdSAndroid Build Coastguard Worker    bpf_usdt_readarg(1, ctx, &nameptr);
81*387f9dfdSAndroid Build Coastguard Worker    bpf_usdt_readarg(3, ctx, &id);
82*387f9dfdSAndroid Build Coastguard Worker    bpf_usdt_readarg(4, ctx, &native_id);
83*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(&te.name, sizeof(te.name), (void *)nameptr);
84*387f9dfdSAndroid Build Coastguard Worker    te.runtime_id = id;
85*387f9dfdSAndroid Build Coastguard Worker    te.native_id = native_id;
86*387f9dfdSAndroid Build Coastguard Worker    __builtin_memcpy(&te.type, type, sizeof(te.type));
87*387f9dfdSAndroid Build Coastguard Worker    threads.perf_submit(ctx, &te, sizeof(te));
88*387f9dfdSAndroid Build Coastguard Worker    return 0;
89*387f9dfdSAndroid Build Coastguard Worker}
90*387f9dfdSAndroid Build Coastguard Worker    """
91*387f9dfdSAndroid Build Coastguard Worker    program += template % ("trace_start", "start")
92*387f9dfdSAndroid Build Coastguard Worker    program += template % ("trace_stop", "stop")
93*387f9dfdSAndroid Build Coastguard Worker    usdt.enable_probe_or_bail("thread__start", "trace_start")
94*387f9dfdSAndroid Build Coastguard Worker    usdt.enable_probe_or_bail("thread__stop", "trace_stop")
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Workerif args.ebpf or args.verbose:
97*387f9dfdSAndroid Build Coastguard Worker    if args.verbose:
98*387f9dfdSAndroid Build Coastguard Worker        print(usdt.get_text())
99*387f9dfdSAndroid Build Coastguard Worker    print(program)
100*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
101*387f9dfdSAndroid Build Coastguard Worker        exit()
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Workerbpf = BPF(text=program, usdt_contexts=[usdt])
104*387f9dfdSAndroid Build Coastguard Workerprint("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." %
105*387f9dfdSAndroid Build Coastguard Worker      (args.pid, language or "none"))
106*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-16s %-8s %-30s" % ("TIME", "ID", "TYPE", "DESCRIPTION"))
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Workerclass ThreadEvent(ct.Structure):
109*387f9dfdSAndroid Build Coastguard Worker    _fields_ = [
110*387f9dfdSAndroid Build Coastguard Worker        ("runtime_id", ct.c_ulonglong),
111*387f9dfdSAndroid Build Coastguard Worker        ("native_id", ct.c_ulonglong),
112*387f9dfdSAndroid Build Coastguard Worker        ("type", ct.c_char * 8),
113*387f9dfdSAndroid Build Coastguard Worker        ("name", ct.c_char * 80),
114*387f9dfdSAndroid Build Coastguard Worker        ]
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Workerstart_ts = time.time()
117*387f9dfdSAndroid Build Coastguard Worker
118*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size):
119*387f9dfdSAndroid Build Coastguard Worker    event = ct.cast(data, ct.POINTER(ThreadEvent)).contents
120*387f9dfdSAndroid Build Coastguard Worker    name = event.name
121*387f9dfdSAndroid Build Coastguard Worker    if event.type == "pthread":
122*387f9dfdSAndroid Build Coastguard Worker        name = bpf.sym(event.runtime_id, args.pid, show_module=True)
123*387f9dfdSAndroid Build Coastguard Worker        tid = event.native_id
124*387f9dfdSAndroid Build Coastguard Worker    else:
125*387f9dfdSAndroid Build Coastguard Worker        tid = "R=%s/N=%s" % (event.runtime_id, event.native_id)
126*387f9dfdSAndroid Build Coastguard Worker    print("%-8.3f %-16s %-8s %-30s" % (
127*387f9dfdSAndroid Build Coastguard Worker        time.time() - start_ts, tid, event.type, name))
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Workerbpf["threads"].open_perf_buffer(print_event)
130*387f9dfdSAndroid Build Coastguard Workerwhile 1:
131*387f9dfdSAndroid Build Coastguard Worker    try:
132*387f9dfdSAndroid Build Coastguard Worker        bpf.perf_buffer_poll()
133*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
134*387f9dfdSAndroid Build Coastguard Worker        exit()
135