Commit 521ab4f1 authored by Sasha Goldshtein's avatar Sasha Goldshtein

Added -s switch to perform allocation sampling

parent 3889a471
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.SH NAME .SH NAME
memleak \- Print a summary of outstanding allocations and their call stacks to detect memory leaks. Uses Linux eBPF/bcc. memleak \- Print a summary of outstanding allocations and their call stacks to detect memory leaks. Uses Linux eBPF/bcc.
.SH SYNOPSIS .SH SYNOPSIS
.B memleak [-h] [-p PID] [-t] [-i INTERVAL] [-a] [-o OLDER] [-c COMMAND] .B memleak [-h] [-p PID] [-t] [-i INTERVAL] [-a] [-o OLDER] [-c COMMAND] [-s SAMPLE_RATE]
.SH DESCRIPTION .SH DESCRIPTION
memleak traces and matches memory allocation and deallocation requests, and memleak traces and matches memory allocation and deallocation requests, and
collects call stacks for each allocation. memleak can then print a summary collects call stacks for each allocation. memleak can then print a summary
...@@ -40,6 +40,9 @@ The default value is 500 milliseconds. ...@@ -40,6 +40,9 @@ The default value is 500 milliseconds.
.TP .TP
\-c COMMAND \-c COMMAND
Run the specified command and trace its allocations only. This traces malloc and free from libc. Run the specified command and trace its allocations only. This traces malloc and free from libc.
.TP
\-s SAMPLE_RATE
Record roughly every SAMPLE_RATE-th allocation to reduce overhead.
.SH EXAMPLES .SH EXAMPLES
.TP .TP
Print outstanding kernel allocation stacks every 3 seconds: Print outstanding kernel allocation stacks every 3 seconds:
...@@ -57,7 +60,8 @@ Run ./allocs and print outstanding allocation stacks for that process: ...@@ -57,7 +60,8 @@ Run ./allocs and print outstanding allocation stacks for that process:
memleak can have significant overhead if the target process or kernel performs memleak can have significant overhead if the target process or kernel performs
allocations at a very high rate. Pathological cases may exhibit up to 100x allocations at a very high rate. Pathological cases may exhibit up to 100x
degradation in running time. Most of the time, however, memleak shouldn't cause degradation in running time. Most of the time, however, memleak shouldn't cause
a significant slowdown. a significant slowdown. You can also use the \-s switch to reduce the overhead
further by capturing only every N-th allocation.
To determine the rate at which your application is calling malloc/free, or the To determine the rate at which your application is calling malloc/free, or the
rate at which your kernel is calling kmalloc/kfree, place a probe with perf and rate at which your kernel is calling kmalloc/kfree, place a probe with perf and
......
...@@ -44,6 +44,15 @@ static int grab_stack(struct pt_regs *ctx, struct alloc_info_t *info) ...@@ -44,6 +44,15 @@ static int grab_stack(struct pt_regs *ctx, struct alloc_info_t *info)
int alloc_enter(struct pt_regs *ctx, size_t size) int alloc_enter(struct pt_regs *ctx, size_t size)
{ {
// Ideally, this should use a random number source, such as
// BPF_FUNC_get_prandom_u32, but that's currently not supported
// by the bcc front-end.
if (SAMPLE_EVERY_N > 1) {
u64 ts = bpf_ktime_get_ns();
if (ts % SAMPLE_EVERY_N != 0)
return 0;
}
u64 pid = bpf_get_current_pid_tgid(); u64 pid = bpf_get_current_pid_tgid();
u64 size64 = size; u64 size64 = size;
sizes.update(&pid, &size64); sizes.update(&pid, &size64);
......
...@@ -47,7 +47,7 @@ class StackDecoder(object): ...@@ -47,7 +47,7 @@ class StackDecoder(object):
@staticmethod @staticmethod
def _is_binary_segment(parts): def _is_binary_segment(parts):
return len(parts) == 6 and \ return len(parts) == 6 and \
parts[5][0] == '[' and 'x' in parts[1] parts[5][0] != '[' and 'x' in parts[1]
def _get_code_ranges(self): def _get_code_ranges(self):
ranges = {} ranges = {}
...@@ -161,6 +161,8 @@ EXAMPLES: ...@@ -161,6 +161,8 @@ EXAMPLES:
./memleak.py -o 60000 ./memleak.py -o 60000
Trace allocations in kernel mode and display a summary of outstanding Trace allocations in kernel mode and display a summary of outstanding
allocations that are at least one minute (60 seconds) old allocations that are at least one minute (60 seconds) old
./memleak.py -s 5
Trace roughly every 5th allocation, to reduce overhead
""" """
description = """ description = """
...@@ -184,6 +186,8 @@ parser.add_argument("-o", "--older", default=500, ...@@ -184,6 +186,8 @@ parser.add_argument("-o", "--older", default=500,
help="prune allocations younger than this age in milliseconds") help="prune allocations younger than this age in milliseconds")
parser.add_argument("-c", "--command", parser.add_argument("-c", "--command",
help="execute and trace the specified command") help="execute and trace the specified command")
parser.add_argument("-s", "--sample-rate", default=1,
help="sample every N-th allocation to decrease the overhead")
args = parser.parse_args() args = parser.parse_args()
...@@ -193,6 +197,7 @@ kernel_trace = (pid == -1 and command is None) ...@@ -193,6 +197,7 @@ kernel_trace = (pid == -1 and command is None)
trace_all = args.trace trace_all = args.trace
interval = int(args.interval) interval = int(args.interval)
min_age_ns = 1e6 * int(args.older) min_age_ns = 1e6 * int(args.older)
sample_every_n = args.sample_rate
if command is not None: if command is not None:
print("Executing '%s' and tracing the resulting process." % command) print("Executing '%s' and tracing the resulting process." % command)
...@@ -200,6 +205,7 @@ if command is not None: ...@@ -200,6 +205,7 @@ if command is not None:
bpf_source = open("memleak.c").read() bpf_source = open("memleak.c").read()
bpf_source = bpf_source.replace("SHOULD_PRINT", "1" if trace_all else "0") bpf_source = bpf_source.replace("SHOULD_PRINT", "1" if trace_all else "0")
bpf_source = bpf_source.replace("SAMPLE_EVERY_N", str(sample_every_n))
bpf_program = BPF(text=bpf_source) bpf_program = BPF(text=bpf_source)
......
...@@ -117,7 +117,7 @@ USAGE message: ...@@ -117,7 +117,7 @@ USAGE message:
# ./memleak.py -h # ./memleak.py -h
usage: memleak.py [-h] [-p PID] [-t] [-i INTERVAL] [-a] [-o OLDER] usage: memleak.py [-h] [-p PID] [-t] [-i INTERVAL] [-a] [-o OLDER]
[-c COMMAND] [-c COMMAND] [-s SAMPLE_RATE]
Trace outstanding memory allocations that weren't freed. Trace outstanding memory allocations that weren't freed.
Supports both user-mode allocations made with malloc/free and kernel-mode Supports both user-mode allocations made with malloc/free and kernel-mode
...@@ -137,6 +137,8 @@ optional arguments: ...@@ -137,6 +137,8 @@ optional arguments:
milliseconds milliseconds
-c COMMAND, --command COMMAND -c COMMAND, --command COMMAND
execute and trace the specified command execute and trace the specified command
-s SAMPLE_RATE, --sample-rate SAMPLE_RATE
sample every N-th allocation to decrease the overhead
EXAMPLES: EXAMPLES:
...@@ -146,4 +148,6 @@ EXAMPLES: ...@@ -146,4 +148,6 @@ EXAMPLES:
./memleak.py -p $(pidof allocs) -t ./memleak.py -p $(pidof allocs) -t
Trace allocations and display each individual call to malloc/free Trace allocations and display each individual call to malloc/free
./memleak.py -p $(pidof allocs) -a -i 10 Trace allocations and display allocated addresses, sizes, and stacks every 10 seconds for outstanding allocations ./memleak.py -c "./allocs" Run the specified command and trace its allocations ./memleak.py Trace allocations in kernel mode and display a summary of outstanding allocations every 5 seconds ./memleak.py -o 60000 Trace allocations in kernel mode and display a summary of outstanding allocations that are at least one minute (60 seconds) old ./memleak.py -p $(pidof allocs) -a -i 10 Trace allocations and display allocated addresses, sizes, and stacks every 10 seconds for outstanding allocations ./memleak.py -c "./allocs" Run the specified command and trace its allocations ./memleak.py Trace allocations in kernel mode and display a summary of outstanding allocations every 5 seconds ./memleak.py -o 60000 Trace allocations in kernel mode and display a summary of outstanding allocations that are at least one minute (60 seconds) old
./memleak.py -s 5
Trace roughly every 5th allocation, to reduce overhead
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment