diff options
author | Aaron LI <aly@aaronly.me> | 2017-08-01 16:31:00 +0800 |
---|---|---|
committer | Aaron LI <aly@aaronly.me> | 2017-08-01 16:31:00 +0800 |
commit | 6f59d9d78b5cc65d825606e4dcb105283a4dc47c (patch) | |
tree | ce73b7c6355a16413f5e6b635776c6a7db4a2441 | |
parent | 77b5fb23539ee8d3c244335d17dd6b1baeda8950 (diff) | |
download | fg21sim-6f59d9d78b5cc65d825606e4dcb105283a4dc47c.tar.bz2 |
utils: Add profile.py to diagnose memory usage
Signed-off-by: Aaron LI <aly@aaronly.me>
-rw-r--r-- | fg21sim/utils/profile.py | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/fg21sim/utils/profile.py b/fg21sim/utils/profile.py new file mode 100644 index 0000000..1ccbdb5 --- /dev/null +++ b/fg21sim/utils/profile.py @@ -0,0 +1,97 @@ +# Copyright (c) 2017 Weitian LI <weitian@aaronly.me> +# MIT license + +""" +Profiling utilities to help analyze the code. +""" + +import sys +import resource +import gc +from numbers import Number +from collections import Set, Mapping, deque, defaultdict + + +def getsize(obj): + """ + Recursively iterate to sum size of object & members. + + Returns + ------- + size : int + The size of the object in units of "Bytes". + + Credit + ------ + * How do I determine the size of an object in Python? + https://stackoverflow.com/a/30316760/4856091 + """ + zero_depth_bases = (str, bytes, Number, range, bytearray) + + def inner(obj, _seen_ids=set()): + obj_id = id(obj) + if obj_id in _seen_ids: + return 0 + + _seen_ids.add(obj_id) + size = sys.getsizeof(obj) + if isinstance(obj, zero_depth_bases): + # bypass remaining control flow and return + pass + elif isinstance(obj, (tuple, list, Set, deque)): + size += sum(inner(i) for i in obj) + elif isinstance(obj, Mapping) or hasattr(obj, "items"): + size += sum(inner(k) + inner(v) for k, v in obj.items()) + # Check for custom object instances - may subclass above too + if hasattr(obj, "__dict__"): + size += inner(vars(obj)) + if hasattr(obj, "__slots__"): + # can have ``__slots__`` with ``__dict__`` + size += sum(inner(getattr(obj, s)) + for s in obj.__slots__ if hasattr(obj, s)) + return size + + return inner(obj) + + +def get_objcounts(): + """ + Get the current objects and counts as an dictionary. + + Credit + ------ + * Working around memory leaks + https://stackoverflow.com/a/1641280/4856091 + """ + objcounts = defaultdict(int) + for obj in gc.get_objects(): + objcounts[type(obj)] += 1 + return objcounts + + +def diff_objcounts(objc, objc_ref): + """ + Compare the ``objc1`` to ``objc_ref`` and return the differences + in a list of ``(type, counts)``. + + Credit + ------ + * Working around memory leaks + https://stackoverflow.com/a/1641280/4856091 + """ + diff = [(k, objc[k]-objc_ref[k]) + for k in objc + if (objc[k]-objc_ref[k])] + return diff + + +def mem_usage(MiB=True): + """ + Get the current memory usage. + """ + usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss # [KiB] + unit = "KiB" + if MiB: + usage /= 1024 + unit = "MiB" + return (usage, unit) |