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
a7cc6c21
Commit
a7cc6c21
authored
Feb 07, 2016
by
Sasha Goldshtein
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored Time class and added usage example
parent
5cd2e0bc
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
53 additions
and
37 deletions
+53
-37
tools/memleak.py
tools/memleak.py
+53
-37
No files found.
tools/memleak.py
View file @
a7cc6c21
...
...
@@ -7,20 +7,48 @@ import subprocess
import
ctypes
import
os
class
Time
(
object
):
# Adapted from http://stackoverflow.com/a/1205762
CLOCK_MONOTONIC_RAW
=
4
# see <linux/time.h>
class
timespec
(
ctypes
.
Structure
):
_fields_
=
[
(
'tv_sec'
,
ctypes
.
c_long
),
(
'tv_nsec'
,
ctypes
.
c_long
)
]
librt
=
ctypes
.
CDLL
(
'librt.so.1'
,
use_errno
=
True
)
clock_gettime
=
librt
.
clock_gettime
clock_gettime
.
argtypes
=
[
ctypes
.
c_int
,
ctypes
.
POINTER
(
timespec
)]
@
staticmethod
def
monotonic_time
():
"""monotonic_time()
Returns the reading of the monotonic clock, in nanoseconds.
"""
t
=
Time
.
timespec
()
if
Time
.
clock_gettime
(
Time
.
CLOCK_MONOTONIC_RAW
,
ctypes
.
pointer
(
t
))
!=
0
:
errno_
=
ctypes
.
get_errno
()
raise
OSError
(
errno_
,
os
.
strerror
(
errno_
))
return
t
.
tv_sec
*
1e9
+
t
.
tv_nsec
examples
=
"""
EXAMPLES:
memleak.py -p $(pidof allocs)
./
memleak.py -p $(pidof allocs)
Trace allocations and display a summary of "leaked" (outstanding)
allocations every 5 seconds
memleak.py -p $(pidof allocs) -t
./
memleak.py -p $(pidof allocs) -t
Trace allocations and display each individual call to malloc/free
memleak.py -p $(pidof allocs) -a -i 10
./
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
./
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
"""
description
=
"""
...
...
@@ -29,12 +57,20 @@ Supports both user-mode allocations made with malloc/free and kernel-mode
allocations made with kmalloc/kfree.
"""
parser
=
argparse
.
ArgumentParser
(
description
=
description
,
formatter_class
=
argparse
.
RawDescriptionHelpFormatter
,
epilog
=
examples
)
parser
.
add_argument
(
"-p"
,
"--pid"
,
help
=
"the PID to trace; if not specified, trace kernel allocs"
)
parser
.
add_argument
(
"-t"
,
"--trace"
,
action
=
"store_true"
,
help
=
"print trace messages for each alloc/free call"
)
parser
.
add_argument
(
"-i"
,
"--interval"
,
default
=
5
,
help
=
"interval in seconds to print outstanding allocations"
)
parser
.
add_argument
(
"-a"
,
"--show-allocs"
,
default
=
False
,
action
=
"store_true"
,
help
=
"show allocation addresses and sizes as well as call stacks"
)
parser
.
add_argument
(
"-o"
,
"--older"
,
default
=
500
,
help
=
"prune allocations younger than this age in milliseconds"
)
parser
=
argparse
.
ArgumentParser
(
description
=
description
,
formatter_class
=
argparse
.
RawDescriptionHelpFormatter
,
epilog
=
examples
)
parser
.
add_argument
(
"-p"
,
"--pid"
,
help
=
"the PID to trace; if not specified, trace kernel allocs"
)
parser
.
add_argument
(
"-t"
,
"--trace"
,
action
=
"store_true"
,
help
=
"print trace messages for each alloc/free call"
)
parser
.
add_argument
(
"-i"
,
"--interval"
,
default
=
5
,
help
=
"interval in seconds to print outstanding allocations"
)
parser
.
add_argument
(
"-a"
,
"--show-allocs"
,
default
=
False
,
action
=
"store_true"
,
help
=
"show allocation addresses and sizes as well as call stacks"
)
parser
.
add_argument
(
"-o"
,
"--older"
,
default
=
500
,
help
=
"prune allocations younger than this age in milliseconds"
)
# TODO Run a command and trace that command (-c)
args
=
parser
.
parse_args
()
...
...
@@ -106,7 +142,7 @@ def decode_addr(code_ranges, addr):
for
binary
,
(
start
,
end
)
in
code_ranges
.
items
():
if
addr
>=
start
and
addr
<=
end
:
offset
=
addr
-
start
if
binary
.
endswith
(
".so"
)
else
addr
return
"%s
%s"
%
(
binary
,
decode_sym
(
binary
,
offset
)
)
return
"%s
[%s]"
%
(
decode_sym
(
binary
,
offset
),
binary
)
return
"%x"
%
addr
def
decode_stack
(
info
):
...
...
@@ -116,45 +152,25 @@ def decode_stack(info):
for
i
in
range
(
0
,
info
.
num_frames
):
addr
=
info
.
callstack
[
i
]
if
kernel_trace
:
stack
+=
" %s (%x) ;"
%
(
bpf_program
.
ksym
(
addr
),
addr
)
stack
+=
" %s
[kernel]
(%x) ;"
%
(
bpf_program
.
ksym
(
addr
),
addr
)
else
:
stack
+=
" %s (%x) ;"
%
(
decode_addr
(
code_ranges
,
addr
),
addr
)
return
stack
# Adapted from http://stackoverflow.com/a/1205762
CLOCK_MONOTONIC_RAW
=
4
# see <linux/time.h>
class
timespec
(
ctypes
.
Structure
):
_fields_
=
[
(
'tv_sec'
,
ctypes
.
c_long
),
(
'tv_nsec'
,
ctypes
.
c_long
)
]
librt
=
ctypes
.
CDLL
(
'librt.so.1'
,
use_errno
=
True
)
clock_gettime
=
librt
.
clock_gettime
clock_gettime
.
argtypes
=
[
ctypes
.
c_int
,
ctypes
.
POINTER
(
timespec
)]
def
monotonic_time
():
t
=
timespec
()
if
clock_gettime
(
CLOCK_MONOTONIC_RAW
,
ctypes
.
pointer
(
t
))
!=
0
:
errno_
=
ctypes
.
get_errno
()
raise
OSError
(
errno_
,
os
.
strerror
(
errno_
))
return
t
.
tv_sec
*
1e9
+
t
.
tv_nsec
def
print_outstanding
():
stacks
=
{}
print
(
"*** Outstanding allocations:"
)
allocs
=
bpf_program
.
get_table
(
"allocs"
)
for
address
,
info
in
sorted
(
allocs
.
items
(),
key
=
lambda
a
:
-
a
[
1
].
size
):
if
monotonic_time
()
-
min_age_ns
<
info
.
timestamp_ns
:
if
Time
.
monotonic_time
()
-
min_age_ns
<
info
.
timestamp_ns
:
continue
stack
=
decode_stack
(
info
)
if
stack
in
stacks
:
stacks
[
stack
]
+=
info
.
size
else
:
stacks
[
stack
]
=
info
.
size
if
stack
in
stacks
:
stacks
[
stack
]
=
(
stacks
[
stack
][
0
]
+
1
,
stacks
[
stack
][
1
]
+
info
.
size
)
else
:
stacks
[
stack
]
=
(
1
,
info
.
size
)
if
args
.
show_allocs
:
print
(
"
\
t
addr = %x size = %s"
%
(
address
.
value
,
info
.
size
))
for
stack
,
size
in
sorted
(
stacks
.
items
(),
key
=
lambda
s
:
-
s
[
1
]):
print
(
"
\
t
%d bytes
allocated from stack
\
n
\
t
\
t
%s"
%
(
size
,
stack
.
replace
(
";"
,
"
\
n
\
t
\
t
"
)))
for
stack
,
(
count
,
size
)
in
sorted
(
stacks
.
items
(),
key
=
lambda
s
:
-
s
[
1
]
[
1
]):
print
(
"
\
t
%d bytes
in %d allocations from stack
\
n
\
t
\
t
%s"
%
(
size
,
count
,
stack
.
replace
(
";"
,
"
\
n
\
t
\
t
"
)))
while
True
:
if
trace_all
:
...
...
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