From fb23da7a5c2a613d3133aa4f8f4490209c676c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Tue, 24 Aug 2021 17:32:51 +0200 Subject: [PATCH] added get_size --- CHANGELOG.md | 1 + docs/instrumentation/memory.rst | 2 ++ satella/__init__.py | 2 +- satella/instrumentation/memory/__init__.py | 3 +- .../instrumentation/memory/get_object_size.py | 29 +++++++++++++++++++ tests/test_instrumentation/test_memory.py | 6 +++- 6 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 satella/instrumentation/memory/get_object_size.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 08b81b0a..db97fa89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,4 @@ * fixed #49 * fixed #48 +* added get_size diff --git a/docs/instrumentation/memory.rst b/docs/instrumentation/memory.rst index 6bca500f..3a0e8f88 100644 --- a/docs/instrumentation/memory.rst +++ b/docs/instrumentation/memory.rst @@ -8,6 +8,8 @@ be recomputed later. Problem is, that they need a trigger to do it. Memory pressure management from Satella solves that problem. +.. autofunction:: satella.instrumentation.memory.get_size + Defining severity levels ------------------------ diff --git a/satella/__init__.py b/satella/__init__.py index d809dae6..fd902b6a 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.17.19a3' +__version__ = '2.17.19' diff --git a/satella/instrumentation/memory/__init__.py b/satella/instrumentation/memory/__init__.py index 8027fa49..7d01e970 100644 --- a/satella/instrumentation/memory/__init__.py +++ b/satella/instrumentation/memory/__init__.py @@ -3,8 +3,9 @@ from .conditions import Any, All, GlobalRelativeValue, GlobalAbsoluteValue, Loca from .default import install_force_gc_collect from .memthread import MemoryPressureManager from .dump_frames_on import dump_memory_on, install_dump_memory_on +from .get_object_size import get_size __all__ = ['Any', 'All', 'MemoryPressureManager', 'GlobalAbsoluteValue', 'GB', 'GlobalRelativeValue', 'LocalRelativeValue', 'LocalAbsoluteValue', 'MB', 'KB', 'CustomCondition', 'Not', 'install_force_gc_collect', - 'dump_memory_on', 'install_dump_memory_on'] + 'dump_memory_on', 'install_dump_memory_on', 'get_size'] diff --git a/satella/instrumentation/memory/get_object_size.py b/satella/instrumentation/memory/get_object_size.py new file mode 100644 index 00000000..fae6a179 --- /dev/null +++ b/satella/instrumentation/memory/get_object_size.py @@ -0,0 +1,29 @@ +import sys + + +# shamelessly stolen from +# https://goshippo.com/blog/measure-real-size-any-python-object/ +def get_size(obj, seen=None) -> int: + """ + Recursively finds size of objects + + :param obj: object to measure + :return: size in bytes of the object and all of it's subcomponents + """ + size = sys.getsizeof(obj) + if seen is None: + seen = set() + obj_id = id(obj) + if obj_id in seen: + return 0 + # Important mark as seen *before* entering recursion to gracefully handle + # self-referential objects + seen.add(obj_id) + if isinstance(obj, dict): + size += sum(get_size(v, seen) for v in obj.values()) + size += sum(get_size(k, seen) for k in obj.keys()) + elif hasattr(obj, '__dict__'): + size += get_size(obj.__dict__, seen) + elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)): + size += sum(get_size(i, seen) for i in obj) + return size diff --git a/tests/test_instrumentation/test_memory.py b/tests/test_instrumentation/test_memory.py index c7fcc8d0..3b73a9a8 100644 --- a/tests/test_instrumentation/test_memory.py +++ b/tests/test_instrumentation/test_memory.py @@ -5,7 +5,7 @@ import sys from satella.instrumentation import install_dump_frames_on from satella.instrumentation.memory import MemoryPressureManager, CustomCondition, All, Any, \ - dump_memory_on + dump_memory_on, get_size import time import unittest logger = logging.getLogger(__name__) @@ -27,6 +27,10 @@ class TestMemory(unittest.TestCase): install_dump_frames_on(signal.SIGUSR1) os.kill(os.getpid(), signal.SIGUSR1) + def test_get_size(self): + a = 'a' * 1024 + self.assertGreaterEqual(get_size(a), 1024) + def test_dump_memory(self): dump_memory_on() -- GitLab