Skip to content
Snippets Groups Projects
Commit e50f2753 authored by Piotr Maślanka's avatar Piotr Maślanka
Browse files

* added memory dumping

* exposed `dump_frames_on`
parent 55f2c079
No related branches found
No related tags found
No related merge requests found
# v2.17.13
* added memory dumping
* exposed `dump_frames_on`
......@@ -56,3 +56,10 @@ If you want, you can install a GC handler that will
force a complete GC collection upon entering given severity level.
.. autofunction:: satella.instrumentation.memory.install_force_gc_collect
Dumping memory information
--------------------------
.. autofunction:: satella.instrumentation.memory.dump_memory_on
.. autofunction:: satella.instrumentation.memory.install_dump_memory_on
......@@ -60,3 +60,10 @@ Alternatively, you can pass a `<frame>` object to Traceback, in order to seriali
There's a helper function as well
.. autofunction:: satella.instrumentation.frame_from_traceback
Dumping all stack frames
------------------------
.. autofunction:: satella.instrumentation.dump_frames_on
.. autofunction:: satella.instrumentation.install_dump_frames_on
__version__ = '2.17.13a1'
__version__ = '2.17.13a3'
from .dump_frames_on import install_dump_frames_on
from .dump_frames_on import install_dump_frames_on, dump_frames_on
from .trace_back import Traceback, GenerationPolicy, StackFrame, StoredVariableValue, \
frame_from_traceback
__all__ = ['install_dump_frames_on', 'Traceback', 'GenerationPolicy', 'StoredVariableValue',
'StackFrame', 'frame_from_traceback']
'StackFrame', 'frame_from_traceback', 'dump_frames_on']
......@@ -11,7 +11,17 @@ except AttributeError:
# noinspection PyUnusedLocal
def dump_frames_on(sig_no: SIG_TYPE, stack_frame: types.FrameType, output: tp.TextIO):
def dump_frames_on(sig_no: tp.Optional[SIG_TYPE] = None,
stack_frame: tp.Optional[types.FrameType] = None,
output: tp.TextIO = sys.stderr):
"""
Dump all stack frames of all threads including the values of all the local variables.
:param sig_no: signal received. Default is None.
:param stack_frame: Stack frame. Default is None.
:param output: output to print to. Default is stderr
:return:
"""
from satella.instrumentation import Traceback
output.write("Stack frame dump requested in response to signal %s\n" % (sig_no,))
......
......@@ -2,7 +2,9 @@ from .conditions import Any, All, GlobalRelativeValue, GlobalAbsoluteValue, Loca
LocalRelativeValue, GB, MB, KB, CustomCondition, Not
from .default import install_force_gc_collect
from .memthread import MemoryPressureManager
from .dump_frames_on import dump_memory_on, install_dump_memory_on
__all__ = ['Any', 'All', 'MemoryPressureManager', 'GlobalAbsoluteValue',
'GB', 'GlobalRelativeValue', 'LocalRelativeValue', 'LocalAbsoluteValue', 'MB', 'KB',
'CustomCondition', 'Not', 'install_force_gc_collect']
'CustomCondition', 'Not', 'install_force_gc_collect',
'dump_memory_on', 'install_dump_memory_on']
import gc
import signal
import sys
import typing as tp
def dump_memory_on(output: tp.TextIO = sys.stderr):
"""
Dump statistics about current Python memory usage to target stream.
Each Python object will be printed, along with a breakdown of most types and their total usage.
Make sure you have enough memory to generate a breakdown. You can preallocate something at the
start for example.
:param output: output, default is stderr
"""
top_scores = {}
instances = {}
for obj in gc.get_objects():
typ = type(obj)
size = sys.getsizeof(obj)
if typ in top_scores:
top_scores[typ] += size
instances[typ] += 1
else:
top_scores[typ] = size
instances[typ] = 1
output.write('object %s type %s size %s bytes\n' % (repr(obj), typ, size))
output.write('----------------------------------\n')
output.write('Memory usage scores: \n')
output.write('----------------------------------\n')
items = list(top_scores.items())
items.sort(key=lambda y: -y[1])
for typ, tot_size in items:
output.write('%s: %s bytes %s instances\n' % (typ, tot_size, instances[typ]))
def install_dump_memory_on(signal_number, output: tp.TextIO = sys.stderr):
"""
Instruct Python to dump all frames onto output, along with their local variables
upon receiving given signal
:param signal_number: number of the signal
:param output: output
"""
signal.signal(signal_number,
lambda sig_no, stack_frame: dump_memory_on(sig_no, stack_frame, output))
import logging
import typing as tp
from satella.instrumentation.memory import MemoryPressureManager, CustomCondition, All, Any
from satella.instrumentation.memory import MemoryPressureManager, CustomCondition, All, Any, \
dump_memory_on
import time
import unittest
logger = logging.getLogger(__name__)
......@@ -16,6 +16,10 @@ class OnDemandCondition(CustomCondition):
class TestMemory(unittest.TestCase):
def test_dump_memory(self):
dump_memory_on()
def test_memory(self):
odc = OnDemandCondition()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment