Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bcc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
bcc
Commits
33522d7b
Commit
33522d7b
authored
Feb 08, 2016
by
Sasha Goldshtein
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed indentation and Python style issues from pep
parent
dda47697
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
267 additions
and
199 deletions
+267
-199
tools/memleak.c
tools/memleak.c
+39
-39
tools/memleak.py
tools/memleak.py
+188
-160
tools/memleak_examples.txt
tools/memleak_examples.txt
+40
-0
No files found.
tools/memleak.c
View file @
33522d7b
...
...
@@ -3,10 +3,10 @@
#define MAX_STACK_SIZE 10
struct
alloc_info_t
{
u64
size
;
u64
timestamp_ns
;
int
num_frames
;
u64
callstack
[
MAX_STACK_SIZE
];
u64
size
;
u64
timestamp_ns
;
int
num_frames
;
u64
callstack
[
MAX_STACK_SIZE
];
};
BPF_HASH
(
sizes
,
u64
);
...
...
@@ -14,23 +14,23 @@ BPF_HASH(allocs, u64, struct alloc_info_t);
// Adapted from https://github.com/iovisor/bcc/tools/offcputime.py
static
u64
get_frame
(
u64
*
bp
)
{
if
(
*
bp
)
{
// The following stack walker is x86_64 specific
u64
ret
=
0
;
if
(
bpf_probe_read
(
&
ret
,
sizeof
(
ret
),
(
void
*
)(
*
bp
+
8
)))
return
0
;
if
(
bpf_probe_read
(
bp
,
sizeof
(
*
bp
),
(
void
*
)
*
bp
))
*
bp
=
0
;
return
ret
;
}
return
0
;
if
(
*
bp
)
{
// The following stack walker is x86_64 specific
u64
ret
=
0
;
if
(
bpf_probe_read
(
&
ret
,
sizeof
(
ret
),
(
void
*
)(
*
bp
+
8
)))
return
0
;
if
(
bpf_probe_read
(
bp
,
sizeof
(
*
bp
),
(
void
*
)
*
bp
))
*
bp
=
0
;
return
ret
;
}
return
0
;
}
static
int
grab_stack
(
struct
pt_regs
*
ctx
,
struct
alloc_info_t
*
info
)
{
int
depth
=
0
;
u64
bp
=
ctx
->
bp
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
int
depth
=
0
;
u64
bp
=
ctx
->
bp
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
...
...
@@ -39,14 +39,14 @@ static int grab_stack(struct pt_regs *ctx, struct alloc_info_t *info)
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
if
(
!
(
info
->
callstack
[
depth
++
]
=
get_frame
(
&
bp
)))
return
depth
;
return
depth
;
return
depth
;
}
int
alloc_enter
(
struct
pt_regs
*
ctx
,
size_t
size
)
{
u64
pid
=
bpf_get_current_pid_tgid
();
u64
size64
=
size
;
sizes
.
update
(
&
pid
,
&
size64
);
u64
pid
=
bpf_get_current_pid_tgid
();
u64
size64
=
size
;
sizes
.
update
(
&
pid
,
&
size64
);
if
(
SHOULD_PRINT
)
bpf_trace_printk
(
"alloc entered, size = %u
\n
"
,
size
);
...
...
@@ -55,21 +55,21 @@ int alloc_enter(struct pt_regs *ctx, size_t size)
int
alloc_exit
(
struct
pt_regs
*
ctx
)
{
u64
address
=
ctx
->
ax
;
u64
pid
=
bpf_get_current_pid_tgid
();
u64
*
size64
=
sizes
.
lookup
(
&
pid
);
struct
alloc_info_t
info
=
{
0
};
u64
address
=
ctx
->
ax
;
u64
pid
=
bpf_get_current_pid_tgid
();
u64
*
size64
=
sizes
.
lookup
(
&
pid
);
struct
alloc_info_t
info
=
{
0
};
if
(
size64
==
0
)
return
0
;
// missed alloc entry
if
(
size64
==
0
)
return
0
;
// missed alloc entry
info
.
size
=
*
size64
;
sizes
.
delete
(
&
pid
);
info
.
size
=
*
size64
;
sizes
.
delete
(
&
pid
);
info
.
timestamp_ns
=
bpf_ktime_get_ns
();
info
.
num_frames
=
grab_stack
(
ctx
,
&
info
)
-
2
;
allocs
.
update
(
&
address
,
&
info
);
info
.
timestamp_ns
=
bpf_ktime_get_ns
();
info
.
num_frames
=
grab_stack
(
ctx
,
&
info
)
-
2
;
allocs
.
update
(
&
address
,
&
info
);
if
(
SHOULD_PRINT
)
bpf_trace_printk
(
"alloc exited, size = %lu, result = %lx, frames = %d
\n
"
,
info
.
size
,
address
,
info
.
num_frames
);
return
0
;
...
...
@@ -77,12 +77,12 @@ int alloc_exit(struct pt_regs *ctx)
int
free_enter
(
struct
pt_regs
*
ctx
,
void
*
address
)
{
u64
addr
=
(
u64
)
address
;
struct
alloc_info_t
*
info
=
allocs
.
lookup
(
&
addr
);
if
(
info
==
0
)
return
0
;
u64
addr
=
(
u64
)
address
;
struct
alloc_info_t
*
info
=
allocs
.
lookup
(
&
addr
);
if
(
info
==
0
)
return
0
;
allocs
.
delete
(
&
addr
);
allocs
.
delete
(
&
addr
);
if
(
SHOULD_PRINT
)
bpf_trace_printk
(
"free entered, address = %lx, size = %lu
\n
"
,
address
,
info
->
size
);
...
...
tools/memleak.py
View file @
33522d7b
This diff is collapsed.
Click to expand it.
tools/memleak_examples.txt
View file @
33522d7b
...
...
@@ -19,6 +19,42 @@ Attaching to malloc and free in pid 5193, Ctrl+C to quit.
__libc_start_main+0xf0 [/usr/lib64/libc-2.21.so] (7fd460ac2790)
As time goes on, it becomes apparent that the main function in the allocs
process is leaking memory, 16 bytes at a time. Fortunately, you don't have to
inspect each allocation individually -- you get a nice summary of which stack
is responsible for a large leak.
Occasionally, you do want the individual allocation details. Perhaps the same
stack is allocating various sizes and you want to confirm which sizes are
prevalent. Use the -a switch:
# ./memleak.py -p $(pidof allocs) -a
Attaching to malloc and free in pid 5193, Ctrl+C to quit.
*** Outstanding allocations:
addr = 948cd0 size = 16
addr = 948d10 size = 16
addr = 948d30 size = 16
addr = 948cf0 size = 16
64 bytes in 4 allocations from stack
main+0x6d [/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [/usr/lib64/libc-2.21.so] (7fd460ac2790)
*** Outstanding allocations:
addr = 948d50 size = 16
addr = 948cd0 size = 16
addr = 948d10 size = 16
addr = 948d30 size = 16
addr = 948cf0 size = 16
addr = 948dd0 size = 16
addr = 948d90 size = 16
addr = 948db0 size = 16
addr = 948d70 size = 16
addr = 948df0 size = 16
160 bytes in 10 allocations from stack
main+0x6d [/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [/usr/lib64/libc-2.21.so] (7fd460ac2790)
When using the -p switch, memleak traces the allocations of a particular
process. Without this switch, kernel allocations (kmalloc) are traced instead.
For example:
...
...
@@ -58,6 +94,10 @@ Attaching to kmalloc and kfree, Ctrl+C to quit.
perf_tp_event_init [kernel] (ffffffff81192479)
Here you can see that arming the kprobe to which our eBPF program is attached
consumed 8KB of memory. Loading the BPF program also consumed a couple hundred
bytes (in bpf_prog_load).
memleak stores each allocated block along with its size, timestamp, and the
stack that allocated it. When the block is deleted, this information is freed
to reduce the memory overhead.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment