Home | History | Annotate | Download | only in tracing
      1 #!/usr/bin/python
      2 #
      3 # mallocstacks  Trace malloc() calls in a process and print the full
      4 #               stack trace for all callsites.
      5 #               For Linux, uses BCC, eBPF. Embedded C.
      6 #
      7 # This script is a basic example of the new Linux 4.6+ BPF_STACK_TRACE
      8 # table API.
      9 #
     10 # Copyright 2016 GitHub, Inc.
     11 # Licensed under the Apache License, Version 2.0 (the "License")
     12 
     13 from __future__ import print_function
     14 from bcc import BPF
     15 from time import sleep
     16 import sys
     17 
     18 if len(sys.argv) < 2:
     19     print("USAGE: mallocstacks PID")
     20     exit()
     21 pid = int(sys.argv[1])
     22 
     23 # load BPF program
     24 b = BPF(text="""
     25 #include <uapi/linux/ptrace.h>
     26 
     27 BPF_HASH(calls, int);
     28 BPF_STACK_TRACE(stack_traces, 1024);
     29 
     30 int alloc_enter(struct pt_regs *ctx, size_t size) {
     31     int key = stack_traces.get_stackid(ctx,
     32         BPF_F_USER_STACK|BPF_F_REUSE_STACKID);
     33     if (key < 0)
     34         return 0;
     35 
     36     // could also use `calls.increment(key, size);`
     37     u64 zero = 0, *val;
     38     val = calls.lookup_or_init(&key, &zero);
     39     (*val) += size;
     40     return 0;
     41 };
     42 """)
     43 
     44 b.attach_uprobe(name="c", sym="malloc", fn_name="alloc_enter", pid=pid)
     45 print("Attaching to malloc in pid %d, Ctrl+C to quit." % pid)
     46 
     47 # sleep until Ctrl-C
     48 try:
     49     sleep(99999999)
     50 except KeyboardInterrupt:
     51     pass
     52 
     53 calls = b.get_table("calls")
     54 stack_traces = b.get_table("stack_traces")
     55 
     56 for k, v in reversed(sorted(calls.items(), key=lambda c: c[1].value)):
     57     print("%d bytes allocated at:" % v.value)
     58     for addr in stack_traces.walk(k.value):
     59         print("\t%s" % b.sym(addr, pid, show_offset=True))
     60