""" 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)