Skip to content

perf: avoid redoing pointer, scan, and lookup work - #3

Merged
whes1015 merged 2 commits into
mainfrom
perf/simplify-hot-paths
Oct 20, 2026
Merged

whes1015 merged 2 commits into
mainfrom
perf/simplify-hot-paths

Conversation

@whes1015

@whes1015 whes1015 commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

這個 PR 做了什麼

指標移動、統計數字和目錄掃描都在重複做同一份工作。這個 PR 把那些重複拿掉,目錄掃描改成一次讀完整個目錄的 metadata。

指標光暈與工具提示不再讓整頁 reconcile,統計數字只改文字節點(src/components/CursorGlow.tsx、src/components/StatsDisplay.tsx)。深度顏色是預先算好的表,檔案類型是啟動時建好的 Map(src/lib/fileTypeUtils.ts)。拿掉沒用到的 recharts、d3-shape、i18next-resources-to-backend、walkdir、lazy_static、filesize。serde_json 留著,因為 Tauri 需要它。

這次 commit(e627a8d)的正式程式碼:

  • src-tauri/src/scan/:根目錄只 canonicalize 一次。macOS 用 getattrlistbulk,Linux 用 getdents64 加 statx,Windows 用 FindFirstFileExW(壓縮或稀疏檔再問壓縮後大小)。macOS 與 Linux 的子目錄用父目錄的 fd openat。只有 symlink 會再查一次,用來判斷目標在不在掃描根裡面。
  • 樹是 arena(scan/tree.rs):一個 node Vec、一段名字、一張子節點索引表。送給 webview 的是平行陣列 n、s、m、k、r,不再是一檔一個 JSON 物件。
  • src/app/analyze/page.tsx 的 unpackForest 把那些陣列組回原本的樹。
  • src-tauri/src/main.rs 的掃描命令改為呼叫這個模組。刪除前的大小計算走同一套掃描。

測試在 scan/mod.rs,不進正式程式碼:硬連結只算一次、symlink、目錄循環、寬目錄,以及 macOS 上 bulk 讀取與 lstat / fstatat 一致。量測用的暫時測試沒有留在這個 commit。

速度是在這台 Mac(Apple M4 Max)上,release 對 release 量的。目前 release 是 origin/main(1015673),新的是上面這個 commit。兩邊都用 cargo test --release 編譯。先暖機一次,再記多次,取中位數。計時的是 scan_directory_streaming 背景執行緒做的那一段:走完整棵樹,並把批次送到一個空的 channel。空的 callback 仍會讓 Tauri 把批次 serde 成 JSON,沒有真的送進 webview。

node_modules(三批、暖機後共 17 次):

  • 目前 release 中位數 574 ms(三批中位數 596、567、570 ms;全部落在 553–599 ms)
  • 這個分支中位數 24.3 ms(三批中位數 22.3、24.0、26.3 ms;全部落在 21.5–27.4 ms)
  • 24.3 ms 對 574 ms 是 23.6 倍,時間少 95.8%

src(各 11 次):

  • 目前 release 中位數 0.638 ms(0.589–0.711 ms)
  • 這個分支中位數 0.135 ms(0.116–0.147 ms)
  • 4.7 倍,時間少 78.8%
  • 兩邊都是 26 項、184320 bytes

node_modules 的總數不一樣:

  • 新的每次都是 19964 項、472494080 bytes,和 find node_modules 的 19964 筆相同
  • 目前 release 每次都是 19957 項,bytes 在 472449024 到 472473600 之間晃
  • 少掉的 7 項是 node_modules/.bin 的 7 個 symlink(next、jiti、tsserver、nanoid、tauri、tsc、semver)。舊版用 fs::metadata,會跟著連結走;目標 inode 已經計過,這個名字就不再計。新版用 lstat,連結自己的 inode 另外計

這次沒有做、留給審查的:

  • 非 symlink 在父目錄已經 canonicalize 之後不再 realpath(src-tauri/src/scan/mod.rs 的 plan_entries)
  • Windows 與 Linux 這次沒有編譯。Windows 不再依賴 filesize,配置大小改在 scan/platform/windows.rs 裡算
  • 沒有開 Tauri 視窗看掃描畫面

相關 issue

沒有對應的 issue。

怎麼驗

  • cargo test --release --bin storviz:11 項通過
  • 速度的量法、目錄、次數與總數差,寫在上一節。量測程式已從 commit 拿掉
  • 尚未開 Tauri 視窗,用介面選目錄掃一次
  • 尚未在 Windows 或 Linux 上編譯

檢查清單

  • tool/check/commits.sh origin/main..HEAD 通過 —— 不適用。StorViz 沒有這支腳本,也沒有 DPIP 的 commit gate。這個 repo 的訊息是 type: summary,後面加一兩句原因
  • 一個 commit 一件事。掃描重寫是 e627a8d;指標光暈、顏色表、檔案類型是已在分支上的 45cebcb
  • mise exec -- flutter analyze 與 mise exec -- flutter test 通過 —— 不適用,這是 Tauri + Next,沒有 Flutter。代替的是上面的 cargo test --release,11 項通過
  • 新的使用者可見字串都走 AppLocalizations,沒有寫死 —— 不適用。沒有新增使用者可見字串;這個專案用 i18next
  • CI 全部通過(gh pr checks:每一項都是 pass 或 skipped)—— 這次 commit 剛推上去,檢查還沒有結果,現在不勾
  • 有 UI 變更的話:用的是 AppSpacing / AppRadius / AppMotion,深色模式看過,文字對比度可接受 —— 不適用。這次 commit 只改掃描結果的解析,沒有改間距或配色,也沒有開視窗看

Pointer movement was re-rendering the page, scans repeated canonicalize and stat calls, and colors and file types were recomputed per item.
Per-entry canonicalize and stat calls dominated scanning. Bulk attributes and a flat arena remove that repeated work.
@whes1015 whes1015 mentioned this pull request Oct 20, 2026
2 of 6 tasks
@whes1015
whes1015 merged commit 615b938 into main Oct 20, 2026
7 checks passed
@whes1015
whes1015 deleted the perf/simplify-hot-paths branch October 20, 2026 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant