Metadata-Version: 2.4
Name: gilviz
Version: 0.1.1
Summary: A side-by-side visualizer for Python's GIL, threading, multiprocessing, and asyncio
Author: Bawan
License: MIT
Project-URL: Homepage, https://github.com/bawansr/gilviz
Project-URL: Repository, https://github.com/bawansr/gilviz
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Debuggers
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.115.0
Requires-Dist: websockets>=13.0
Requires-Dist: uvicorn>=0.32.0
Requires-Dist: typer>=0.27.0
Dynamic: license-file

# gilviz

[![PyPI](https://img.shields.io/pypi/v/gilviz)](https://pypi.org/project/gilviz/)

`gilviz` is a small Python project that turns the GIL from a vague interview topic into something you can watch, measure, and explain.

It combines three things that are usually shown separately:

- a CPU-bound benchmark that highlights why the GIL limits threaded throughput,
- a browser dashboard that streams sampled thread activity in real time,
- export and comparison modes that produce data you can reuse in reports, blog posts, or portfolio writeups.

The project is intentionally simple in the workload it runs, but it is intentionally modern in the way it presents the result: FastAPI, WebSockets, a browser-based Gantt chart, and a free-threaded Python comparison path for CPython 3.13+.

## Why this project matters

Most Python concurrency demos stop at “threads are slow for CPU work.” That is true, but not memorable. `gilviz` is designed to show the mechanism rather than just the conclusion.

That matters because it demonstrates a few things interviewers and reviewers care about:

- you can build a small tool around a concrete systems problem,
- you know how to connect a backend sampler to a live UI,
- you can measure behavior and export the data instead of hand-waving it,
- you know enough about modern Python to talk about free-threaded builds, not just the traditional GIL runtime.

## What it shows

`gilviz` focuses on four visible outcomes:

- `gilviz compare` runs the same prime-counting workload with threads and processes, then compares it to an asyncio I/O workload.
- `gilviz live` opens a browser dashboard and streams sampled thread activity into a canvas-based timeline view.
- `gilviz free-threaded` checks whether the interpreter exposes the CPython 3.13+ free-threaded switch and compares threaded performance against multiprocessing.
- `gilviz export` writes the collected samples to JSON or CSV for follow-up plotting with tools like matplotlib or pandas.

## How it works

The internal flow is deliberately straightforward:

1. `src/workloads.py` defines a pure-Python prime counter and a small I/O sleep workload.
2. `src/sampler.py` samples `sys._current_frames()` at a very fine interval and infers which thread is advancing between samples.
3. `src/sessions.py` runs the workload under a `ThreadPoolExecutor` while the sampler is active and returns a `SampleRun` object.
4. `src/browser.py` exposes a FastAPI app and a WebSocket endpoint that pushes sample batches to the browser.
5. The browser renders a live canvas chart and a small stats panel so you can see the activity instead of reading raw logs.

The important design choice is that the data is collected once and then reused in multiple views. The same samples can drive the browser UI, the export command, and the benchmark summary.

## Benchmark snapshot

The numbers below are representative results from this workspace on Windows with Python 3.12. They are not meant to be universal performance claims, because CPU model, OS scheduling, and interpreter build all change the result.

| Command | What it measures | Result |
| --- | --- | --- |
| `gilviz compare` threading | CPU-bound prime counting with threads | `1.07s` |
| `gilviz compare` multiprocessing | Same CPU-bound workload with processes | `0.64s` |
| `gilviz compare` asyncio | I/O-bound sleep workload | `1.02s` |
| Inferred GIL handoffs | Thread switches observed during the sampled run | `7` |

If you want to update the table for a new machine, rerun `gilviz compare` and replace the values with the numbers you observe.

## Related work

Tools like `py-spy`, `VizTracer`, and `gil_load` already cover important parts of Python performance visibility.

- `py-spy` is a low-overhead sampler and profiler for live Python processes.
- `VizTracer` focuses on detailed trace visualization and profiling output.
- `gil_load` is aimed specifically at GIL contention and related measurements.

`gilviz` is intentionally different. It is not trying to out-profile those tools. Instead, it is a teaching and presentation project: simple workload, real-time browser visualization, inferred handoff counting, exportable sample data, and a free-threaded comparison path. That makes it better suited to demos, interviews, blog posts, and portfolio discussions.

## Installation

Install it in editable mode during development:

```bash
uv pip install -e .
```

The project uses an editable package layout so the `gilviz` command is available after install.

## Usage

Compare the concurrency models:

```bash
gilviz compare
```

Open the browser dashboard:

```bash
gilviz live
```

Inspect the current interpreter’s free-threaded status:

```bash
gilviz free-threaded
```

Export samples for later plotting or reporting:

```bash
gilviz export --output gilviz-samples.json --format json
gilviz export --output gilviz-samples.csv --format csv
```

Run without installing globally:

```bash
uv run gilviz compare
uv run gilviz live
```

## Browser dashboard

`gilviz live` starts a FastAPI server and opens a browser page that receives sample batches over WebSocket.

The page shows:

- a live sample count,
- the inferred handoff count,
- the number of worker threads being tracked,
- the interpreter status label,
- a canvas-based timeline of which thread appears to be running over time.

If the dashboard shows zeroes, it usually means the browser connected before the run had emitted enough samples, or the runtime environment is missing the WebSocket dependency. Reinstalling with `uv pip install -e .` refreshes the environment and includes the required runtime packages.

## Export format

`gilviz export` writes the sampled run to disk so you can post-process it with pandas, matplotlib, or your own reporting script.

- JSON keeps the full nested structure, including the per-sample thread state map.
- CSV expands the samples into rows that are easy to filter or chart in spreadsheet tools.

## Free-threaded mode

CPython 3.13 introduced a free-threaded build option that can run without the GIL. `gilviz free-threaded` checks whether the interpreter exposes that capability and then compares threaded CPU-bound execution against the same process-based baseline.

That is valuable because it lets you demonstrate the difference between “threads are limited by the GIL” and “threads can scale when the runtime removes that lock.” Even if you are not on a free-threaded build locally, the command documents the concept and the code path.

## Terminal recording GIF

The repository includes a VHS script so you can generate a terminal recording GIF for the project page or README.

Script:

- [demo.tape](demo.tape)

To render it with VHS after installing the tool:

```bash
vhs demo.tape
```

If you prefer asciinema, record the same commands with asciinema and convert the result to a GIF using your preferred converter.

## Fresh install check

This is the installation smoke test used during development:

```bash
uv venv --python 3.12 /tmp/test-env
source /tmp/test-env/bin/activate
uv pip install -e .
gilviz compare
```

On Windows, the equivalent is to create a temporary venv, install the package into that interpreter, and run `gilviz compare` from the generated console script.

## Publishing

When you are ready to publish a release to PyPI, the intended flow is:

```bash
uv build
uv publish
```

The publish step requires valid PyPI credentials configured in your environment. I can prepare the package and verify the build, but I cannot complete the actual upload without your PyPI token or trusted publishing configuration.

## Tests and linting

Run the deterministic checks locally with:

```bash
uv run pytest tests/test_workloads.py tests/test_sampler.py tests/test_exporting.py
uv run ruff check src/ tests/
uv run ruff format src/ tests/
```

## Project layout

```text
gilviz/
├── gilviz/          # Public import wrappers for the package name used by the CLI/tests
├── src/             # Implementation modules
├── tests/           # Deterministic tests
├── demo.tape        # VHS terminal recording script
├── README.md
├── LICENSE
└── pyproject.toml
```
