Skip to content

Latest commit

 

History

History
201 lines (162 loc) · 7.29 KB

File metadata and controls

201 lines (162 loc) · 7.29 KB

Design Space Exploration with VOLT's Genetic Algorithm

This document describes how the GA encodes, evaluates, and evolves CPU configurations. It's the bridge between the cycle-level simulator and the analytical models — the engine that discovers Pareto-optimal microarchitectures.


The Chromosome — 34 Bits, 17 Billion Designs

Every CPU configuration is encoded as a 34-bit binary chromosome. Bits are grouped by microarchitectural domain:

Bit Layout

Frontend [0:7]   Backend [7:20]   Memory [20:30]  Pipeline/Process [30:34]
│                │                │                │
├─ 0-1:  Fetch   ├─ 7-8:  ROB    ├─ 20:   L1I sz  ├─ 30-31: Pipe depth
├─ 2:    Decode  ├─ 9-11: IQ sz   ├─ 21:   L1D sz  └─ 32-33: Process node
├─ 3-4:  Pred    ├─ 12-13: PhyReg ├─ 22:   L1 assoc
└─ 5-6:  BTB     ├─ 14-15: ALUs   ├─ 23-24: L2 sz
                 ├─ 16:   LdUnit  ├─ 25:   MSHR
                 ├─ 17:   StUnit  └─ 26-27: LdQ sz
                 └─ 18-19: IssWdth └─ 28-29: StQ sz

Parameter Table

Bits Parameter Options
0-1 Fetch width 4, 6, 8
2 Decode width 4, 6
3-4 Branch predictor Gshare, Tage, Hybrid
5-6 BTB entries 256, 512, 1024
7-8 ROB size 256, 320, 384, 448
9-11 Issue queue 24, 32, 40, 48, 64
12-13 Int phys regs 192, 256, 320, 384
14-15 ALU count 3, 4, 5
16 Load units 2, 3
17 Store units 2, 3
18-19 Issue width 3, 4, 5, 6
20 L1I size 32 KB, 64 KB
21 L1D size 32 KB, 64 KB
22 L1 associativity 4, 8
23-24 L2 size 0, 256 KB, 512 KB, 1 MB
25 MSHR entries 8, 12
26-27 Load queue 32, 40, 48, 56
28-29 Store queue 24, 32, 40
30-31 Pipeline depth 14, 16, 18
32-33 Process node 5 nm, 7 nm, 10 nm

The decoder in src/ga/chromosome.rs extracts fields using bit masking:

fn extract(bits: &[bool], start: usize, count: usize) -> usize {
    bits[start..start+count].iter()
        .rev().fold(0, |acc, &b| (acc << 1) | b as usize)
}

The GA Pipeline

                   ┌─────────────────────┐
                   │  Initial Population │  (random 34-bit chromosomes)
                   └─────────┬───────────┘
                             ↓
              ┌─── each individual ───┐
              │ 1. Decode → VoltConfig │
              │ 2. Run CoreMark (500K) │  ← real binary execution
              │ 3. Get IPC, BP stats   │
              │ 4. Run analytical models│  ← freq, area, power
              │ 5. Compute fitness     │
              └────────────────────────┘
                             ↓
                   ┌──────────────────┐
                   │  Fitness Scoring  │  ← best → elite preserve
                   └─────────┬────────┘
                             ↓
              ┌─────────────────────────┐
              │  Tournament Selection   │  (size 3)
              │  × Uniform Crossover    │  (50% bit-swap)
              │  × Adaptive Mutation    │  (base 8%, grows to 25%)
              └─────────┬───────────────┘
                             ↓
                   ┌──────────────────┐
                   │  Next Generation  │  (40 individuals)
                   └──────────────────┘

Evaluation

Each individual is evaluated by:

  1. Decoding the 34-bit chromosome into a VoltConfig
  2. Running CoreMark for 500,000 instructions through the cycle-level simulator
  3. Recording IPC and cache/mispredict statistics
  4. Running analytical models to get frequency, area, and power
  5. Computing fitness

If area exceeds 35 mm², evaluation is skipped (fitness = 0). This prevents the GA from wasting time on obviously infeasible designs.

Fitness Function

let area_penalty = (area_mm2 / 25.0).min(1.0);     // target: 25 mm²
let penalty = 1.0 - ALPHA * area_penalty;            // ALPHA = 0.7
fitness = ipc * freq_ghz * penalty;                    // score to maximize

This is a single-objective reduction of the three objectives (IPC ↑, Freq ↑, Area ↓). The alpha parameter controls the trade-off: higher alpha penalizes area more aggressively.

GA Parameters

Parameter Value
Population 40
Generations 15
Tournament size 3
Crossover rate 0.8 (uniform)
Base mutation 0.08 (adaptive: grows 1% per gen, max 25%)
Elite count 2 (top individuals preserved)
Area cap 35 mm² (skip above)
Instruction limit 500,000 (CoreMark)

Results

Best Configuration

Metric Value
Name GA-8w-256r
Fitness 17.06
IPC 5.16
Frequency 4.71 GHz
Area 10.65 mm²
Power 2.42 W
Process 5 nm
Fetch width 8
Decode width 4
Branch predictor Hybrid (Gshare + Bimodal)
ROB 256
Issue queue 32
Issue width 6
Int phys regs 192
ALUs 4
L1D 32 KB, 4-way
L1I 32 KB, 4-way
L2 None (direct to DRAM)
Pipeline depth 18

Pareto Frontier

The GA discovered configurations along the IPC/Frequency/Area trade-off curve:

IPC Freq (GHz) Area (mm²) Power (W) Fitness Config
5.16 4.71 10.65 2.42 17.06 8w-256r
5.16 4.71 10.81 2.42 16.95 8w-256r
5.16 4.67 10.59 2.41 16.93 8w-256r
5.16 4.71 10.88 2.46 16.91 8w-256r
5.16 4.67 10.77 2.51 16.81 8w-256r
5.16 4.57 12.07 3.23 15.60 8w-256r

The Pareto frontier is concentrated around 8-wide fetch / 256-entry ROB / 32 IQ — suggesting this is a sweet spot for CoreMark. The GA never selected 6-wide or 4-wide fetch in the top tier.

Convergence

The GA converges rapidly — within 5 generations the best fitness reaches >15.5/17.06, and the remaining generations fine-tune around the optimum:

Gen 0: best=11.30 | Gen 5: best=15.75 | Gen 10: best=16.93 | Gen 15: best=17.06

How to Run Your Own GA

# Quick GA — saves best config only
cargo run --release -- --ga 15

# Full GA — saves all outputs to Volt CPU Designs/
cargo run --release -- --ga-full 15

# Customize the search in src/main.rs:
#   - POPULATION_SIZE (line ~120)
#   - ALPHA (area penalty weight)
#   - INST_LIMIT (instructions per eval)
#   - AREA_CAP (max area to consider)

Outputs live in Volt CPU Designs/:

File Contains
ga_results.csv All 600 evaluations (40 pop × 15 gen) with IPC, freq, area, power, fitness
config_best_ever.json Best config in a loadable JSON format
config_top01.jsonconfig_top10.json Top 10 configs
report.md Full GA report with Pareto frontier and search space description