feat: add --tracemalloc flag for memory profiling

Starts tracemalloc before the event loop and dumps the top 25
allocations on shutdown. Accepts optional nframes depth (default 10).
Can be combined with --cprofile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
user
2026-02-17 10:41:45 +01:00
parent 933d9e1ddd
commit a123eba32a
2 changed files with 35 additions and 0 deletions

View File

@@ -40,6 +40,14 @@ def build_parser() -> argparse.ArgumentParser:
const="derp.prof",
help="enable cProfile; dump stats to PATH [derp.prof]",
)
p.add_argument(
"--tracemalloc",
metavar="NFRAMES",
nargs="?",
const=10,
type=int,
help="enable tracemalloc; capture NFRAMES deep [10]",
)
p.add_argument(
"-V", "--version",
action="version",
@@ -70,6 +78,23 @@ def _shutdown(bot: Bot) -> None:
asyncio.get_running_loop().create_task(bot.conn.close())
def _dump_tracemalloc(log: logging.Logger, limit: int = 25) -> None:
"""Log top memory allocations from tracemalloc snapshot."""
import tracemalloc
snapshot = tracemalloc.take_snapshot()
snapshot = snapshot.filter_traces([
tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
tracemalloc.Filter(False, "<frozen importlib._bootstrap_external>"),
tracemalloc.Filter(False, "<unknown>"),
])
stats = snapshot.statistics("traceback")
total = sum(s.size for s in stats)
log.info("tracemalloc top %d (total tracked: %.1f KiB)", limit, total / 1024)
for i, stat in enumerate(stats[:limit], 1):
log.info("#%d %.1f KiB %s", i, stat.size / 1024, stat.traceback.format()[0])
def main(argv: list[str] | None = None) -> int:
"""Main entry point."""
parser = build_parser()
@@ -93,6 +118,12 @@ def main(argv: list[str] | None = None) -> int:
bot = Bot(config, registry)
bot.load_plugins()
if args.tracemalloc:
import tracemalloc
tracemalloc.start(args.tracemalloc)
log.info("tracemalloc enabled, nframes=%d", args.tracemalloc)
if args.cprofile:
import cProfile
@@ -102,6 +133,9 @@ def main(argv: list[str] | None = None) -> int:
else:
_run(bot)
if args.tracemalloc:
_dump_tracemalloc(log)
return 0