add --cprofile flag with periodic dump
This commit is contained in:
@@ -22,6 +22,26 @@ tuimble --host mumble.example.com --user myname
|
||||
- **toggle** — press to start, press again to stop (default)
|
||||
- **hold** — hold key to transmit, release to stop (requires evdev)
|
||||
|
||||
## Profiling
|
||||
|
||||
```sh
|
||||
tuimble --cprofile # saves to ~/.config/tuimble/profile.prof
|
||||
tuimble --cprofile /tmp/tuimble.prof # saves to custom path
|
||||
```
|
||||
|
||||
Profile data is dumped every 30 seconds and on exit, so snapshots
|
||||
are available even after a crash or `kill`. Output is standard `.prof`
|
||||
format:
|
||||
|
||||
```sh
|
||||
python3 -m pstats /tmp/tuimble.prof # interactive explorer
|
||||
# or install snakeviz for a browser-based flamegraph:
|
||||
# pip install snakeviz && snakeviz /tmp/tuimble.prof
|
||||
```
|
||||
|
||||
Note: cProfile captures the main thread only. Background workers
|
||||
started with `@work(thread=True)` are not included.
|
||||
|
||||
## Configuration
|
||||
|
||||
See `~/.config/tuimble/config.toml`. All fields are optional;
|
||||
|
||||
@@ -1,13 +1,67 @@
|
||||
"""Entry point for tuimble."""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="tuimble",
|
||||
description="TUI client for Mumble",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cprofile",
|
||||
nargs="?",
|
||||
const=None,
|
||||
default=False,
|
||||
metavar="FILE",
|
||||
help="run under cProfile, saving to FILE "
|
||||
"(default: ~/.config/tuimble/profile.prof)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
from tuimble.app import TuimbleApp
|
||||
|
||||
app = TuimbleApp()
|
||||
app.run()
|
||||
|
||||
if args.cprofile is not False:
|
||||
_run_profiled(app, args.cprofile)
|
||||
else:
|
||||
app.run()
|
||||
|
||||
|
||||
def _run_profiled(app, dest):
|
||||
"""Run the app under cProfile with periodic 30s dumps."""
|
||||
import cProfile
|
||||
from pathlib import Path
|
||||
from threading import Event, Thread
|
||||
|
||||
if dest is None:
|
||||
from tuimble.config import CONFIG_DIR
|
||||
|
||||
dest = CONFIG_DIR / "profile.prof"
|
||||
else:
|
||||
dest = Path(dest)
|
||||
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
prof = cProfile.Profile()
|
||||
stop = Event()
|
||||
|
||||
def _periodic_dump():
|
||||
while not stop.wait(30):
|
||||
prof.dump_stats(str(dest))
|
||||
|
||||
dumper = Thread(target=_periodic_dump, daemon=True)
|
||||
dumper.start()
|
||||
|
||||
try:
|
||||
prof.enable()
|
||||
app.run()
|
||||
finally:
|
||||
prof.disable()
|
||||
stop.set()
|
||||
prof.dump_stats(str(dest))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user