Skip to main content

bpred

bpred logo

Pure-Python simulator of classical CPU branch predictors for computer architecture education.

Implements six predictors from first principles with zero runtime dependencies:

  • Bimodal (Smith 1981) -- a table of n-bit saturating counters indexed by PC.
  • Gshare (McFarling 1993) -- PC XOR global-history register indexes 2-bit counters.
  • Tournament (McFarling 1993 / Alpha 21264) -- a meta-selector combining local and global sub-predictors.
  • Perceptron (Jimenez and Lin 2001) -- a table of integer-weight perceptrons that can learn linearly-separable history patterns bimodal and gshare cannot capture.
  • Local-history / PAg (Yeh and Patt 1991) -- a per-branch local history table feeds a shared pattern history table, learning periodic per-branch patterns that a bimodal predictor thrashes on.
  • TAGE (Seznec and Michaud 2006) -- a base bimodal predictor plus multiple tagged components indexed by geometrically increasing global-history lengths, letting the predictor allocate exactly the history length a branch actually needs.

Part of the same open-source computer architecture education series as tomasulo (out-of-order execution) and scoreboarding.

Install

pip install bpred

Python API

from bpred import BimodalPredictor, GsharePredictor, PerceptronPredictor, TournamentPredictor
from bpred import LocalHistoryPredictor
from bpred import run_trace, accuracy, mispredictions

# Bimodal: 2-bit counters, 1024-entry table
pred = BimodalPredictor(counter_bits=2, table_size=1024)

# Gshare: 10-bit history, 1024-entry table
pred = GsharePredictor(history_bits=10, table_size=1024)

# Tournament
from bpred import BimodalPredictor, GsharePredictor
local = BimodalPredictor(counter_bits=2, table_size=1024)
global_ = GsharePredictor(history_bits=10, table_size=1024)
pred = TournamentPredictor(local=local, global_=global_, meta_bits=2)

# Perceptron: 12-bit history, 1024-entry table
pred = PerceptronPredictor(history_length=12, table_size=1024)

# Local-history (PAg): 8-bit per-branch history, 1024-entry BHT, 256-entry PHT
pred = LocalHistoryPredictor(history_bits=8, bht_size=1024, pht_size=256)

# TAGE: base bimodal + two tagged components with 8- and 20-bit history
from bpred import TagePredictor
pred = TagePredictor(
    base_counter_bits=2,
    base_table_size=1024,
    history_lengths=(8, 20),
    component_table_sizes=(1024, 1024),
    tag_bits=9,
    counter_bits=3,
    useful_bits=2,
    reset_period=256_000,
)

# Feed a trace
trace = [(0x1000, True), (0x1004, False), (0x1008, True)]
result = run_trace(pred, trace=trace)
print(accuracy(trace_result=result))       # e.g. 0.6667
print(mispredictions(trace_result=result)) # e.g. 1

Why use the perceptron predictor?

Bimodal and gshare each use a single scalar counter per table entry, so they can only learn the average bias of a branch. When the taken/not-taken outcome correlates with a specific combination of recent history bits (a linearly-separable pattern), those predictors plateau.

The perceptron predictor maintains a weight vector per entry. The dot product of those weights with the history vector expresses arbitrary linear functions over H history bits. This lets it learn, for example, "taken when the last 4 branches were all taken" or "taken on every other iteration" -- patterns that require tracking distinct history bits simultaneously. The trade-off is that the predictor needs more warm-up branches to converge and the weights grow without bound (in simulation; hardware clamps them to a fixed-point range).

Why use the local-history (PAg) predictor?

Bimodal predicts each branch from a single counter, so a branch whose outcome follows a short repeating pattern -- the textbook T, N, T, N, ... of a loop that runs an even number of times, for example -- makes the counter oscillate and the predictor thrashes near 50%.

The local-history predictor (the PAg configuration of Yeh and Patt's two-level adaptive scheme, 1991) gives every branch its own N-bit shift register of recent outcomes in a branch history table (BHT). That local pattern then indexes a shared pattern history table (PHT) of 2-bit counters, so each distinct recent-history pattern gets its own counter. A period-k pattern is learned to near-100% accuracy once history_bits >= k, because each phase of the period maps to a different PHT entry. The first level is per-address (P), the training is adaptive (A), and the second-level PHT is global (g), which is what the name PAg encodes. The per-address-PHT variant (PAp) is a natural extension left as future work.

Why use the TAGE predictor?

Gshare and PAg each commit to a single, fixed history length. Too short and long-period or highly-correlated branches can't be disambiguated; too long and short, simple branches drown in noise and aliasing while training takes longer to converge.

TAGE (Seznec and Michaud, 2006) sidesteps that trade-off by keeping several tagged tables side by side, one per history length, growing geometrically from short to long. A tag on every entry means a table only "claims" a branch once it has actually been trained on that branch's specific history, so predictions come from the longest history length that has proven useful for that branch, while a base bimodal predictor always covers branches that no tagged table has claimed yet. When a misprediction happens, TAGE opportunistically allocates a new entry in a longer-history table, so a predictor instance can end up giving one branch a two-bit-history answer and another branch a twenty-bit-history answer, whichever each one needs.

CLI

bpred bimodal --counter-bits 2 --table-size 1024 path/to/trace.trace
bpred gshare --history-bits 10 --table-size 1024 path/to/trace.trace
bpred local --history-bits 8 --bht-size 1024 --pht-size 256 path/to/trace.trace
bpred tournament \
  --local-predictor bimodal --local-counter-bits 2 --local-table-size 1024 \
  --global-predictor gshare --global-history-bits 10 --global-table-size 1024 \
  --meta-bits 2 \
  path/to/trace.trace

Trace file format -- one branch per line:

# pc taken
0x1000 1
0x1004 0
0x1008 T
0x100c false

Accuracy example

Running the bundled sample trace with a gshare predictor:

$ bpred gshare --history-bits 4 --table-size 16 examples/sample.trace
Predictor : GsharePredictor(history_bits=4, table_size=16)
Branches  : 20
Hits      : 18
Misses    : 2
Accuracy  : 90.0000%

Development

pip install -e ".[dev]"
pytest -q
ruff check .
mypy src

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bpred-0.4.0.tar.gz (869.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bpred-0.4.0-py3-none-any.whl (23.6 kB view details)

Uploaded Python 3

File details

Details for the file bpred-0.4.0.tar.gz.

File metadata

  • Download URL: bpred-0.4.0.tar.gz
  • Upload date:
  • Size: 869.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for bpred-0.4.0.tar.gz
Algorithm Hash digest
SHA256 19e2a75cd36e554375e20c0329f3e8711261238439a12528cc40052b2aa5e1b3
MD5 748bb7af4bbd8cd4d41ab56e777fad16
BLAKE2b-256 53ceae649809926d35ab052321608a7a7b1b8948e1c85273ffadc1956a3ae010

See more details on using hashes here.

File details

Details for the file bpred-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: bpred-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 23.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for bpred-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 19276680124a20238aea46dde16b6ec977edffdfd1ed387db90f2cc361514b8f
MD5 a4e5a140ad3f76b3ddd22cda05453b5d
BLAKE2b-256 3aef63fa2a2bc485416cca1a8bdb720e8a6bc6b13752084d5013aeb716aadad5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page