2022-05-23 00:16:32 +04:00

98 lines
3.3 KiB
Python

"""
Memory usage profiler for Python.
"""
import inspect
import sys
from pympler import muppy
class MProfiler(object):
"""A memory usage profiler class.
Memory data for each function is stored as a 3-element list in the
dictionary self.memories. The index is always a codepoint (see below).
The following are the definitions of the members:
[0] = The number of times this function was called
[1] = Minimum memory consumption when this function was measured.
[2] = Maximum memory consumption when this function was measured.
A codepoint is a list of 3-tuple of the type
(filename, functionname, linenumber). You can omit either element, which
will cause the profiling to be triggered if any of the other criteria
match. E.g.
- (None, foo, None), will profile any foo function,
- (bar, foo, None) will profile only the foo function from the bar file,
- (bar, foo, 17) will profile only line 17 of the foo function defined
in the file bar.
Additionally, you can define on what events you want the profiling be
triggered. Possible events are defined in
http://docs.python.org/lib/debugger-hooks.html.
If you do not define either codepoints or events, the profiler will
record the memory usage in at every codepoint and event.
"""
def __init__(self, codepoints=None, events=None):
"""
keyword arguments:
codepoints -- a list of points in code to monitor (defaults to all
codepoints)
events -- a list of events to monitor (defaults to all events)
"""
self.memories = {}
self.codepoints = codepoints
self.events = events
def codepoint_included(self, codepoint):
"""Check if codepoint matches any of the defined codepoints."""
if self.codepoints is None:
return True
for cp in self.codepoints:
mismatch = False
for i in range(len(cp)):
if (cp[i] is not None) and (cp[i] != codepoint[i]):
mismatch = True
break
if not mismatch:
return True
return False
def profile(self, frame, event, arg): # arg req to match signature
"""Profiling method used to profile matching codepoints and events."""
if (self.events is None) or (event in self.events):
frame_info = inspect.getframeinfo(frame)
cp = (frame_info[0], frame_info[2], frame_info[1])
if self.codepoint_included(cp):
objects = muppy.get_objects()
size = muppy.get_size(objects)
if cp not in self.memories:
self.memories[cp] = [0, 0, 0, 0]
self.memories[cp][0] = 1
self.memories[cp][1] = size
self.memories[cp][2] = size
else:
self.memories[cp][0] += 1
if self.memories[cp][1] > size:
self.memories[cp][1] = size
if self.memories[cp][2] < size:
self.memories[cp][2] = size
def run(self, cmd):
sys.setprofile(self.profile)
try:
exec(cmd)
finally:
sys.setprofile(None)
return self
if __name__ == "__main__":
p = MProfiler()
p.run("print('hello')")
print(p.memories)