# Binary Size Analysis and Optimization

This document explains how to analyze and reduce the Wasot binary size.

## Quick Reference

| Build Type | Command | Expected Size |
|------------|---------|---------------|
| Minimal | `cargo build --release --no-default-features` | ~3.2MB |
| Default (sqlite) | `cargo build --release` | ~4.0MB |
| Full (all features) | `cargo build --release --all-features` | ~6.5MB |

## Feature Flags

Wasot uses Cargo features to enable optional functionality:

| Feature | Default | Dependencies Added | Size Impact |
|---------|---------|-------------------|-------------|
| `sqlite` | Yes | sqlx (~0.8MB) | +0.8MB |
| `grpc` | No | tonic, prost (~0.5MB) | +0.5MB |
| `html` | No | scraper, html5ever (~0.3MB) | +0.3MB |
| `python` | No | pyo3 | +0.2MB |
| `optimized-alloc` | No | mimalloc | +0.1MB |

### Minimal Build

For the smallest binary without SQLite, gRPC, or HTML input support:

```bash
cargo build --release --bin=wasot --no-default-features
```

### Custom Feature Combinations

```bash
# SQLite only (default)
cargo build --release

# gRPC support for remote tools
cargo build --release --features grpc

# HTML input support
cargo build --release --features html

# Everything
cargo build --release --all-features
```

## Analyzing Binary Size

### Install Tools

```bash
# cargo-bloat - shows what's taking up space
cargo install cargo-bloat

# Optional: cargo-llvm-lines for LLVM IR analysis
cargo install cargo-llvm-lines
```

### Analyze by Crate

Shows which crates contribute most to binary size:

```bash
cargo bloat --release --bin=wasot --no-default-features --crates
```

Example output:
```
 File  .text     Size Crate
11.8%  27.9% 622.0KiB std
 5.7%  13.5% 300.6KiB regex_automata
 4.1%   9.7% 216.1KiB clap_builder
 3.5%   8.3% 185.3KiB wasot_compiler
...
```

### Analyze by Function

Shows which functions are largest:

```bash
cargo bloat --release --bin=wasot --no-default-features -n 30
```

### Dependency Tree

Check what's pulling in large dependencies:

```bash
# Find what depends on regex
cargo tree --edges=normal -i regex --no-default-features

# Check if grpc deps are excluded
cargo tree --edges=normal --no-default-features | grep -E "(prost|tonic)"
```

## Size Contributors

The minimal build (~3.2MB) breaks down roughly as:

| Component | Size | Notes |
|-----------|------|-------|
| std (Rust stdlib) | ~620KB | Required, hard to reduce |
| regex_* + aho_corasick | ~620KB | Used for pattern matching |
| clap_* | ~280KB | CLI argument parsing |
| wasot_compiler | ~185KB | Core wasot code |
| pest | ~55KB | Parser generator |
| ignore | ~50KB | Gitignore handling |
| tokio | ~36KB | Async runtime (minimal) |
| Other | ~150KB | Various small crates |

## Optimization Strategies

### Already Applied

The following optimizations are in `Cargo.toml`:

```toml
[profile.release]
opt-level = 3      # Maximum optimization
lto = "fat"        # Link-time optimization
codegen-units = 1  # Single codegen unit for better optimization
panic = "abort"    # Smaller panic handling
strip = true       # Strip symbols
```

### Potential Future Optimizations

1. **Replace clap with lighter alternative** - argh or pico-args could save ~200KB
2. **Lazy regex compilation** - reduce regex_automata impact
3. **Feature-gate more dependencies** - make ignore, tokio optional
4. **Use regex-lite** - smaller but slower regex (~10x smaller, ~3x slower)

### Trade-offs

| Option | Size Savings | Trade-off |
|--------|--------------|-----------|
| regex-lite | ~500KB | 3x slower regex matching |
| Remove clap_complete | ~65KB | No shell completions |
| Static musl linking | +200KB | Fully static binary |

## Build Script

The build release script creates a minimal binary:

```bash
./scripts/build/build_release_simple.sh
```

This builds with `--no-default-features` for the smallest binary.

## Verifying Feature Exclusion

To verify a feature is properly excluded:

```bash
# Check no sqlite dependencies
cargo tree --no-default-features | grep -i sqlite
# Should return nothing

# Check no grpc dependencies
cargo tree --no-default-features | grep -E "(prost|tonic)"
# Should return nothing

# Check no html dependencies
cargo tree --no-default-features | grep -i scraper
# Should return nothing
```

## Size Over Time

Track binary size changes:

```bash
# Add to CI or pre-commit
ls -lh target/release/wasot | awk '{print $5}'
```

Consider failing CI if size exceeds a threshold:

```bash
SIZE=$(stat -f%z target/release/wasot 2>/dev/null || stat -c%s target/release/wasot)
MAX_SIZE=$((4 * 1024 * 1024))  # 4MB
if [ "$SIZE" -gt "$MAX_SIZE" ]; then
    echo "Binary too large: $SIZE bytes (max: $MAX_SIZE)"
    exit 1
fi
```
