73 lines
1.9 KiB
Python
Executable File
73 lines
1.9 KiB
Python
Executable File
#!/usr/bin/python
|
|
#
|
|
# mallocstacks Trace malloc() calls in a process and print the full
|
|
# stack trace for all callsites.
|
|
# For Linux, uses BCC, eBPF. Embedded C.
|
|
#
|
|
# This script is a basic example of the new Linux 4.6+ BPF_STACK_TRACE
|
|
# table API.
|
|
#
|
|
# Copyright 2016 GitHub, Inc.
|
|
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
|
|
from __future__ import print_function
|
|
from bcc import BPF
|
|
from bcc.utils import printb
|
|
from time import sleep
|
|
import sys
|
|
|
|
if len(sys.argv) < 2:
|
|
print("USAGE: mallocstacks PID [NUM_STACKS=1024]")
|
|
exit()
|
|
pid = int(sys.argv[1])
|
|
if len(sys.argv) == 3:
|
|
try:
|
|
assert int(sys.argv[2]) > 0, ""
|
|
except (ValueError, AssertionError) as e:
|
|
print("USAGE: mallocstacks PID [NUM_STACKS=1024]")
|
|
print("NUM_STACKS must be a non-zero, positive integer")
|
|
exit()
|
|
stacks = sys.argv[2]
|
|
else:
|
|
stacks = "1024"
|
|
|
|
# load BPF program
|
|
b = BPF(text="""
|
|
#include <uapi/linux/ptrace.h>
|
|
|
|
BPF_HASH(calls, int);
|
|
BPF_STACK_TRACE(stack_traces, """ + stacks + """);
|
|
|
|
int alloc_enter(struct pt_regs *ctx, size_t size) {
|
|
int key = stack_traces.get_stackid(ctx, BPF_F_USER_STACK);
|
|
if (key < 0)
|
|
return 0;
|
|
|
|
// could also use `calls.increment(key, size);`
|
|
u64 zero = 0, *val;
|
|
val = calls.lookup_or_try_init(&key, &zero);
|
|
if (val) {
|
|
(*val) += size;
|
|
}
|
|
return 0;
|
|
};
|
|
""")
|
|
|
|
b.attach_uprobe(name="c", sym="malloc", fn_name="alloc_enter", pid=pid)
|
|
print("Attaching to malloc in pid %d, Ctrl+C to quit." % pid)
|
|
|
|
# sleep until Ctrl-C
|
|
try:
|
|
sleep(99999999)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
|
|
calls = b.get_table("calls")
|
|
stack_traces = b.get_table("stack_traces")
|
|
|
|
for k, v in reversed(sorted(calls.items(), key=lambda c: c[1].value)):
|
|
print("%d bytes allocated at:" % v.value)
|
|
if k.value > 0 :
|
|
for addr in stack_traces.walk(k.value):
|
|
printb(b"\t%s" % b.sym(addr, pid, show_offset=True))
|