diff --git a/man/man8/memleak.8 b/man/man8/memleak.8 index fa52c8cf67a4..2fd2676435c7 100644 --- a/man/man8/memleak.8 +++ b/man/man8/memleak.8 @@ -3,8 +3,8 @@ 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] [--combined-only] -[-s SAMPLE_RATE] [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [-O OBJ] [INTERVAL] -[COUNT] +[--wa-missing-free] [-s SAMPLE_RATE] [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] +[-O OBJ] [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 @@ -53,6 +53,9 @@ Use statistics precalculated in kernel space. Amount of data to be pulled from kernel significantly decreases, at the cost of losing capabilities of time-based false positives filtering (\-o). .TP +\-\-wa-missing-free +Make up the action of free to alleviate misjudgments when free is missing. +.TP \-s SAMPLE_RATE Record roughly every SAMPLE_RATE-th allocation to reduce overhead. .TP @@ -109,6 +112,9 @@ Additionally, option \-\-combined-only saves processing time by reusing already calculated allocation statistics from kernel. It's faster, but lacks information about particular allocations. +Also, option \-\-wa-missing-free makes memleak more accuracy in the complicated +environment. + 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 collect statistics. For example, to determine how many calls to __kmalloc are diff --git a/tools/memleak.py b/tools/memleak.py index ac34fd4d17f6..0800135e626a 100755 --- a/tools/memleak.py +++ b/tools/memleak.py @@ -4,8 +4,8 @@ # memory leaks in user-mode processes and the kernel. # # USAGE: memleak [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND] -# [--combined-only] [-s SAMPLE_RATE] [-T TOP] [-z MIN_SIZE] -# [-Z MAX_SIZE] [-O OBJ] +# [--combined-only] [--wa-missing-free] [-s SAMPLE_RATE] +# [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [-O OBJ] # [interval] [count] # # Licensed under the Apache License, Version 2.0 (the "License") @@ -88,6 +88,8 @@ def run_command_get_pid(command): help="execute and trace the specified command") parser.add_argument("--combined-only", default=False, action="store_true", help="show combined allocation statistics only") +parser.add_argument("--wa-missing-free", default=False, action="store_true", + help="Workaround to alleviate misjudgments when free is missing") parser.add_argument("-s", "--sample-rate", default=1, type=int, help="sample every N-th allocation to decrease the overhead") parser.add_argument("-T", "--top", type=int, default=10, @@ -330,11 +332,15 @@ def run_command_get_pid(command): bpf_source_kernel = """ TRACEPOINT_PROBE(kmem, kmalloc) { + if (WORKAROUND_MISSING_FREE) + gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } TRACEPOINT_PROBE(kmem, kmalloc_node) { + if (WORKAROUND_MISSING_FREE) + gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } @@ -344,11 +350,15 @@ def run_command_get_pid(command): } TRACEPOINT_PROBE(kmem, kmem_cache_alloc) { + if (WORKAROUND_MISSING_FREE) + gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } TRACEPOINT_PROBE(kmem, kmem_cache_alloc_node) { + if (WORKAROUND_MISSING_FREE) + gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } @@ -385,6 +395,10 @@ def run_command_get_pid(command): else: bpf_source += bpf_source_kernel +if kernel_trace: + bpf_source = bpf_source.replace("WORKAROUND_MISSING_FREE", "1" + if args.wa_missing_free 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_source = bpf_source.replace("PAGE_SIZE", str(resource.getpagesize())) diff --git a/tools/memleak_example.txt b/tools/memleak_example.txt index 307a9fa51074..421801702c11 100644 --- a/tools/memleak_example.txt +++ b/tools/memleak_example.txt @@ -146,13 +146,33 @@ Note that even though the application leaks 16 bytes of memory every second, the report (printed every 5 seconds) doesn't "see" all the allocations because of the sampling rate applied. +Profiling in memory part is hard to be accurate because of BPF infrastructure. +memleak keeps misjudging memory leak on the complicated environment which has +the action of free in hard/soft irq. +Add workaround to alleviate misjudgments when free is missing: + +# ./memleak --wa-missing-free +Attaching to kernel allocators, Ctrl+C to quit. +... + 248 bytes in 4 allocations from stack + bpf_prog_load [kernel] + sys_bpf [kernel] + + 328 bytes in 1 allocations from stack + perf_mmap [kernel] + mmap_region [kernel] + do_mmap [kernel] + vm_mmap_pgoff [kernel] + sys_mmap_pgoff [kernel] + sys_mmap [kernel] + USAGE message: # ./memleak -h usage: memleak.py [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND] - [--combined-only] [-s SAMPLE_RATE] [-T TOP] [-z MIN_SIZE] - [-Z MAX_SIZE] [-O OBJ] + [--combined-only] [--wa-missing-free] [-s SAMPLE_RATE] + [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [-O OBJ] [interval] [count] Trace outstanding memory allocations that weren't freed. @@ -177,6 +197,8 @@ optional arguments: -c COMMAND, --command COMMAND execute and trace the specified command --combined-only show combined allocation statistics only + --wa-missing-free Workaround to alleviate misjudgments when free is + missing -s SAMPLE_RATE, --sample-rate SAMPLE_RATE sample every N-th allocation to decrease the overhead -T TOP, --top TOP display only this many top allocating stacks (by size)