Auto Upload Agent commited on
Commit
833ef4d
·
1 Parent(s): 84fbb3b

v9: STATUS/README 補上 SSD 讀取能力與實測成果

Browse files
Files changed (2) hide show
  1. README.md +10 -0
  2. STATUS.md +14 -2
README.md CHANGED
@@ -14,6 +14,16 @@ ST_RAM_BUDGET_MB=512 ./llama_server.sh # 手動壓低 RAM 預算做實驗
14
 
15
  進度真相來源:[STATUS.md](STATUS.md)。續作指引:[AGENTS.md](AGENTS.md)。
16
 
 
 
 
 
 
 
 
 
 
 
17
  ## 檔案
18
 
19
  | 檔案 | 用途 |
 
14
 
15
  進度真相來源:[STATUS.md](STATUS.md)。續作指引:[AGENTS.md](AGENTS.md)。
16
 
17
+ ## 實測成果
18
+
19
+ | 設定 | peak 總 RSS | swap | 冷權重 SSD 重讀 | 輸出 |
20
+ | --- | --- | --- | --- | --- |
21
+ | 上游行為(`ST_PAGER=0`) | 2.564 GiB | 0 | — | 基準 |
22
+ | 預算 512 MiB | **0.833 GiB** | 0 | 2315 MiB | **逐字相同** |
23
+ | 預算 256 MiB | **0.601 GiB** | 0 | 2320 MiB | **逐字相同** |
24
+
25
+ 證據:`validate/ab-test.json`(`all_passed: true`)與 `validate/last-run.json`。
26
+
27
  ## 檔案
28
 
29
  | 檔案 | 用途 |
STATUS.md CHANGED
@@ -96,6 +96,16 @@ expert 維度是最外層):
96
  取捨很清楚:**放棄 I/O 預取,換取「計算路徑完全沒動過」的保證。**
97
  模型只有 2.45 GiB、SSD 讀取 300+ MB/s,demand paging 的penalty 可接受。
98
 
 
 
 
 
 
 
 
 
 
 
99
  ## 踩過的坑(全部有實測證據,不要重蹈)
100
 
101
  | 坑 | 真相 | 怎麼知道的 |
@@ -110,11 +120,13 @@ expert 維度是最外層):
110
  | **`nb[2] != ne[0]*nb[0]` 檢查會誤判量化張量** | 量化張量 `nb[0]` 是**一個 block** 的位元組數,不是 1。只要檢查 `nb[2] == ne[1]*nb[1]` | 「layer 0 不連續」誤報 |
111
  | **第一輪 sweep 永遠什麼都不做** | 條件寫成 `last_used < now - hot_tokens`,第一輪時門檻是 0 而 `last_used` 也是 0,`0 < 0` 為假 | sweep 計數有跳、但 resident 不降 |
112
  | **拿 layer 0 的 `nb[2]` 當全模型常數** | `down_exps` 逐層量化型別不同(實測 layer 4 是 Q4_K、layer 0 是 Q6_K) | 「layer 4 part 2 形狀不一致」 |
 
113
  | **外部取樣 RSS 抓不到 decode 階段** | 一次 generation 的樣本數太少。改由**行程自己**在 sweep 裡讀 `/proc/self/status` | 兩邊數字對不起來時才發現 |
114
 
115
- (本專案被「量測方式/語意/時序」教訓共 5 次:① 只看外部 peak RSS
116
  ② 讀 `/proc/self/io` 的格式錯 ③ 在行程退出後才讀它 ④ 把 prefetch 語意寫反
117
- ⑤ 分層時把「有打算分頁」和「已註冊分頁」混為一談。
 
118
  共同特徵都是「看起來有在做事,但量錯了地方」。每次都是靠實測抓到的。)
119
 
120
  ,不要重蹈)
 
96
  取捨很清楚:**放棄 I/O 預取,換取「計算路徑完全沒動過」的保證。**
97
  模型只有 2.45 GiB、SSD 讀取 300+ MB/s,demand paging 的penalty 可接受。
98
 
99
+ ## 本機 SSD 讀取能力(實測,`validate/io-probe.json`)
100
+
101
+ | threads | 1 | 2 | 4 | 8 |
102
+ | --- | --- | --- | --- | --- |
103
+ | 循序讀取 | 337 MB/s | 667 MB/s | 1328 MB/s | 2558 MB/s |
104
+
105
+ 4K 隨機讀 ≈ 1767 IOPS。檔案系統是 **overlayfs**。
106
+ 單執行緒 337 MB/s 是「每個 decode step 重讀 4 experts × 32 層」這個負載的基準,
107
+ SSD 讀取頻寬是本模型 decode 速度的主要上限。
108
+
109
  ## 踩過的坑(全部有實測證據,不要重蹈)
110
 
111
  | 坑 | 真相 | 怎麼知道的 |
 
120
  | **`nb[2] != ne[0]*nb[0]` 檢查會誤判量化張量** | 量化張量 `nb[0]` 是**一個 block** 的位元組數,不是 1。只要檢查 `nb[2] == ne[1]*nb[1]` | 「layer 0 不連續」誤報 |
121
  | **第一輪 sweep 永遠什麼都不做** | 條件寫成 `last_used < now - hot_tokens`,第一輪時門檻是 0 而 `last_used` 也是 0,`0 < 0` 為假 | sweep 計數有跳、但 resident 不降 |
122
  | **拿 layer 0 的 `nb[2]` 當全模型常數** | `down_exps` 逐層量化型別不同(實測 layer 4 是 Q4_K、layer 0 是 Q6_K) | 「layer 4 part 2 形狀不一致」 |
123
+ | **`os.pread()` 回傳資料本身,不是讀到的位元組數** | 寫成 `got += n` 會得到 `TypeError: int + bytes`,而**執行緒裡的例外不會讓主程式失敗** → `io_probe` 印出 `bytes: 0、0.015 秒、0.0 MB/s`,看起來像「SSD 完全沒速度」 | `bytes: 0` 搭配「只花 15 ms」這個不合理組合才察覺 |
124
  | **外部取樣 RSS 抓不到 decode 階段** | 一次 generation 的樣本數太少。改由**行程自己**在 sweep 裡讀 `/proc/self/status` | 兩邊數字對不起來時才發現 |
125
 
126
+ (本專案被「量測方式/語意/時序」教訓共 6 次:① 只看外部取樣的 RSS
127
  ② 讀 `/proc/self/io` 的格式錯 ③ 在行程退出後才讀它 ④ 把 prefetch 語意寫反
128
+ ⑤ 分層時把「有打算分頁」和「已註冊分頁」混為一談 ⑥ 在執行緒裡把 `pread` 的
129
+ 回傳值當成位元組數,例外被吞掉後看起來像「量到 0」。
130
  共同特徵都是「看起來有在做事,但量錯了地方」。每次都是靠實測抓到的。)
131
 
132
  ,不要重蹈)