InterSim2/allocators/ — Switch & VC Allocation Algorithms

Allocators — Switch & VC Allocation Algorithms

Resolves contention when multiple input VCs compete for the same output port or output VC during the switch-allocation (SA) and VC-allocation (VA) stages of the router pipeline.

12
Classes
20
Files
~2.5 k
Lines
7
Algorithms

📚 What is this & why does it exist?

Inside every router on the Network-on-Chip, multiple packets arriving on different input ports may want to leave through the same output port at the same time. The allocators sub-module decides who wins that competition each cycle. Without fair, fast allocation the crossbar switch would be wasted and packets would stall needlessly.

💡 Real-world analogy

Imagine a busy airport with many gates (inputs) and a limited number of runways (outputs). Each gate wants to send a plane to a runway, but only one plane can use each runway at a time. The allocator is the air traffic controller: it collects all departure requests, applies a fairness policy (round-robin, priority, or random), and grants exactly one gate per runway each cycle — maximizing throughput while preventing starvation.

Contents

Architecture

classDiagram
    class Module {
        +Name()
        +FullName()
    }
    class Allocator {
        #int _inputs
        #int _outputs
        #vector~int~ _inmatch
        #vector~int~ _outmatch
        +AddRequest(in, out, label, in_pri, out_pri)
        +Allocate()*
        +OutputAssigned(in) int
        +InputAssigned(out) int
        +NewAllocator()$ Allocator*
    }
    class DenseAllocator {
        #vector~vector~sRequest~~ _request
        +ReadRequest()
    }
    class SparseAllocator {
        #vector~map~ _in_req
        #vector~map~ _out_req
        +ReadRequest()
    }
    Module <|-- Allocator
    Allocator <|-- DenseAllocator
    Allocator <|-- SparseAllocator
    DenseAllocator <|-- Wavefront
    DenseAllocator <|-- PIM
    DenseAllocator <|-- LOA
    DenseAllocator <|-- MaxSizeMatch
    SparseAllocator <|-- iSLIP_Sparse
    SparseAllocator <|-- SeparableAllocator
    SparseAllocator <|-- SelAlloc
    SeparableAllocator <|-- SeparableInputFirstAllocator
    SeparableAllocator <|-- SeparableOutputFirstAllocator

Allocation Flow

flowchart LR
    A["IQRouter: SA/VA stage"] -->|"AddRequest(in,out,pri)"| B["Allocator"]
    B --> C{"Allocate()"}
    C -->|iSLIP| D["Grant/Accept\nround-robin pointers"]
    C -->|Wavefront| E["Diagonal sweep\non dense matrix"]
    C -->|Separable| F["Input Arb → Output Arb\n(or vice-versa)"]
    C -->|PIM| G["Random parallel\nmatching iterations"]
    D --> H["OutputAssigned(in)\nInputAssigned(out)"]
    E --> H
    F --> H
    G --> H
    H --> I["Router crossbar\ntraversal"]

Key Classes

ClassFilePurpose
Allocatorallocator.hppAbstract base class — defines AddRequest(), Allocate(), OutputAssigned(), InputAssigned(); factory method NewAllocator()
DenseAllocatorallocator.hppStores full N×M request matrix in vector<vector<sRequest>>; base for Wavefront, PIM, LOA, MaxSize
SparseAllocatorallocator.hppSparse request storage via map<int, sRequest> per input/output; base for iSLIP, Separable, SelAlloc
iSLIP_Sparseislip.hppIterative round-robin matching — _gptrs (grant) / _aptrs (accept) pointers rotated on match
Wavefrontwavefront.hppDiagonal-sweep matching on dense matrix; _pri offset, _skip_diags optimization flag
SeparableAllocatorseparable.hppTwo-phase allocation using per-input _input_arb and per-output _output_arb Arbiter objects
SeparableInputFirstAllocatorseparable_input_first.hppInput-first variant: each input arbiter picks best output, then output arbiters resolve conflicts
SeparableOutputFirstAllocatorseparable_output_first.hppOutput-first variant: each output arbiter picks best input, then input arbiters resolve
PIMpim.hppParallel Iterative Matching — _PIM_iter iterations of randomized grant/accept on dense matrix
LOAloa.hppLonely Output Allocator — prioritizes outputs with fewest requests via _counts vector
SelAllocselalloc.hppSelection-based allocator with _outmask for masked outputs and iterated grant/accept
MaxSizeMatchmaxsize.hppMaximum-size matching via augmenting paths (_ShortestAugmenting()); guarantees optimal matching

Data Structures

