diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index fa2a4f675..56614b98a 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -1,3 +1,4 @@ +import linecache import os import re import asyncio @@ -4541,10 +4542,10 @@ class Daemon(metaclass=JSONRPCServerType): Enable/disable tracemalloc memory tracing Usage: - jsonrpc_tracemalloc_set () + jsonrpc_tracemalloc_set ( | --enable=) Options: - --enable : (bool) True enables, False disables + --enable= : (bool) True enables, False disables Returns: (bool) is it tracing? @@ -4555,6 +4556,49 @@ class Daemon(metaclass=JSONRPCServerType): tracemalloc.stop() return tracemalloc.is_tracing() + def jsonrpc_tracemalloc_top(self, items: int = 10): + """ + Show most common objects, the place that created them and their size. + + Usage: + jsonrpc_tracemalloc_top [( | --items=)] + + Options: + --items= : (int) maximum items to return, from the most common + + Returns: + (dict) dictionary containing most common objects in memory + { + "line": (str) filename and line number where it was created, + "code": (str) code that created it, + "size": (int) size in bytes, for each "memory block", + "count" (int) number of memory blocks + } + """ + if not tracemalloc.is_tracing(): + raise Exception("Enable tracemalloc first! See 'tracemalloc set' command.") + stats = tracemalloc.take_snapshot().filter_traces(( + tracemalloc.Filter(False, ""), + tracemalloc.Filter(False, ""), + # tracemalloc and linecache here use some memory, but thats not relevant + tracemalloc.Filter(False, tracemalloc.__file__), + tracemalloc.Filter(False, linecache.__file__), + )).statistics('lineno', True) + results = [] + for stat in stats: + frame = stat.traceback[0] + filename = os.sep.join(frame.filename.split(os.sep)[-2:]) + line = linecache.getline(frame.filename, frame.lineno).strip() + results.append({ + "line": f"{filename}:{frame.lineno}", + "code": line, + "size": stat.size, + "count": stat.count + }) + if len(results) == items: + break + return results + COMMENT_DOC = """ View, create and abandon comments. """ diff --git a/tests/integration/other/test_other_commands.py b/tests/integration/other/test_other_commands.py index ba95c6225..deb9bf936 100644 --- a/tests/integration/other/test_other_commands.py +++ b/tests/integration/other/test_other_commands.py @@ -44,3 +44,13 @@ class TroubleshootingCommands(CommandTestCase): async def test_tracemalloc_commands(self): self.assertFalse(self.daemon.jsonrpc_tracemalloc_set(False)) self.assertTrue(self.daemon.jsonrpc_tracemalloc_set(True)) + + class WeirdObject(): + pass + hold_em = [WeirdObject() for _ in range(500)] + self.assertEqual( + [{'code': 'hold_em = [WeirdObject() for _ in range(500)]', + 'count': 502, + 'line': 'other/test_other_commands.py:50', + 'size': 36656}], self.daemon.jsonrpc_tracemalloc_top(items=1) + )