分析軟體複雜度的 Cyclomatic complexity

在「decomplexification continued」這邊看到很久前有讀過,但已經忘記又重新看到的東西:「Cyclomatic complexity」。

cURL 這邊拿來當作目標,但看起來應該不是直接 optimize 這個指標,而是透過這個指標來找哪些 function 過於複雜的問題 (這邊有個經典的 Goodhart's law 可以參考)。

去年開始看 Cyclomatic complexity 的時候有超過 100 的 function:

In May 2025 I had just managed to get the worst function in curl down to complexity 100, and the average score of all curl production source code (179,000 lines of code) was at 20.8. We had 15 functions still scoring over 70.

十個月的努力,最大的降到 59,然後平均也降下來了:

Almost ten months later we have reduced the most complex function in curl from 100 to 59. Meaning that we have simplified a vast number of functions. Done by splitting them up into smaller pieces and by refactoring logic. Reviewed by humans, verified by lots of test cases, checked by analyzers and fuzzers,

The current 171,000 lines of code now has an average complexity of 15.9.

翻了一下好像可以掛到 CI 裡面去過濾真的太大的 function?

Meta 的 jemalloc 宣言

Lobsters 上看到「Investing in Infrastructure: Meta’s Renewed Commitment to jemalloc」這篇,這讓我馬上想到 Jason Evans (就是發明 jemalloc 的人,je 取自他的名字縮寫) 在去年寫的「jemalloc Postmortem」這篇,文章最後提到 Meta 的制度設計使得不會有資源投入 jemalloc。

不確定是有什麼變化,目前比較成熟的領先群應該是 mimalloc,最近記憶體變得很貴...?這好像有點牽強...

找到 Meta 文章署名的三個人的 LinkedIn

看完後還是沒看到比較明顯的脈絡,就突然冒出來說要繼續投入...

GitHub Copilot CLI 突然從 0.0.423 進到 1.0.2 了

剛剛更新的時候發現 GitHub Copilot CLI 突然從 0.0.423 進到 1.0.2 了:「https://github.com/github/copilot-cli/releases/tag/v1.0.2」。

最近一直在測不同的 coding agent 與 model,GitHub Copilot CLI 的計價方式與其他人不太一樣,是算 premium requests 的 quota,而不是看 token 的數量,所以如果可以一包講多一點讓他一次處理的話,就會比較省... (?)

另外一個特點是 GitHub Copilot CLI 的 model 支援的蠻多的,目前是這些,後面的倍數表示 premium requests 消化的速度:

  Claude Sonnet 4.6 (default)         1x
  Claude Sonnet 4.5                   1x
  Claude Haiku 4.5                 0.33x
  Claude Opus 4.6 ✓                   3x
  Claude Opus 4.5                     3x
  Claude Sonnet 4                     1x
  Gemini 3 Pro (Preview)              1x
  GPT-5.3-Codex                       1x
  GPT-5.2-Codex                       1x
  GPT-5.2                             1x
  GPT-5.1-Codex-Max                   1x
  GPT-5.1-Codex                       1x
  GPT-5.1                             1x
  GPT-5.1-Codex-Mini (Preview)     0.33x
  GPT-5 mini                          0x
  GPT-4.1                             0x

剛好幾家大的都有支援,包括 AnthropicClaude 系列,GoogleGemini 系列,以及 OpenAI 的各種 model。

另外還有不用錢的 GPT-5 mini 與 GPT-4.1,不過實際在 coding agent 幫不到什麼忙...

macOS 上用 sandbox-exec 隔離

上上禮拜看到「sandbox-exec: macOS's Little-Known Command-Line Sandboxing Tool (via)」這個感到興趣,主要是因為有跑 coding agent 的需求,在 Linux 上可以透過 bubblewrap 隔離 (參考「Linux 下用 bubblewrap (bwrap) 跑 Claude Code」),但 macOS 上沒有 bubblewrap,所以需要另外找工具,看起來就是這個了。

Hacker News 上有人提到 deprecated 的問題,從 2017 年就已經是 deprecated 了,但實際上大家還是繼續用得很兇,尤其是各家 coding agent 還是會 sandbox-exec:

The sandbox-exec command is DEPRECATED. Developers who wish to sandbox an app should instead adopt the App Sandbox feature described in the App Sandbox Design Guide.

另外語法上懶得另外再重頭寫,就請 coding agent 翻譯 bwrap 的版本,轉成 macOS 上的版本,另外包括路徑的對應也請 coding agent 一起轉,第一次跑起來有遇到一些錯誤訊息,把錯誤訊息丟回去給 coding agent 修正後看起來就沒什麼太大的問題了。

另外這邊提到的 App Sandbox Design Guide,查了一下看起來跟 sandbox-exec 很不一樣,能處理的東西也差很多,不算是替代品,看起來還是得窩在 sandbox-exec。

Firefox 上大約有 10% 的 crash 是出自記憶體的 bit flip

Firefoxtelemetry 分析的,出自 https://mas.to/@gabrielesvelto/116171750653898304 (via) 這邊:

這讓我想到一般桌機的 ECC memory 還是沒有普及:CPU 的部分,AMD 這幾代都有支援了,但 Intel 沒給,查了一下發現 Linus 在 2021 年的時候就幹剿過 Intel 的這塊了:「Linus Torvalds On The Importance Of ECC RAM, Calls Out Intel's "Bad Policies" Over ECC」。

主機板的部分也得挑有支援的,看起來不算很多,但還不到市場上買不到的程度。

ECH 變成 Standards Track 了

看到 ECH 變成 Standards Track 了:「RFC 9849 TLS Encrypted Client Hello (via)」。

瀏覽器都在 2023 的下半年預設啟用了 (Firefox 119 是 2023/10/24,Chromium 117 是 2023/09/12)。

ECH is enabled in Firefox by default since version 119, and is recommended by Mozilla to be used along with DNS over HTTPS. In September 2023, Chromium version 117 (used in Google Chrome, Microsoft Edge, Samsung Internet, and Opera) enabled it by default, also requiring keys to be deployed in HTTPS resource records in DNS.

而 server 端看起來最近也都支援了:nginx 的「Encrypted Client Hello Comes to NGINX」、Caddy 的「Automatic HTTPS」。

這個算是基礎建設,再降低可被偵測到的部分。從 ESNI 走到 ECH 這樣也五六年了:

直接用 uBlock Origin 做 Always Active Window 的效果

本來是用 Always active Window (Always Visible) 這個套件,但發現常常失效,結果在 review page 上看到有人用 uBlock Origin 做到:

這邊的 aeld 其實是出自 Resources Library 的功能 addEventListener-defuser.js

Prevents attaching event listeners.

這邊要 apply 到所有站台的話可以用 *,所以會是這樣:

*##+js(aeld, /blur|visibilitychange/)

/blur|focus|afterblur|mousemove|visibilitychange/ 擋下去感覺有不少網站掛掉,先擋這兩個看起來還夠用,另外進階語法可以指定 html 元素,之後也可以參考。

Chromium 處理 CSS 的 Use after free 問題,可 RCE (CVE-2026-2441)

在「Stable Channel Update for Desktop (via)」這邊看到 Chromium 處理 CSSUse after free 問題:「CVE-2026-2441」。

Chromium 這邊沒有提太多,反而是在 CVE 這邊有多寫一些,有提到可以 RCE

Use after free in CSS in Google Chrome prior to 145.0.7632.75 allowed a remote attacker to execute arbitrary code inside a sandbox via a crafted HTML page. (Chromium security severity: High)

少見的 CSS 打穿... 雖然細節沒講,但因為 open source 的關係,diff 已經先釋出了,從 145.0.7632.67..145.0.7632.76 這包可以看到跟 WebGPU 有關,在 63f3cb4864c64c677cd60c76c8cb49d37d08319c 這邊可以看到是跟 font 相關的功能。

等後續的文章分析...

不使用 .gitkeep 的方式

看到「Git: Don’t create .gitkeep files, use .gitignore instead (via)」這篇在講不要用 .gitkeep 的方式維持空目錄的存在,直接用 .gitignore 就可以了,文章裡面是提到這個方式:

*
!.gitignore

不過 Hacker News 上的討論有不少看點,第一個是當初在「
How to .gitignore all files/folder in a folder, but not the folder itself?」這篇提出 .gitkeep 的作者也跑來道歉:

I'm not sure if I'm the one to blame for this or not, but the earliest reference to ".gitkeep" I can find online is my 2010 answer on Stack Overflow: https://stackoverflow.com/a/4250082/28422

If this is all my fault, I'm sorry.

第二個是有更乾淨的作法,直接在 foo/ 裡面放 .gitignore

*

然後用 git add -f foo/.gitignore 強制 Git 加進去就可以了,這是因為加入後就不受 .gitignore 限制,所以只要透過 -f 加入即可:

A gitignore file specifies intentionally untracked files that Git should ignore. Files already tracked by Git are not affected; see the NOTES below for details.

MariaDB 12.3 對 InnoDB 的大改進

看到 Mark Callaghan 寫的「MariaDB innovation: binlog_storage_engine」、「MariaDB innovation: binlog_storage_engine, small server, Insert Benchmark」這篇,裡面提到了 MariaDB 12.3 (還沒 GA) 的 InnoDB 改了很底層的架構,從本來的 binlog + InnoDB 的架構整合到只有 InnoDB,連帶也降低了 fsync 呼叫的次數:

MariaDB 12.3 has a new feature enabled by the option binlog_storage_engine. When enabled it uses InnoDB instead of raw files to store the binlog. A big benefit from this is reducing the number of fsync calls per commit from 2 to 1 because it reduces the number of resource managers from 2 (binlog, InnoDB) to 1 (InnoDB).

這個是 MySQL InnoDB 架構上很久的問題,binlog 與 InnoDB 本身兩次的寫入會需要呼叫兩次 fsync,而 fsync 本身就有很高的 latency (需要等到 i/o 完成)。

Mark Callaghan 用手邊的機器測試發現,改進甚至比想像中的大,無論是 cpu bounded 或是 i/o bounded 的情況:

tl;dr for a CPU-bound workload

* Enabling sync on commit for InnoDB and the binlog has a large impact on throughput for the write-heavy steps -- l.i0, l.i1 and l.i2.
* When sync on commit is enabled, then also enabling the binlog_storage_engine is great for performance as throughput on the write-heavy steps is 1.75X larger for l.i0 (load) and 4X or more larger on the random write steps (l.i1, l.i2)

tl;dr for an IO-bound workload

* Enabling sync on commit for InnoDB and the binlog has a large impact on throughput for the write-heavy steps -- l.i0, l.i1 and l.i2. It also has a large impact on qp1000, which is the most write-heavy of the query+write steps.
* When sync on commit is enabled, then also enabling the binlog_storage_engine is great for performance as throughput on the write-heavy steps is 4.74X larger for l.i0 (load), 1.50X larger for l.i1 (random writes) and 2.99X larger for l.i2 (random writes)

如果在大台 server 上面也有類似的效果,這個有機會是 InnoDB 這十年來在寫入效能上最大的改進?上次應該是壓縮了...