iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Software Development

從 C++ 菜鳥到 Low-Latency 勇者:一場分秒必爭的賽局系列 第 7

[Day 7] Hardware-Aware Memory & CPU Architecture: Machine Code

  • 分享至 

  • xImage
  •  

在一般的 C++ 開發中,我們往往習慣從 source code 的角度思考問題:

  • 這個 class 的 interface 是否設計得好?
  • 這個 abstraction 是否容易使用?
  • std::vectorstd::unordered_map 或其他 container 是否適合?
  • 這個 function 是否需要 inline
  • 是否應該使用 unique_ptr、reference 或 value?
  • 這段 code 是否足夠 clean?

但在 Low-Latency C++ 的世界裡,這些問題通常只是第一層。因為真正決定 latency 的並不是 C++ source code 本身,而是 compiler 將其轉換成什麼樣的 machine code,以及 CPU 如何執行這些 machine code。

1. 從 C++ Source Code 走到 Machine Code

在 Low-Latency C++ 中,我們不能只看 source code,更要了解其底層的概念。以下會舉一些簡化後的範例,實際過程有哪些 load、store、register movement 以及最終的 instruction sequence,則取決於 compiler 的 code generation、optimization、target architecture 等因素。

例如 processor.process(order); 看起來只有短短一行 function call,但 compiler 最後可能產生情況 1:
load  // 找到 processor
 ↓
load  // 找到 order
 ↓
call   // 跳去執行 process()

而若 process() 原本是:

void process(Order order) {
    if (order.price > 100) {
        order.total += 10;
    }
}

由於 process() 很小,而且 compiler 在當前編譯條件下可以看到其 implementation,compiler 可能會將這個 function inline。也就是將其運算邏輯直接整合到 call site,而不再需要實際的 function call:

if (order.price > 100) {
    order.total += 10;
}

接著 compiler 再做 optimization,流程可能接近情況 2:
load    // 讀 price
 ↓
cmp     // 比較
 ↓
branch  // 根據結果決定是否要執行
 ↓
add     // 計算

甚至當 compiler 能證明這個 function 實際上只是:

order.total = order.price + order.tax;

那表示 abstraction 可以在 compile time 被消除,情況 3 之下 CPU 可能將這段程式降低成非常少量的 machine instructions:
load   // 讀 price
 ↓
add    // 加上 tax
 ↓
store  // 把結果寫回 total

上訴例子可以看出,source code 中存在的 abstraction boundary,不一定會存在於最終 machine code 中。而在 low-latency optimization 中,不應該把 inline 關鍵字當成效能保證。真正重要的是 compiler 最後產生了什麼 code,這也是為什麼理解 assembly、compiler optimization、branch prediction、cache hierarchy,對 Low-Latency C++ 的開發非常重要。

2. 一個更完整的 Mental Model

到這裡,我們可以建立一個比較完整的 Low-Latency C++ mental model,其中每一層都可能影響程式效能:
Algorithm
    ↓
Data Structure / Abstraction
    ↓
Memory Layout
    ↓
Allocation / Lifetime
    ↓
Compiler Optimization
    ↓
Generated Machine Code
    ↓
Instruction Set Architecture (ISA)
    ↓
CPU Microarchitecture
    ├── Pipeline
    ├── Branch Prediction
    ├── Out-of-Order Execution
    ├── Cache Hierarchy
    └── Memory Ordering
    ↓
Observed Latency
    ↓
Latency Distribution

如同之前反覆強調的觀念,低延遲系統最關心的並不只是平均 latency,而是整個 latency distribution 甚至更高 percentile 的 tail latency。即使平均值看似非常漂亮,仍然要避免少數 request 因為 cache miss、branch misprediction、memory stall、context switch 或其他 microarchitectural event 而突然變慢。

當 algorithm、data structure、allocation、memory layout 等較高層次因素都已經被最佳化後,下一步就需要理解 CPU microarchitecture 如何執行 compiler 產生的 machine code。此時就會進入 Low-Latency C++ 的下一個階段 —— Branch Prediction、Instruction Pipeline、Out-of-Order Execution、CPU Cache Hierarchy 以及 Memory Ordering。


上一篇
[Day 6] 進度存檔 | Low-Latency 新手村冒險日誌
下一篇
[Day 8] Hardware-Aware Memory & CPU Architecture: Machine Code II
系列文
從 C++ 菜鳥到 Low-Latency 勇者:一場分秒必爭的賽局8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言