執行人: willy-liu
專題解說影片
BitNet b1.58 的運行效率極高。在 Apple M2 這類通用 CPU 上可達 29 毫秒延遲,且記憶體佔用僅為 0.4GB,遠小於例如 Gemma 3 1B 所需的 1.4GB。微軟團隊在基準測試中將其與 Llama 3.2 1B、Gemma 3 1B 與 Qwen 2.5 1.5B 等全精度模型對比,發現 BitNet 即使在參數較少、權重精度較低的情況下,仍能在 MMLU、GSM8K、MATH 等任務中維持穩定表現,並在 GSM8K 上奪得最佳成績。BitNet 於 30 億參數以上的規模下,其性能已能接近 FP16 模型,並於 70 億參數規模達成高達 4 倍的推理速度提升與 7 倍的記憶體節省,顯示此技術具備高度擴展潛力。
本任務嘗試運用 Linux 核心提供的效能分析工具,定位出 BitNet 運行時期的效能瓶頸,歸納出推理過程中的程式熱點並予以分析
BitNet是微軟研究院與中國科學院研究人員在2023年發表的一個 1-bit transformers for LLM 架構,原生訓練純二值(1‑bit,權重僅為 ±1)BitLinear 模組,和其他研究不同,BitNet是原生用 1 Bit 從頭訓練,而不是先訓練全精度再量化,目標是達到與 FP16/FP32 Transformers 相當的效能,同時顯著減少記憶體佔用與能源消耗。
在 2024 年 2 月,團隊進一步提出 BitNet b1.58 2B4T 模型,使用1.58-bit權重量化(即三值 {-1, 0, +1})與8-bit激活值(float32->int8)方案,在2B參數規模、4兆token語料上從零訓練,效能可與同級全精度開源模型媲美,同時支援將訓練好的模型在bitnet.cpp(llama.cpp)框架等進行高效CPU/GPU推理;可以用在更輕量的平台。
(p.s. 累加和矩陣運算仍以 int32 或 float32 處理,這樣能兼顧訓練精度與推理速度。)
運用 Linux 核心提供的效能分析工具,如 perf,也搭配 uftrace 一類使用者層級的工具,歸納出推理過程中的程式熱點並予以分析
參考其他人的實驗:
實驗方向
分析程式的熱點函式
| 佔比(%) | 函式名稱 | 所屬模組 | 推測用途與說明 | 
|---|---|---|---|
| 54.33% | ggml_vec_dot_i2_i8_s | 
libggml.so | 
量化矩陣乘法核心:針對 i2/i8 格式做向量內積運算,加速推論;通常為低精度 INT2/INT8 的權重乘法。 | 
| 36.03% | ggml_vec_dot_f16 | 
libggml.so | 
向量內積(半精度):FP16 格式的內積操作,是未量化模型的基礎乘法核心。 | 
| 26.41% | _start → main → llama_decode | 
llama-cli | 
主要執行流程:程式從主函式 main 開始,呼叫 LLaMA 解碼(推論)流程。 | 
| 25.92% | llama_decode_internal | 
libllama.so | 
核心推論邏輯:負責 LLaMA 模型解碼,包括 token-by-token 的預測計算。 | 
| 17.98% | ggml_graph_compute_thread | 
libggml.so | 
背景執行緒:處理計算圖執行的多執行緒核心。 | 
| 1.74% | ggml_vec_dot_i2_i8_s(其他執行緒) | 
libggml.so | 
同上,分佈在其他 thread 中。 | 
| 0.75% | ggml_barrier | 
libggml.so | 
執行緒同步點:等待所有執行緒完成,類似 barrier 的功能。 | 
| 0.74% | quantize_row_i8_s | 
libggml.so | 
量化處理:將浮點資料轉換為 INT8 表示,通常在加速部署時使用。 | 
火焰圖
函式用途分類
| 分類 | 函式(代表) | 說明 | 
|---|---|---|
| 矩陣/內積計算 | ggml_vec_dot_i2_i8_s, ggml_vec_dot_f16 | 
是整個模型計算的最核心部分(矩陣乘法的 dot product)。 | 
| 矩陣乘法流程 | ggml_compute_forward_mul_mat, ggml_compute_forward_mul_mat_one_chunk | 
表示計算圖中 forward pass 的一部分,針對不同區塊處理矩陣乘法。 | 
| 模型執行主體 | llama_decode_internal, llama_graph_compute | 
控制推論 token 的運作流程、計算圖排程等。 | 
| 排程與執行緒 | ggml_graph_compute_thread, ggml_graph_compute_secondary_thread, ggml_backend_sched_* | 
代表 GGML 用來安排 CPU 多執行緒運算的排程與背景執行邏輯。 | 
| 同步與量化 | ggml_barrier, quantize_row_i8_s | 
在前後處理中同步各 thread,或處理資料格式轉換。 | 
整體效能指標
| 項目 | 數值 | 解釋與分析 | 
|---|---|---|
cycles | 
337,403,155,184 | CPU 時鐘週期數,越多表示執行時間越長。 | 
instructions | 
375,024,850,451 | 指令數量,代表總共執行的 CPU 指令。 | 
insn per cycle (IPC) | 
1.11 | 每 cycle 執行 1.11 條指令, 理想值越高越好,通常 > 1 表示 CPU 沒有完全被 memory 拖慢。  | 
time elapsed | 
16.46 秒(wall clock) | 真實執行時間。注意和下方 user/sys 是不同角度。 | 
user time | 
84.49 秒 | 表示使用者空間總 CPU 使用時間, 多執行緒程式會大於實際時間(共用 CPU 核心)。  | 
sys time | 
0.27 秒 | 核心空間(系統呼叫)耗費的時間,低代表系統開銷小。 | 
快取
| 項目 | 數值 | 解釋與分析 | 
|---|---|---|
cache-references | 
6.13B | Cache 存取次數。高代表 CPU 積極使用快取。 | 
cache-misses | 
1.68B | Cache miss 數量,越高代表從 RAM 讀取次數多。 | 
| cache miss ratio | 27.37% | 高達 27% → 快取命中率差,效能可能受限於記憶體存取延遲。可能是模型參數太大或資料存取模式不佳。 | 
TLB(Translation Lookaside Buffer)
| 項目 | 數值 | 解釋 | 
|---|---|---|
dTLB-loads | 
155B | data TLB 存取次數 | 
dTLB-load-misses | 
19M(0.01%) | 幾乎沒有 miss,代表資料分頁效率很好 | 
iTLB-loads | 
7.59M | instruction TLB 存取次數 | 
iTLB-load-misses | 
1.05M(13.89%) | iTLB miss 比例偏高 → 程式碼/指令分布廣、跳躍多,可能影響效能(常見於大型模型推論) | 
效能比較
| 項目 | ❌ 預設 | ✅ 開啟 THP | ✅ THP + 綁定核心taskset -c 0-5 | 
|---|---|---|---|
time elapsed(秒) | 
16.46 | 15.64 | 15.53 | 
instructions | 
375.02B | 373.47B | 373.01B | 
cycles | 
337.4B | 324.7B | 320.1B | 
IPC | 
1.11 | 1.15 | 1.17 | 
cache-miss ratio | 
27.37% | 27.86% | 28.17% | 
iTLB-load-misses | 
1.05M | 0.64M | 0.97M | 
iTLB miss rate | 
13.89% | 13.30% | 18.84% 🔺 | 
使用uftrace前,要重新 make 專案,並加入
修改./setup_env.py
再重新編譯
python setup_env.py -md models/BitNet-b1.58-2B-4T -q i2_s
執行結果
熱點分析
| # | Function 名稱 | 呼叫次數 | 總時間 | 主要功能說明 | 
|---|---|---|---|---|
| 1 | ggml_vec_dot_i2_i8_s | 
~37M | 40.35s | INT2xINT8 量化矩陣乘法 dot product | 
| 2 | ggml_vec_dot_f16 | 
~11.7M | 18.87s | float16 dot product,應為主推理路徑 | 
| 3 | ggml_compute_forward_mul_mat_one_chunk | 
~715K | 6.46s | 單一 chunk 的矩陣乘法計算 | 
| 4 | ggml_barrier | 
~424K | 20.05s | 執行緒同步,thread barrier | 
| 5 | ggml_graph_compute_thread | 
306 次 | 85.57ms | 主要 graph 計算執行緒 | 
| 6 | ggml_graph_compute_secondary_thread | 
10 次 | 119μs | 次要執行緒調度 | 
| 7 | ggml_thread_cpu_relax | 
~219M | 23.36s | idle 等待同步,表示有大量同步等待時間 | 
| 8 | llama_decode | 
102 次 | 41.93s | 單一 token 的推理過程 | 
| 9 | llama_decode_internal | 
51 次 | 20.97s | llama_decode 的核心實作 | 
| 10 | std::map::emplace 等 STL | 
- | 10s+ | token 對應、編碼解碼查表等 | 
主要耗時在: