---
tags: [2025_Fall]
---
# 平行程式設計筆記
## Datapath Structure
1. Instruction Fetch: 用 Program Counter 從 Instruction Memory 抓指令
2. Instruction Decode: Decoder 解碼出 OP code, register selections
3. Execute: ALU 做運算,從 register 抓資料
4. Memory Access: Load/Store 從 Data Memory 抓資料或儲存結果。
5. Write Back: 把結果寫回 register 或 Data Memory
## Instruction Level Parallelism (ILP)
Instruction 介紹(跳過)
有些 instruction 之間沒有相依性,可以同時執行,這樣就可以提升效能。對程式設計師來說,ILP 通常是不可見的。
**為何不能實現 N 倍加速?**
* 處理器在同一指令流中找到獨立指令並平行執行的能力 (ILP) 已達到**極限**
* 傳統透過提高時脈頻率和探索 ILP 來提升性能,但受到 **Power Wall** 和製造技術限制
* 因此現在傾向**增加處理單元** (multicore),但這要求軟體必須寫成平行程式才能獲得性能提升
## Vector Program
比如 Intel AVX2, AVX-512: 用更大的 register 做 vectorization,存好幾個數字,一次進行多個運算,算是一種 **SIMD**,使用 OpenMP 的 `#pragma omp simd` 來告訴 compiler 做 vectorization。
## SIMD on CPUs and GPUs
* CPU: 所有 ALU 要對固定長的 vector 同時做同樣的運算
* GPU: SIMT (single instruction, multiple threads),執行同樣的 instruction,但每個 thread 可以是不同路徑(if-else)
比如 CPU/GPU 中多個 ALU/thread 同時執行有 if-else 的 code,會因為有些執行 if、有些執行 else,導致 **Divergent execution (分歧執行)**。為確保正確性,所有執行緒必須執行**兩條路徑**,並使用 **Masking (遮罩)** 來停用不需要寫入結果的 ALU。這會造成資源利用效率低下,最壞情況下吞吐量會大幅下降。
## Memory Constraints
記憶體的 **latency (延遲)** 和 **bandwidth (頻寬)** 還是個瓶頸。
**Stalls (停滯)**: 處理器因依賴於前一個 instruction (如 memory access) 而無法執行下一條 instruction 時發生停滯。一個 memory access 可能要幾百、幾千個 cycle。
因此有 Cache,暫存 memory 中常用的資料,L1 cache hit 的話只需要幾個 cycle。
## Hiding memory latencies
**Prefetch (預取)**: 提前把可能會用到的資料從 memory 抓到 cache,主要是 **CPU** 硬體操控,透過分析 memory access pattern 來預測並隱藏 latency。
用 **multi-threading**,有的 thread stall 時就可以執行其他 thread。這是在硬體層面 schedule logical threads (如 SMT/Hyper-Threading),需要 CPU core 儲存多個 execution contexts。與 OS 作的 process context switch 不同,更快一點。
**Multi-threading/SMT 的優缺點**:
* **優點**: 更有效利用 ALU、hide memory latency、當單一 thread 的 ILP 不足時填補 functional units
* **缺點**: 需要額外儲存 execution contexts、單一 thread 執行時間變長、高度依賴 memory bandwidth、cache 被多個 thread 瓜分而更容易 miss
## Data Parallel Execution Models
### SPMD (Single Program, Multiple Data)
以多個 process 執行同樣程式,但處理**不同的資料集**,之間可能用 shared memory 等方式溝通。
算是 MPMD (Multiple Program, Multiple Data) 的特例。
### Execution Model Comparison
| 模型 | 特點 | 優點 | 缺點 |
|------|------|------|------|
| **MPMD/SPMD** | 多個獨立 threads (Multicore CPUs) | 更通用,支援 thread-level parallelism,可混合 sequential 和 parallel code | 對 data parallelism 效率較差 |
| **SIMD/Vector** | 一個 thread 具有寬執行 datapath (許多 ALU) (x86 SSE/AVX) | 易於為 data parallelism 編程 | Vector programming 較困難 |
| **SIMT** | 多個 lockstep threads (可遵循不同 control flow) (GPUs) | Data parallelism 很簡單 | Divergent execution 會嚴重損害 performance |
## Decomposition of a program
把問題分成小任務,不一定要是靜態的切,程式執行過程也可能產生新的任務。重要的是建立足夠的任務來**保持所有 execution units 都 busy**。
### 簡單的範例
要把一張 N×N 圖片的綠色通道調亮,並計算紅色通道的平均值:
* **Step 1 (調亮)**: 可以輕易平行作,時間約 $N^2/P$
* **Step 2 (計算平均值)**:
* **方法一 (序列合併)**: Step 2 需序列執行 ($N^2$)。總時間約 $N^2/P + N^2$。加速比 $\le 2$
* **方法二 (平行優化)**: Step 2 先平行計算**局部和** ($N^2/P$),再花 $P$ 的時間**序列合併**。總時間約 $2N^2/P + P$。當 $N >> P$ 時,**加速比接近 $P$**
## Task scheduling and distribution
會想盡量讓所有 processors 的負載平均,讓它們都 busy。使用 assign tasks to threads 的方式。
### Static assignment
先決定好如何分配,好處是簡單。可能基於預測的執行時間。
**適用性**: 當工作成本 (執行時間) 和總工作量是可預測的時候。
### Semi-static assignment
執行時週期性的重新分配任務,在重新分配間是 static 的。
例如粒子模擬,因為會動,根據區域切給不同 processor 的方法需要動態調整。
### Dynamic assignment
比如 thread pool,thread 執行完一個任務後再從任務佇列拿下一個任務來執行。適用於執行時間不可預測的情況。
* **Granularity (任務粒度)**:
* **太細**: 有利於良好的負載平衡,但可能導致高同步成本 (頻繁進入 critical section 存取 shared queue)
* **太粗**: 可減少同步 overhead,但可能犧牲負載平衡
* **理想**: 任務數量應比 processor 多以確保負載平衡,但任務數量應盡可能少以減少管理 overhead 和進入 critical section 的頻率
* **A big task**: 如果突然冒出一個大任務,如果放在最後執行會拖很久,可以考慮獨立用部分 threads。
* **Distributed Task Queues (分佈式任務佇列)**: 每個 worker thread 都有自己的任務佇列,只有當本地佇列為空時,才從其他佇列中 **steal** 任務。這有助於減少同步 overhead,因為不需要在單一 shared queue 上同步。
## Example: 2D grid solver
### 問題敘述
假設 (N+2)×(N+2) 方格中,周圍一圈不會變,而中央 N×N 的點需要在每次運算設為:四周與自己的值的平均(是否是取舊值不重要,因為是要取得最終的平衡點)。
如果用從上而下、從左而右掃描計算的話,可以獨立算每個右上到左下的對角線,但開始與結尾的平行化效果不好、會需要常常同步(下一層很需要上一層的值)。
### 平行化方法
比較好的方法是 **Red-Black Coloring (紅黑著色)**,交錯放置,先更新**所有紅點**(這些點只依賴黑點),完成後**同步**;再更新**所有黑點**(這些點只依賴紅點),再同步。
考量 **Communication overhead** 時,要設計 assignment 給 processes 的方法:
* **Blocked assignment (連續幾列)**: 每個 process 負責連續幾列,與其他 process 的溝通只需要頭尾兩列
* **Interleaved assignment (交錯分配,如 12341234)**: 需要更多的溝通
因此前者較好。
### Message Passing Model
在計算完後,假設所有 processes 都先 send 再 recv(receive) 的話,因為 MPI 的 send, recv 是 **blocking (同步)** 的,呼叫會等待完成,會導致 **deadlock**。
**避免 deadlock 的策略**:
* **同步傳輸**: 可以改為:**奇數 process 先 send 再 recv,偶數 process 先 recv 再 send** (或交替進行),確保有人負責接收
* **非同步/無阻塞傳輸**: 使用 `MPI_Isend` 和 `MPI_Irecv`,這些呼叫會**立即返回**,允許 processor 在訊息實際傳輸時執行其他工作。但程式設計師必須確保在操作完成前 (通常使用 `MPI_Wait()` 檢查狀態),**不要修改用於傳輸的 buffer**
另外,關於是否完成,所有 process 傳送 diff 給 root,root 決定是否結束再傳給所有 process。
## Communication Cost Model
總通訊時間 = **Overhead (開銷)** + **Occupancy (佔用時間)** + **Network Delay (網路延遲)**
**Occupancy** 由系統中最慢的組件決定,決定了穩態下的訊息傳輸速率。
### Inherent Communication (內在溝通)
演算法本身**根本上必需**的通訊。可以透過**改變演算法**或**優化核心間的資料分配**來減少。
**例子**: Grid Solver 中,採用 **Blocked assignment** (區塊分配) 而非 Interleaved assignment,可大幅降低溝通與計算的比率。算術強度 $\propto N/P$。
> 核心間溝通也是屬於 Inherent Communication。
**Communication-to-Computation Ratio**:
$$\frac{\text{Amount of communication (e.g. bytes)}}{\text{Amount of computation (e.g. instructions)}}$$
Arithmetic intensity = 1 / Communication-to-Computation Ratio,越高越好
### Artifactual Communication (人為溝通)
由於**系統實作細節**造成的額外通訊:
* 採用 Write through cache 時頻繁寫入會需要一直儲存到記憶體,改用 Write back 就不用
* Cache Line Granularity,如 cache line 大小為 64 bytes,但實際需要用 65 bytes,會導致多傳輸 63 bytes 的無用資料
#### Cache Miss 類型
* **Cold miss (Compulsory miss)**: 第一次存取,sequential 程式無法避免,但平行程式可以 hide latency
* **Capacity miss**: Working set 大於 cache
* **Conflict miss**: Set-associative cache 的映射衝突
* **Communication miss (Coherent miss)**: 比如 P1 使用 `a[0:3]`,P2 使用 `a[4:7]`,兩者都在同一 cache line,P1 寫完後 P2 讀就會 miss。
#### Locality Optimization
透過 **Loop Fusion (迴圈融合)**,讓多個運算步驟重複使用已載入的資料,從而**提高 Arithmetic Intensity**,減少對 memory 的存取次數。
#### Contention
資源競爭,比如 critical section (dynamic assignment 存取 shared task queue)、GPU 存取共享記憶體的同一個 memory bank。
可透過增加 ginarity 或是 distributed task queue 來減少。
## CUDA Programming Model
2007 Tesla 架構後才有 CUDA,之前只能用來處理 Vertex/Fragment shaders 等 graphics 任務。
* **Host (CPU)**: 執行 sequential code,呼叫 **Kernel** 函數
* **Device (GPU)**: 執行 parallel kernel 函數
### Execution Hierarchy
Kernel 函數被組織成三個層次:
* **Grid**: 整個 kernel,執行在整個 GPU 上
* **Block**: 一組 threads,執行在單一 **SM (Streaming Multiprocessor)** 上,且**不會遷移**。視資源使用情況而定,有可能一個 SM 上同時執行多個 blocks。
* **Thread**: 最小執行單位,執行在 **CUDA Core (SP, Streaming Processor)** 上
### Warp
Threads 被分組為 **Warps** (通常 32 個 threads)。Warp 是 **SIMT (Single Instruction, Multiple Threads)** 架構下的基本執行單位。
如果 block 中的 thread 數量是 **warp 大小的倍數**,資源使用效率會更高。
### CUDA Function Qualifiers
* **`__global__`**: Host 呼叫,在 Device 執行 (kernel 函數)
* **`__device__`**: 僅在 Device 上呼叫和執行 (device 函數)
* **`__host__`**: 在 Host 上執行 (預設)
### Occupancy (佔用率)
$$\frac{\text{Active Warps}}{\text{Maximum Allowable Active Warps}}$$
衡量 GPU 計算資源的利用率。**高 occupancy** 表示有足夠多的 active threads 來**隱藏 memory latency**。
每個 block 使用的資源過多會限制 occupancy:
* **Register 使用量**: $\text{Active threads} \le \frac{\text{Total Registers per SM}}{\text{Registers per Thread}}$
* **Shared memory 使用量**: $\text{Active threads} \le \frac{\text{Total Shared memory per SM}}{\text{Shared memory per Thread}}$,shared memory 還是各 block 共用,只是通常會隨著 thread 數增加而增加。
* **Block size**: $\text{Active threads} = \text{Threads per block}\times \text{Blocks per SM} \le \text{Max Threads per SM}$
**低 occupancy** 可能導致 **GPU 資源利用不足**。
### CUDA Memory Hierarchy
GPU memory 分為三種 address spaces:
* **Private**: 每個 thread 的 registers/local variables
* **Shared**: Block 內所有 threads 共享,速度比 global memory 快約 **100 倍**
* **Global**: 所有 threads 可存取,生命週期與應用程式相同
### Memory Coalescing (記憶體合併)
為了提高 global memory 存取效率,Warp 中 threads 的請求會被**分組 (grouped)**,並以 128 bytes 等對齊單位進行存取。
**最佳情況**: Warp 中相鄰 threads 存取連續的 memory addresses。
### Shared Memory Bank Conflicts
Shared memory 劃分為多個 Banks。如果同一個 Warp 中的多個 threads 同時存取**相同的 Bank** (但不同地址),會發生衝突,導致請求被序列化處理。
**例外**: 多個 threads 讀取同一地址不會有衝突 (broadcast)。
SM 與 L1 cache 是用同個空間,可以用 `cudaFuncSetCacheConÞg` 來設定 L1 與 shared memory 的比例。
### Synchronization
* **`__syncthreads()`**: 在 **block 內**作為 **barrier**,確保 block 內所有 threads 到達此點
* **Atomic operations**: 如 `atomicAdd`,用於保護 critical section,確保能存取變數的 threads 中只有一個 thread 執行操作
* Host 與 Device 之間的同步: `cudaDeviceSynchronize()`、kernel 結束時。
## Unified Memory (UM)
一種更簡單的 memory 管理方式,CPU 和 GPU 可以存取相同的變數,使用 `cudaMallocManaged`。
CPU 或 GPU 存取時觸發 **page fault**,自動將 memory pages 遷移到存取它的 processor 上
**適用**: 存取模式**稀疏或不可預測**的情況。
### Asynchronous Prefetch
使用 `cudaMemPrefetchAsync` 可以在資料實際被需要之前,**非同步地**將 UM 資料塊遷移到 CPU 或 GPU memory 中,以**減少 page fault 和遷移 overhead**。
### Asynchronous Transfers
允許在 **GPU 執行 kernel 時,同時在 PCIe bus 上傳輸資料**。透過使用 **CUDA Streams** 和 `cudaMemcpyAsync` 實現,可有效利用通訊通道 (pipelining)。
## CUDA Streams
GPU 上的**操作序列**。不同 Streams 之間的操作可以**並行執行 (Concurrent)**。
**Default Stream** 比較特殊,會阻塞所有其他 Streams。
### Host/Device Synchronization
* **`cudaDeviceSynchronize()`**: CPU 等待**所有** GPU 操作完成
* **`cudaStreamSynchronize(stream)`**: 只等待**特定 Stream** 的操作完成
## GPU Dynamic Scheduling
**Hardware scheduler** 負責將 **Thread Blocks 動態地映射到 SMs**。系統假設 blocks 間沒有依賴性,可以**以任何順序執行**。
**NVIDIA 4090 SM**: 具有四個 **Warp schedulers**,可同時運行來自四個 Warps 的 instructions。每個 SM 可同時維護多達 **48 個 Warp 的 execution contexts**。
### Block Dependency 問題
雖然 blocks 可按**任何順序**執行,但若不同 blocks 存取 global memory 的**相同變數** (例如在 Histogram 範例中使用 `atomicAdd`),則必須確保執行順序不影響結果。
**程式設計師必須非常小心**,因為系統不保證 blocks 的執行順序。
## Barnes-Hut Algorithm (BH)
用於加速 N-body 模擬 (如星系演化) 的演算法。它將計算複雜度從 $O(N^2)$ 降低到 **$O(N \log N)$**,通過將遠處的粒子群組視為單一質量中心來近似計算引力。
### BH 挑戰與分解
* 每個粒子的**工作量是非均勻的**
* 粒子會移動,導致工作成本和通訊模式**隨時間變化**
* BH 使用 **Quad-tree (四元樹)** 來表示粒子空間分佈
### BH 負載平衡策略
採用 **Semi-static assignment (半靜態分配)**。根據每個粒子**先前計算的交互成本**,**週期性地重新分配**工作給 processors。這利用了粒子空間分佈緩慢演變的特性。
## Performance Evaluation
### Basic Metrics
* **Speedup**: $\text{Speedup} = \frac{\text{Execution time of sequential program}}{\text{Execution time on } P \text{ processors}}$
* **Efficiency**: Performance per unit resource (e.g., per watt, per dollar, per chip area).
> **Pitfall (常見陷阱)**:
> 算 Speedup 時,Baseline (分母) 必須是 **Fastest sequential algorithm on one core**,而不是把原本的 Parallel program 跑在一個 core 上。
> 因為 Parallel program 會有 synchronization/communication overhead,跑在單核上通常比純 sequential 版本慢,這樣算出來的 Speedup 會灌水 (unfair)。
### Scaling Constraints
設計系統或評估效能時,受限於問題規模與硬體資源的關係:
1. **Problem Constrained Scaling (PC)**
* **定義**: 固定 Problem size,目標是縮短執行時間 (Solve faster)。
* **場景**: 大部分課堂作業、批次處理。
* **問題**: 如果機器變大 ($P$ 增加) 但問題太小,Parallelism overhead 會蓋過好處。
2. **Time Constrained Scaling (TC)**
* **定義**: 固定執行時間,目標是做更多的事 (Do more work)。
* **場景**:
* **Real-time Gaming**: 每一幀必須在 16ms 內算完,顯卡變強通常是為了讓畫質更好 (更多 work),而不是讓 FPS 衝到幾千。
* **High-frequency Trading**: 必須在固定 latency 內完成決策。
3. **Memory Constrained Scaling (MC)**
* **定義**: 固定每個 Processor 的 Memory usage,目標是跑更大的 Problem size (Run largest problem possible)。
* **場景**: 科學運算 (N-body simulation)、大型 ML 模型訓練。
* 重點是把記憶體塞滿,避免 Thrashing (Swap to disk)。
## Roofline Model
用來視覺化與分析系統效能瓶頸的模型。
* **X 軸**: **Arithmetic Intensity** (FLOPS/Byte)
* 每從 Memory 搬運 1 Byte 資料進來,能做幾次運算。
* **Y 軸**: **Performance** (GFLOPS)
* **公式**: $P = \min(\pi, \beta \times I)$
* $\pi$: Peak Performance (硬體運算極限)
* $\beta$: Peak Bandwidth (記憶體頻寬極限)
* $I$: Arithmetic Intensity
### 兩個主要區域
1. **Memory Bound (Diagonal region)**
* 圖表的左半邊斜線區。
* $I \le \pi / \beta$
* 效能被 **Memory Bandwidth** 卡住。
* **Optimization**:
* Software Prefetching (隱藏 latency)
* 改善 Data Locality (如 loop fusion,增加 Cache hit rate,提升 effective $I$)
* NUMA optimization
2. **Compute Bound (Horizontal region)**
* 圖表的右半邊平坦區。
* $I > \pi / \beta$
* 效能被 **Compute capability** 卡住 (已達硬體極限)。
* **Optimization**: Parallelism
* ILP (Instruction Level Parallelism)
* SIMD/Vectorization
* FMA (Fused Multiply-Add)
* **Ridge Point**: 斜線轉平線的轉折點,代表達到 Peak performance 所需的最低 Arithmetic Intensity。
## Interconnection Networks
### 簡介
互連網路 (Interconnection Networks),也稱為**片上網路 (Networks-on-Chips, NoCs)**,是連接處理器節點的基礎設施。
**為什麼 NoC 很重要?**
* **系統可擴展性 (Scalability)**: 匯流排 (Bus) 式互連難以良好擴展(單一匯流排難以共享),而 NoC 易於擴展到大型系統,並可輕鬆添加新組件
* **系統性能**: 實現組件之間的**快速通訊**和**可管理延遲**
* **能源效率**: 相比匯流排,NoC 通常具有更低的能耗
### 核心術語
| 術語 | 定義 |
| :--- | :--- |
| **Node (節點)** | 連接到互連網路的組件,例如處理器、快取、記憶體等 |
| **Links (鏈路)** | 用於傳輸訊號的連接結構(例如電線) |
| **Switch/Router (交換器/路由器)** | 連接固定數量的輸入與輸出鏈路 |
| **Network interface** | 連接節點到網路的介面 |
| **Topology (拓撲)** | 交換器/路由器透過鏈路連接的方式;影響路由、吞吐量、延遲、複雜性和成本 |
| **Routing (路由)** | 訊息從源頭到目的地傳輸的方式;可以是**靜態路由**(預定義策略)或**動態路由**(基於流量負載調整) |
| **Flow control (流量控制)** | 管理網路流量和緩衝區空間的演算法 |
### 拓撲的屬性
| 屬性 | 定義 |
| :--- | :--- |
| **Routing distance (路由距離/跳數)** | 兩節點之間沿著路徑的鏈路數量 |
| **Diameter (直徑)** | 最大的路由距離 |
| **Average distance (平均距離)** | 所有有效路徑的平均路由距離 |
| **Bisection bandwidth (對分頻寬)** | 將網路切成兩半,計算所有被切斷鏈路的總頻寬,是衡量網路的常見指標 |
| **Blocking vs. Non-blocking (阻塞 vs. 非阻塞)** | 如果任意一對節點之間的通訊**總是可能**,則網路為非阻塞 (Non-blocking) |
### 網路類型
* **Direct Network (直接網路)**: 每個節點都有自己的交換器/路由器,節點**位於網路內部**
* **Indirect Network (間接網路)**: 節點**位於網路外部**
### 常見拓撲比較
| 拓撲 (Topology) | 類型 | 成本 (Cost) | 延遲 (Latency) | 特點與應用 |
| :--- | :--- | :--- | :--- | :--- |
| **Bus (匯流排)** | 直接 | 低 (小系統) | N/A | 爭用 (Contention) 高、頻寬有限、擴展性差 |
| **Crossbar (交叉開關)** | 間接 | $O(N^2)$ | $O(1)$ | 高頻寬、低延遲;難以擴展,成本高 |
| **Ring (環狀)** | 直接 | $O(N)$ | 高 | 簡單;對分頻寬不變,擴展性問題 |
| **Mesh (網格)** | 直接 | $O(N)$ | $O(\sqrt{N})$ | **優異的可擴展性**,易於晶片佈局 |
| **Torus (環面)** | 直接 | $O(N)$ | N/A | 結合 Mesh 和 Ring,有更多鏈路和路由選項;佈局複雜 |
| **Tree (樹狀)** | 間接 | N/A | $O(\log N)$ | 分層拓撲,用 **Fat tree** 緩解根節點頻寬瓶頸 |
| **Multi-Stage Network** | 間接 | $O(N\log N)$ | $O(\log N)$ | 阻塞網路 |
### 通訊粒度
* **Message (訊息)**: 節點間通訊的資訊,可由多個 Packet 組成
* **Packet (封包)**: 網路傳輸的單位,可由多個 Flit 組成
* **Flit (Flow Control Digit)**: 封包分解成的更小單位,是**鏈路傳輸的基本單元**,也是**緩衝和路由的最小粒度**
* 封包包含:**Header flit** (含路由資訊)、**Payload/Body flit** (主體)、**Tail flit** (含錯誤校正碼)
### 交換方法
* **Circuit Switching (電路交換)**: 在傳輸前建立發送方和接收方之間的**完整路徑**
* **優點**: 傳輸期間**無競爭**,高頻寬傳輸,不需緩衝
* **缺點**: 需要設置和釋放鏈路的開銷,可能導致**鏈路利用率低**
* **Packet Switching (封包交換)**: 針對**每個封包**做路由決策
* **優點**: 無需設置開銷,鏈路閒置時可被立即分配
### 流量控制方法
流量控制決定了如何管理網路中的流量和緩衝空間。
#### Flit (FLow control digIT)
NoC 使用的網路架構中,當一個封包要在網路中傳輸時,會被切成多個固定數量的 Flits:
* **Header flit**: 包含目的地位址和路由資訊,決定封包要往哪裡走
* **Body/Payload flits**: 實際要傳輸的資料內容
* **Tail flit**: 標記封包結束,可能包含錯誤檢查碼 (checksum)
這樣的設計讓 pipeline 的方式傳輸變得可能,進一步壓低延遲。
#### Store and Forward (儲存與轉發)
* **流程控制單元**: 整個**封包**
* **機制**: 封包必須在路由器中**完整複製**,然後才能轉發到下一節點
* **缺點**: **高延遲**。延遲隨著跳數 (number of hops) 線性增加
#### Cut-Through (直通式)
* **機制**: 交換器/路由器在**接收到封包 Header 後**,立即開始將資料轉發到下一鏈路
* **優點**: 顯著**降低延遲**
* **缺點**: 仍需要**緩衝整個封包**。如果輸出鏈路阻塞 (blocked),整個傳輸會**退化成 Store-and-Forward**
#### Wormhole (蟲孔式)
* **機制**: Body flits 跟隨 Header flit。如果 Header 停止,其餘 flits 也停止,形成**完全管線化 (pipelined)** 傳輸
* **優點**: **所需緩衝區數量較少**
* **總延遲**: 主要取決於單個 Flit 的傳輸時間和 Flit 總數
* **問題**: **Head of Line Blocking (隊頭阻塞)**: 當一個封包的 Header 被阻塞時,它佔用了路由器中的緩衝區,阻止了其他**可以通過**的封包。也有可能導致 deadlock。
#### Virtual Channel (虛擬通道, VC) 流量控制
* **目的**: 允許**不同的封包共享一個物理通道**,主要用於解決**隊頭阻塞 (Head of Line Blocking)**
* **機制**: 路由器的輸入緩衝區被劃分為多個 **虛擬通道 (VCs)**。如果一個 VC 中的 Flits 被阻塞,其他 VC 仍然可以使用共享鏈路傳輸 Flits
* **裁決**: 使用 **Virtual Channel Arbiter** 來決定哪個 VC 可以使用共享鏈路
* **優勢**:
* **避免死結 (Deadlock avoidance)**: 可用於打破資源的**循環依賴**
* **流量優先級 (Prioritization)**: 某些 VC 可以設定更高的優先級,提供服務品質 (QoS) 保證
一個 Link 一次還是只能走一個 Flit,VC 只是解決了 Head-of-Line Blocking、deadlock。
### 現代路由器管線
現代 NoC 路由器由多個組件構成,包括輸入緩衝區(劃分為 VCs)、**Crossbar Switch**、**VC Allocator** 和 **Switch Allocator**。
標準的**五級路由器管線 (Five-stage router pipeline)** 階段:
1. **BW** (Buffer Write, 緩衝區寫入)
2. **RC** (Route Calculation, 路由計算)
3. **VA** (VC Allocation, VC 分配)
4. **SA** (Switch Allocation, 交換器分配)
5. **ST** (Switch Traversal, 交換器穿越)