Trace Python Execution With Low Overhead and Visualize It in Perfetto
You've probably been there: something in your Python code is slow, and you've got a vague sense of where the problem lives, but print statements and guesswork aren't cutting it. You want to actually see what's happening—which functions run, in what order, and for how long. VizTracer is a tool built for exactly that. It traces your Python code execution and renders it as a timeline you can explore in a browser.
What It Does
VizTracer is a logging, debugging, and profiling tool that traces and visualizes your Python code execution. It captures detailed function entry and exit information and lays it out on a timeline alongside the relevant source code. The front-end UI is powered by Perfetto, the same tracing visualization tool used in Chrome and Android, which means you get a mature, capable interface for free (use "AWSD" to zoom and navigate; more controls are under "Support - Controls").
The core workflow is simple. For most use cases, you don't need to touch your source code at all. You run your script through the viztracer command instead of python, and it produces a result.json trace file. Then you open that file with vizviewer, which spins up a local HTTP server at http://localhost:9001 and displays the trace in your browser. If you'd rather control tracing manually, you can import VizTracer in your own script, call start() and stop(), and save() the output—or use a with statement. There's also a VS Code extension if you'd prefer to keep things inside your editor.
Why It's Cool
-
Low overhead is the headline. The README claims VizTracer is "probably the fastest tracer in the market," which matters a lot. Tracing tools are only useful if they don't distort the thing they're measuring. If the tracer adds so much overhead that your program's behavior changes, you're profiling the tracer, not your code.
-
It handles the messy stuff. Threading, multiprocessing, subprocesses, async, and PyTorch are all supported. That's a meaningful list. A lot of simple profilers fall apart the moment you introduce concurrency or spawn child processes, and those are exactly the scenarios where you need visibility the most.
-
No source changes required for most features. The command-line interface means you can point VizTracer at an existing script without rewriting anything. That lowers the barrier from "I should set up a profiler someday" to "let me just run this right now."
-
The front-end can handle serious data. The README notes it's able to render GB-level trace files smoothly. Tracing generates a lot of data fast, and a viewer that chokes on large traces is useless. Building on Perfetto gives VizTracer a front-end that's already proven at scale. For very large files, there's an option to use an external trace processor.
-
It works where you work. Linux, macOS, and Windows are all supported. No platform lock-in.
-
Small quality-of-life touches. The
--openflag opens reports right after tracing.vizviewercan serve an entire directory of trace files. Modules and console scripts (likeflask run) are supported via-mand direct invocation. These aren't flashy, but they're the kind of details that separate a tool you try once from one you keep using.
How to Try It
Installation is a single pip command:
pip install viztracer
Then, instead of running your script the usual way:
# Instead of "python3 my_script.py arg1 arg2"
viztracer my_script.py arg1 arg2
This generates a result.json file. Open it with the viewer:
vizviewer result.json
vizviewer hosts an HTTP server on http://localhost:9001 and opens your browser. You can also point it at a directory to view multiple traces:
vizviewer ./
If you don't want the browser opening automatically, use --server_only. If you just want a one-off report without a persistent server, use --once. And if you want the report to open immediately after tracing:
viztracer --open my_script.py arg1 arg2
For manual control inside your code:
from viztracer import VizTracer
tracer = VizTracer()
tracer.start()
# Something happens here
tracer.stop()
tracer.save() # also takes output_file as an optional argument
You can also use a with statement if that fits your style better.
The repository is at github.com/gaogaotiantian/viztracer, and there's a VS Code extension if you'd rather not leave your editor.
Final Thoughts
VizTracer is aimed at anyone who needs to understand what their Python code is actually doing at runtime—whether you're chasing a performance bottleneck, debugging a concurrency issue, or just trying to build a mental model of a codebase you inherited. The combination of low overhead, broad support for threading and multiprocessing, and a capable Perfetto-based front-end makes it a solid addition to your debugging toolkit. If you've been putting off proper profiling because the setup felt like too much work, this is a reasonable place to start.