TypeNameDescription
structsRequestRequest record: port, label, in_pri, out_pri
vector<int>_inmatch / _outmatchResult arrays — _inmatch[i] = output granted to input i (-1 if none)
vector<int>_gptrs / _aptrsiSLIP grant and accept round-robin pointers (one per output/input)
set<pair>_prioritiesWavefront priority set for diagonal start positions
vector<Arbiter*>_input_arb / _output_arbPer-port arbiter objects used by SeparableAllocator
vector<int>_countsLOA per-output request count for lonely-output prioritization
int*_s / _nsMaxSizeMatch BFS stacks for augmenting path search
vector<int>_outmaskSelAlloc bitmask to disable specific outputs during allocation

Interactions

DirectionPartnerInterfaceDescription
←IQRouterNewAllocator()Router creates VC and SW allocators via factory at construction
←IQRouterAddRequest(in, out, pri)SA/VA stages register competing requests each cycle
→IQRouterOutputAssigned(in)Router reads matching result after Allocate()
→IQRouterInputAssigned(out)Router reads which input won each output port
←IQRouterClear()Request matrix reset at the start of each cycle
↔ArbiterAddRequest() / Arbitrate()SeparableAllocator delegates to per-port Arbiter objects
←Configurationalloc_type stringAllocator type selected via config: islip, wavefront, separable, etc.

Configuration

Knob / ParameterDefaultDescription
sw_allocatorislipSwitch allocator type: islip, wavefront, separable, pim, loa, selalloc, maxsize
vc_allocatorislipVC allocator type (same choices as sw_allocator)
sw_alloc_iters1Number of iSLIP / PIM / SelAlloc iterations per cycle
vc_alloc_iters1Number of VC allocation iterations per cycle
arb_typeround_robinArbiter type used inside separable allocators
speculative0Enable speculative SA (allocate before VA completes)
spec_check_elig1Check VC eligibility during speculative allocation
spec_check_cred1Check credit availability during speculative allocation
spec_mask_by_reqs0Mask speculative requests by non-speculative results
hold_switch_for_packet0Hold switch grant across all flits of a multi-flit packet
vc_busy_when_full0Mark VC as busy (not eligible for allocation) when buffer is full
num_vcs4Number of virtual channels per input port (affects allocator matrix dimensions)

Directory Map

Source tree for allocators/
allocators/
├── allocator.hpp / .cpp           ← Base class, DenseAllocator, SparseAllocator, factory
├── islip.hpp / .cpp               ← iSLIP iterative round-robin matching
├── wavefront.hpp / .cpp           ← Diagonal-sweep dense matching
├── separable.hpp / .cpp           ← SeparableAllocator base (holds Arbiter vectors)
├── separable_input_first.hpp/.cpp ← Input-first separable allocation
├── separable_output_first.hpp/.cpp← Output-first separable allocation
├── pim.hpp / .cpp                 ← Parallel Iterative Matching
├── loa.hpp / .cpp                 ← Lonely Output Allocator
├── selalloc.hpp / .cpp            ← Selection-based allocator with output masking
└── maxsize.hpp / .cpp             ← Maximum-size matching via augmenting paths

Deep-Dive Highlights

Core allocation algorithms extracted for in-depth exploration. Each topic covers one algorithm family with diagrams, code walks, and configuration details.

Deep-Dive Pages

iSLIP Round-Robin Matching Focus

Iterative grant-accept protocol with rotating pointers that guarantees fairness and converges in O(1) iterations for uniform traffic.

Extracted topic page

Separable Two-Phase Allocation Focus

Decomposes NxM matching into per-input and per-output arbiter phases. Configurable with any arbiter type (round-robin, matrix, tree).

Extracted topic page

Wavefront & PIM Matching Focus

Dense-matrix algorithms: wavefront sweeps diagonals for O(N) matching; PIM uses randomized parallel iterations for distributed matching.

Extracted topic page

Code Examples

Example: Allocator Factory & Usage in IQRouter

// Router constructs allocators at init time via factory
_vc_allocator = Allocator::NewAllocator(
    this, "vc_allocator", config.GetStr("vc_allocator"),
    _vcs * _inputs, _vcs * _outputs, &config);

_sw_allocator = Allocator::NewAllocator(
    this, "sw_allocator", config.GetStr("sw_allocator"),
    _inputs * _input_speedup, _outputs * _output_speedup, &config);

Example: iSLIP Grant-Accept Loop

// Simplified iSLIP Allocate() — one iteration
void iSLIP_Sparse::Allocate() {
  for (int iter = 0; iter < _iSLIP_iter; ++iter) {
    // Phase 1: Grant — each output scans from _gptrs[out] round-robin
    for (int out = 0; out < _outputs; ++out) {
      auto &req = _out_req[out];
      int best = -1;
      for (auto &r : req) {
        if (_inmatch[r.first] == -1) {  // input not yet matched
          if (best == -1 || /* round-robin priority */ ...)
            best = r.first;
        }
      }
      if (best != -1) { _outmatch[out] = best; }
    }
    // Phase 2: Accept — each input picks best granted output
    for (int in = 0; in < _inputs; ++in) {
      // accept from _aptrs[in], update pointers on match
    }
  }
}