Skip to content

Commit

Permalink
Added -z and -Z switches for filtering by size, added copyright notices
Browse files Browse the repository at this point in the history
  • Loading branch information
goldshtn committed Feb 10, 2016
1 parent 828edb5 commit 5045964
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 6 deletions.
18 changes: 15 additions & 3 deletions man/man8/memleak.8
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
.SH NAME
memleak \- Print a summary of outstanding allocations and their call stacks to detect memory leaks. Uses Linux eBPF/bcc.
.SH SYNOPSIS
.B memleak [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND] [-s SAMPLE_RATE] [-d STACK_DEPTH] [-T TOP] [INTERVAL] [COUNT]
.B memleak [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND] [-s SAMPLE_RATE]
[-d STACK_DEPTH] [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [INTERVAL] [COUNT]
.SH DESCRIPTION
memleak traces and matches memory allocation and deallocation requests, and
collects call stacks for each allocation. memleak can then print a summary
Expand Down Expand Up @@ -52,6 +53,12 @@ The default value is 10.
Print only the top TOP stacks (sorted by size).
The default value is 10.
.TP
\-z MIN_SIZE
Capture only allocations that are larger than or equal to MIN_SIZE bytes.
.TP
\-Z MAX_SIZE
Capture only allocations that are smaller than or equal to MAX_SIZE bytes.
.TP
INTERVAL
Print a summary of oustanding allocations and their call stacks every INTERVAL seconds.
The default interval is 5 seconds.
Expand All @@ -76,12 +83,17 @@ stacks 10 times before quitting.
Run ./allocs and print outstanding allocation stacks for that process:
#
.B memleak -c "./allocs"
.TP
Capture only allocations between 16 and 32 bytes in size:
#
.B memleak -z 16 -Z 32
.SH OVERHEAD
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
degradation in running time. Most of the time, however, memleak shouldn't cause
a significant slowdown. You can also use the \-s switch to reduce the overhead
further by capturing only every N-th allocation.
a significant slowdown. You can use the \-s switch to reduce the overhead
further by capturing only every N-th allocation. The \-z and \-Z switches can
also reduce overhead by capturing only allocations of specific sizes.

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
Expand Down
11 changes: 8 additions & 3 deletions tools/memleak.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/*
* memleak.c Trace and display outstanding allocations to detect
* memory leaks in user-mode processes and the kernel.
*
* Copyright (C) 2016 Sasha Goldshtein.
*/

#include <uapi/linux/ptrace.h>

struct alloc_info_t {
Expand Down Expand Up @@ -33,9 +40,7 @@ static int grab_stack(struct pt_regs *ctx, struct alloc_info_t *info)

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.
SIZE_FILTER
if (SAMPLE_EVERY_N > 1) {
u64 ts = bpf_ktime_get_ns();
if (ts % SAMPLE_EVERY_N != 0)
Expand Down
31 changes: 31 additions & 0 deletions tools/memleak.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
#!/usr/bin/env python
#
# memleak.py Trace and display outstanding allocations to detect
# memory leaks in user-mode processes and the kernel.
#
# USAGE: memleak.py [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND]
# [-s SAMPLE_RATE] [-d STACK_DEPTH] [-T TOP] [-z MIN_SIZE]
# [-Z MAX_SIZE]
# [interval] [count]
#
# Copyright (C) 2016 Sasha Goldshtein.

from bcc import BPF
from time import sleep
Expand Down Expand Up @@ -195,6 +205,10 @@ def run_command_get_pid(command):
help="maximum stack depth to capture")
parser.add_argument("-T", "--top", type=int, default=10,
help="display only this many top allocating stacks (by size)")
parser.add_argument("-z", "--min-size", type=int,
help="capture only allocations larger than this size")
parser.add_argument("-Z", "--max-size", type=int,
help="capture only allocations smaller than this size")

args = parser.parse_args()

Expand All @@ -208,6 +222,12 @@ def run_command_get_pid(command):
num_prints = args.count
max_stack_size = args.stack_depth + 2
top_stacks = args.top
min_size = args.min_size
max_size = args.max_size

if min_size is not None and max_size is not None and min_size > max_size:
print("min_size (-z) can't be greater than max_size (-Z)")
exit(1)

if command is not None:
print("Executing '%s' and tracing the resulting process." % command)
Expand All @@ -219,6 +239,17 @@ def run_command_get_pid(command):
bpf_source = bpf_source.replace("GRAB_ONE_FRAME", max_stack_size *
"\tif (!(info->callstack[depth++] = get_frame(&bp))) return depth;\n")
bpf_source = bpf_source.replace("MAX_STACK_SIZE", str(max_stack_size))

size_filter = ""
if min_size is not None and max_size is not None:
size_filter = "if (size < %d || size > %d) return 0;" % \
(min_size, max_size)
elif min_size is not None:
size_filter = "if (size < %d) return 0;" % min_size
elif max_size is not None:
size_filter = "if (size > %d) return 0;" % max_size
bpf_source = bpf_source.replace("SIZE_FILTER", size_filter)

bpf_program = BPF(text=bpf_source)

if not kernel_trace:
Expand Down
4 changes: 4 additions & 0 deletions tools/memleak_examples.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ optional arguments:
-d STACK_DEPTH, --stack_depth STACK_DEPTH
maximum stack depth to capture
-T TOP, --top TOP display only this many top allocating stacks (by size)
-z MIN_SIZE, --min-size MIN_SIZE
capture only allocations larger than this size
-Z MAX_SIZE, --max-size MAX_SIZE
capture only allocations smaller than this size

EXAMPLES:

Expand Down

0 comments on commit 5045964

Please sign in to comment.