# Azure VM Setup for Benchmarking

## VM Spec

| Setting | Value |
|---|---|
| Name | `rich-bench` |
| Resource group | `RICH-BENCH-RG` |
| Region | `westus2` |
| Size | `Standard_D2s_v5` (2 vCPU, 8 GB RAM, **non-burstable**) |
| OS | Ubuntu 24.04 LTS |
| Image | `Canonical:ubuntu-24_04-lts:server:latest` |

Non-burstable is critical — burstable VMs (B-series) have variable CPU performance that makes benchmarks unreliable.

## Provisioning

```bash
# Create resource group
az group create --name RICH-BENCH-RG --location westus2

# Create VM
az vm create \
  --resource-group RICH-BENCH-RG \
  --name rich-bench \
  --image Canonical:ubuntu-24_04-lts:server:latest \
  --size Standard_D2s_v5 \
  --admin-username azureuser \
  --generate-ssh-keys \
  --custom-data cloud-init.yaml
```

## Cloud-init

The full cloud-init is in [`cloud-init.yaml`](cloud-init.yaml). It installs:

1. **System packages**: `git`, `build-essential`, `curl`
2. **uv**: `curl -LsSf https://astral.sh/uv/install.sh | sh`
3. **Python 3.12 + 3.13**: `uv python install 3.12 3.13`
4. **hyperfine**: From GitHub releases (latest)
5. **Rich clone**: `git clone https://github.com/Textualize/rich /home/azureuser/rich`
6. **Venvs**: `.venv` (3.12) and `venv313` (3.13) with Rich in editable mode
7. **Bench scripts**: Copied to `/home/azureuser/bench/`

## Post-provisioning verification

```bash
ssh azureuser@<ip>

# Check tools
python3.12 --version
python3.13 --version
hyperfine --version

# Check Rich
cd ~/rich && git status
~/rich/.venv/bin/python -c "import rich; print(rich.__version__)"

# Run baseline
bash ~/bench/bench_import.sh

# Verify low stddev (should be <2ms for import benchmarks)
```

## Directory layout on VM

```
/home/azureuser/
├── rich/                  # Rich repo clone (editable install)
│   ├── .venv/             # Python 3.12 venv
│   └── ...
├── venv313/               # Python 3.13 venv
├── bench/
│   ├── bench_import.sh    # Overall import time
│   ├── bench_module.sh    # Per-module imports
│   ├── bench_e2e.sh       # A/B branch comparison
│   ├── bench_compare.sh   # Generic branch comparison
│   ├── bench_importtime.py # -X importtime parser
│   ├── bench_runtime.py   # PR #12 runtime benchmarks
│   ├── bench_runtime2.py  # PR #13 runtime benchmarks
│   ├── bench_text.py      # Text hot-path benchmarks
│   └── test_all_impls.sh  # Multi-version test runner
└── results/               # Benchmark output storage
```

## Why this setup

- **Dedicated VM** eliminates background process noise from a developer laptop
- **Non-burstable** gives consistent CPU frequency — no turbo boost variability
- **Two Python versions** because `typing` imports `re` on 3.12 but not 3.13, which affects the `re` deferral benchmarks
- **hyperfine** handles warmup, min-runs, and statistical reporting (mean ± stddev)
- **Editable install** allows quick branch switching without reinstall overhead
