Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # @lint-avoid-python-3-compatibility-imports |
| 3 | # |
| 4 | # uthreads Trace thread creation/destruction events in high-level languages. |
| 5 | # For Linux, uses BCC, eBPF. |
| 6 | # |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 7 | # USAGE: uthreads [-l {java}] [-v] pid |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 8 | # |
| 9 | # Copyright 2016 Sasha Goldshtein |
| 10 | # Licensed under the Apache License, Version 2.0 (the "License") |
| 11 | # |
| 12 | # 25-Oct-2016 Sasha Goldshtein Created this. |
| 13 | |
| 14 | from __future__ import print_function |
| 15 | import argparse |
Paul Chaignon | 4bb6d7f | 2017-03-30 19:05:40 +0200 | [diff] [blame] | 16 | from bcc import BPF, USDT, utils |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 17 | import ctypes as ct |
| 18 | import time |
Paul Chaignon | 4bb6d7f | 2017-03-30 19:05:40 +0200 | [diff] [blame] | 19 | import os |
| 20 | |
| 21 | languages = ["java"] |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 22 | |
| 23 | examples = """examples: |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 24 | ./uthreads -l java 185 # trace Java threads in process 185 |
| 25 | ./uthreads 12245 # trace only pthreads in process 12245 |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 26 | """ |
| 27 | parser = argparse.ArgumentParser( |
| 28 | description="Trace thread creation/destruction events in " + |
| 29 | "high-level languages.", |
| 30 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 31 | epilog=examples) |
Paul Chaignon | 4bb6d7f | 2017-03-30 19:05:40 +0200 | [diff] [blame] | 32 | parser.add_argument("-l", "--language", choices=languages + ["none"], |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 33 | help="language to trace (none for pthreads only)") |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 34 | parser.add_argument("pid", type=int, help="process id to attach to") |
| 35 | parser.add_argument("-v", "--verbose", action="store_true", |
| 36 | help="verbose mode: print the BPF program (for debugging purposes)") |
| 37 | args = parser.parse_args() |
| 38 | |
| 39 | usdt = USDT(pid=args.pid) |
| 40 | |
| 41 | program = """ |
| 42 | struct thread_event_t { |
| 43 | u64 runtime_id; |
| 44 | u64 native_id; |
| 45 | char type[8]; |
| 46 | char name[80]; |
| 47 | }; |
| 48 | |
| 49 | BPF_PERF_OUTPUT(threads); |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 50 | |
| 51 | int trace_pthread(struct pt_regs *ctx) { |
| 52 | struct thread_event_t te = {}; |
| 53 | u64 start_routine = 0; |
| 54 | char type[] = "pthread"; |
| 55 | te.native_id = bpf_get_current_pid_tgid() & 0xFFFFFFFF; |
| 56 | bpf_usdt_readarg(2, ctx, &start_routine); |
| 57 | te.runtime_id = start_routine; // This is really a function pointer |
| 58 | __builtin_memcpy(&te.type, type, sizeof(te.type)); |
| 59 | threads.perf_submit(ctx, &te, sizeof(te)); |
| 60 | return 0; |
| 61 | } |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 62 | """ |
Sasha Goldshtein | dc3a57c | 2017-02-08 16:02:11 -0500 | [diff] [blame] | 63 | usdt.enable_probe_or_bail("pthread_start", "trace_pthread") |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 64 | |
Paul Chaignon | 4bb6d7f | 2017-03-30 19:05:40 +0200 | [diff] [blame] | 65 | language = args.language |
| 66 | if not language: |
| 67 | language = utils.detect_language(languages, args.pid) |
| 68 | |
| 69 | if language == "java": |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 70 | template = """ |
| 71 | int %s(struct pt_regs *ctx) { |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 72 | char type[] = "%s"; |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 73 | struct thread_event_t te = {}; |
| 74 | u64 nameptr = 0, id = 0, native_id = 0; |
| 75 | bpf_usdt_readarg(1, ctx, &nameptr); |
| 76 | bpf_usdt_readarg(3, ctx, &id); |
| 77 | bpf_usdt_readarg(4, ctx, &native_id); |
| 78 | bpf_probe_read(&te.name, sizeof(te.name), (void *)nameptr); |
| 79 | te.runtime_id = id; |
| 80 | te.native_id = native_id; |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 81 | __builtin_memcpy(&te.type, type, sizeof(te.type)); |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 82 | threads.perf_submit(ctx, &te, sizeof(te)); |
| 83 | return 0; |
| 84 | } |
| 85 | """ |
| 86 | program += template % ("trace_start", "start") |
| 87 | program += template % ("trace_stop", "stop") |
Sasha Goldshtein | dc3a57c | 2017-02-08 16:02:11 -0500 | [diff] [blame] | 88 | usdt.enable_probe_or_bail("thread__start", "trace_start") |
| 89 | usdt.enable_probe_or_bail("thread__stop", "trace_stop") |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 90 | |
| 91 | if args.verbose: |
| 92 | print(usdt.get_text()) |
| 93 | print(program) |
| 94 | |
| 95 | bpf = BPF(text=program, usdt_contexts=[usdt]) |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 96 | print("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." % |
Paul Chaignon | 4bb6d7f | 2017-03-30 19:05:40 +0200 | [diff] [blame] | 97 | (args.pid, language or "none")) |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 98 | print("%-8s %-16s %-8s %-30s" % ("TIME", "ID", "TYPE", "DESCRIPTION")) |
| 99 | |
| 100 | class ThreadEvent(ct.Structure): |
| 101 | _fields_ = [ |
| 102 | ("runtime_id", ct.c_ulonglong), |
| 103 | ("native_id", ct.c_ulonglong), |
| 104 | ("type", ct.c_char * 8), |
| 105 | ("name", ct.c_char * 80), |
| 106 | ] |
| 107 | |
| 108 | start_ts = time.time() |
| 109 | |
| 110 | def print_event(cpu, data, size): |
| 111 | event = ct.cast(data, ct.POINTER(ThreadEvent)).contents |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 112 | name = event.name |
| 113 | if event.type == "pthread": |
Sasha Goldshtein | b1bff01 | 2017-02-08 23:25:28 -0500 | [diff] [blame] | 114 | name = bpf.sym(event.runtime_id, args.pid, show_module=True) |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 115 | tid = event.native_id |
| 116 | else: |
| 117 | tid = "R=%s/N=%s" % (event.runtime_id, event.native_id) |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 118 | print("%-8.3f %-16s %-8s %-30s" % ( |
Sasha Goldshtein | bf0cf12 | 2016-10-25 04:28:06 -0700 | [diff] [blame] | 119 | time.time() - start_ts, tid, event.type, name)) |
Sasha Goldshtein | 989057d | 2016-10-25 04:08:10 -0700 | [diff] [blame] | 120 | |
| 121 | bpf["threads"].open_perf_buffer(print_event) |
| 122 | while 1: |
Teng Qin | dbf0029 | 2018-02-28 21:47:50 -0800 | [diff] [blame] | 123 | bpf.perf_buffer_poll() |