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:
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user