🗓️ 【2026年10月1日 追記】v3(20本・9月17日)と v4(22本・9月23日)が出ました

その後、v3(9月17日・20本) と v4(9月23日・22本) が投稿されました。v3 では予告どおり rustc 並列フロントエンドの1本を落とし、objtool のリロケーションのハッシュを撤去しています。v4 は kbuild ツリーの変更と Kees Cook 氏の別系列の上にリベースし、既存の sorttable のバグを直す1本を加えました。カバーレターの見出し(allmodconfig 最大36%)は変わっていません。経緯は §5 の末尾に追記しました。10月1日時点でマージはまだです。

🗓️ 【2026年9月15日 追記】v2(21本)が投稿されました

本記事は9月8日の v1(23本) を扱っています。9月14日に v2 が投稿され、系列は21本になりました。 減った分は、mksysmap の修正2本(01・02)が先にメインラインへ入ったこと(7.3-rc3 に収録)と、srcversion の2本(13・17)を上流の別系列に譲ったこと。増えた分は、toolchain 検査を init/Kconfig.toolchain に移す1本です。番号の対応・変更点・投稿者の再計測値・レビューの反応・AI レビューボット Sashiko の件は §5 に追記しました。§2・§3 の秒数とパッチ番号は v1 のまま、§6 の手元の実測も v1 のままです(v2 で測り直す必要があるかの判断は §6 の callout)。タイトルの「23パッチ」は投稿時の本数です。

はじめに

2026年9月8日、Linux カーネルのメーリングリストに [PATCH 00/23] kbuild: significantly speed up kernel builds という23本組のパッチが投稿されました。投稿者は Lorenzo Stoakes 氏(署名は “Lorenzo Stoakes (ARM)")。カバーレターの冒頭はこうです。

A typical kernel build consists of a frustratingly large amount of time spent stuck in single-threaded bottlenecks. (典型的なカーネルビルドは、いらだたしいほど長い時間を、単一スレッドのボトルネックに引っかかって過ごしている)

結果として投稿者が示した数字が、allmodconfig のフルビルドで最大36%減、インクリメンタルビルドで最大70%減、何も変えずに make を打つ no-op ビルドで最大94%減です。128スレッドの Threadripper、512スレッドの2ソケット EPYC、8コアの M2 MacBook Pro の3台で、gcc と clang の両方で測った表がついています。

数字だけなら「速くなった」で終わる話です。この投稿が当サイトで扱う価値を持つのは、カバーレターに 「LLM usage」という節 があるからです。

An LLM was used to first determine where the bottlenecks were then to figure out how to improve them. It generated a lot of code, much of it hideous. (LLM を使って、まずボトルネックがどこにあるかを特定し、次にどう改善するかを考えさせた。大量のコードを生成したが、その多くは醜悪だった)

そしてそのコードを 「私が徹底的に監査し、多くを書き直した」 と続け、23本すべてのコミットに Assisted-by: タグを付けています。翌9日には Linus Torvalds が返信し、「怖くて最初は見なかった」と正直に書いたうえで「どのパッチも全然ひどくない。マージに全面的に賛成だ」と述べました。

当サイトは2週間前に、Linux のネットワーク担当メンテナが AI 由来のパッチの洪水に「完全に手一杯だ」と書いた話を書きました。今回はその対になる肯定側の実例です。同じ道具を、同じコミュニティの、しかも「洪水を受ける側」のメンテナが使ったとき、何が起きたか。LLM に何をさせ、人が何を握ったかが一次資料に書いてある——ここがこの記事のいちばんの価値です。

この記事では次の6点を扱います。

  1. kbuild とは何をしているのか — Kconfig からリンクまでの流れと、「no-op」「インクリメンタル」「allmodconfig」の意味
  2. 何が投稿されたか — 3台×2コンパイラの元の秒数と、第三者の追試
  3. 23パッチの中身 — mksysmap の C 再実装、*.mod.c の廃止、objtool の DWARF、pigz など技術的に面白いものを1つずつ
  4. LLM に何をさせ、人が何を握ったか — カバーレターの原文と、投稿者自身の言葉
  5. Linus の返信とスレッドの現在地 — 賛否・注文、v2(9月14日・21本)で何が変わったか、AI レビューボット Sashiko の報告の扱い(2026年9月15日時点)
  6. 手元で測ってみた — 当サイトの Ubuntu 26.04 機(Core i7-4790K・4コア8スレッド)での実測——インクリメンタル −47%、no-op −59%、フル −2.4%
⚠️ 数字の帰属について

本記事の秒数・削減率は、特記のない限り投稿者本人がカバーレターと各コミットメッセージに書いた計測値です。投稿者は「数回走らせた中の最良値(best of several runs)」と明記しています。第三者の追試は、それぞれ発言者に帰属して書きます。§2・§3 の秒数とパッチ番号は v1(9月8日・23本) のものです。9月14日に v2(21本)が投稿され、v2 の再計測値と番号の対応は §5 に載せています。系列は2026年9月15日時点でマージされておらず、レビュー中で、投稿者は v3 の準備も表明しています。


🧱 1. kbuild とは — カーネルビルドで何が起きているか

Linux カーネルのビルドシステムは kbuild と呼ばれます。make defconfig && make -j$(nproc) の裏で、実際には次のような工程が走っています。

flowchart TD A[Kconfig
.config を決める] --> B[kbuild の Makefile 群
各ディレクトリを巡回] B --> C[コンパイル
数千〜数万の .c → .o
ここは並列] C --> D[ld -r で vmlinux.o に結合] D --> E[objtool
命令を解読し検証] E --> F[modpost
モジュールの整合性検査
*.mod.c を生成] F --> G[kallsyms
シンボル表を作って
2〜3回リンクし直す] G --> H[vmlinux 完成
System.map] H --> I[圧縮
gzip → bzImage] F --> J[モジュール仕上げ
*.mod.c をコンパイル
→ .ko]

読者の PC のコア数がいくつあっても、この図の C(コンパイル)以外は、ほとんどが1本のスレッドで順番に進みます。コンパイルが終わったあとの「尾」——ld -r、objtool、modpost、kallsyms のリンク繰り返し、gzip——は直列です。コア数を増やしてもここは縮まない。投稿者が「単一スレッドのボトルネック」と呼んだのはこの部分です。

投稿者は9日のメールで、LLM に描かせたビルド中の CPU 使用率グラフを添付し、あわせて ASCII 版も載せています。文字1個が一定時間で、文字の種類が「そのとき何が走っていたか」を表します。並列に走るコンパイルは C、それ以外は1本の直列区間です(帰属:投稿者が LLM に生成させたもの。図の CPU 使用率の段は罫線文字のため省き、工程の段だけ転記しました)。

凡例: C=コンパイル L=リンク O=objtool P=modpost K=kallsyms Z=圧縮 m=make自身 .=アイドル
(x86 allmodconfig, clang, 128スレッド)

== クリーンビルド(1文字=4秒)==
before 343.6s
mCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOOOPPPCCCCCCCCCCCCCLL
after  265.6s
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCOOCCCCC

== mm/vma.c を1つ touch(1文字=0.5秒)==
before 45.7s
mCmCCmmmCLOOOOOOOOOOOOOOOOOOOOmPPPPPPPPPPPPPPPPPPPCLmKKKCCCmmKKKCCCLmmmmmmCCZZZZZZZZZZZZZZC
after  15.7s
mmCCCLOOOOOOOOOPPPPLKCKCLmmmmmCC

== 何も変えずに make(1文字=0.2秒)==
before 14.4s
CCCCmmmCCCmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
after  2.0s
CCmmmCmm

インクリメンタルの before を見ると、O(objtool)が20文字=10秒、P(modpost)が19文字=9.5秒、Z(gzip 圧縮)が14文字=7秒。1ファイル直しただけなのに、コンパイルそのものはほんの一瞬で、あとは全部「尾」です。no-op の before に至っては、ほぼ全部が m——make 自身が依存関係を読み直しているだけで14秒かかっています。この系列がやったのは、この尾を「並列にできるものは並列に、無駄な仕事はやめる」ことです。

💡 ワード解説:defconfig/allmodconfig/インクリメンタル/no-op
  • defconfig:アーキテクチャごとの既定の設定。x86 なら数千個のオプションを「ふつうの PC」向けに選んだ状態。自分で使うカーネルを作るときの出発点で、ビルドは数分〜十数分
  • allmodconfig:モジュールにできるものをすべてモジュールとして有効化した設定。x86-64 では1万個超のモジュールが生成される。カーネル開発者がコンパイルの通りを確かめるための「全部入り」で、ビルドは128スレッドでも数分、家庭用 PC なら1時間単位
  • フル(clean)ビルド:生成物を消してゼロから。インクリメンタル:1ファイルだけ触って make。no-op:何も変えずに make を打つ。開発中いちばん多く打つのはインクリメンタルと no-op で、投稿者は「日々の使い勝手にはこの2つがいちばん大事」と書いています
💡 ワード解説:Assisted-by タグ

カーネルのコミットメッセージ末尾に付ける帰属タグの一つ。公式ドキュメント Documentation/process/coding-assistants.rst は「AI ツールがカーネル開発に寄与したとき、貢献には次の形式の Assisted-by タグを含めるべき(should)」として Assisted-by: LLM [TOOL1] [TOOL2] を定めています([TOOL] は coccinelle や sparse のような専門解析ツール。git や gcc は書かない)。同じ文書は 「AI エージェントは Signed-off-by を付けてはならない(MUST NOT)。DCO を法的に証明できるのは人間だけ」 と定め、人間の提出者が「AI 生成コードをすべてレビューする」「全責任を負う」と明記しています。このポリシーの成り立ちと DCO の意味はLinux 7.2 の記事で扱いました。なお当時の記事では Assisted-by: AGENT_NAME:MODEL_VERSION という書式を紹介しましたが、2026年9月12日時点の公式ドキュメントは上記の Assisted-by: LLM [TOOL] 形式になっています。


📊 2. 何が投稿されたか — 数字と検証

まず投稿者が示した数字を、元の秒数のまま並べます。計測機は次の3台です(帰属:カバーレター)。

略称 構成
Threadripper x86、AMD Threadripper 9980X、64コア/128スレッド
EPYC x86、2ソケット EPYC 9754、256コア/512スレッド
M2 arm64、2022年 M2 MacBook Pro、8コア/8スレッド(性能4+効率4)

allmodconfig(投稿者の計測・best of several runs)

機種・コンパイラ フル インクリメンタル no-op
Threadripper, gcc 345.3s → 275.2s(−20%) 46.4s → 15.3s(−67%) 12.97s → 1.18s(−91%)
Threadripper, clang 345.5s → 265.7s(−23%) 44.4s → 15.2s(−66%) 13.84s → 1.64s(−88%)
EPYC, gcc 188.6s → 121.1s(−36%) 82.0s → 24.3s(−70%) 25.92s → 1.52s(−94%)
EPYC, clang 261.7s → 184.6s(−29%) 77.6s → 24.3s(−69%) 27.58s → 2.17s(−92%)

defconfig(投稿者の計測・best of several runs)

機種・コンパイラ フル インクリメンタル no-op
Threadripper, gcc 35.3s → 28.6s(−19%) 11.6s → 5.5s(−53%) 0.96s → 0.47s(−51%)
Threadripper, clang 33.5s → 26.1s(−22%) 11.6s → 5.0s(−57%) 1.21s → 0.55s(−55%)
EPYC, gcc 31.2s → 20.6s(−34%) 19.3s → 9.2s(−52%) 1.47s → 0.66s(−55%)
EPYC, clang 38.6s → 32.2s(−17%) 20.1s → 8.6s(−57%) 1.87s → 0.80s(−57%)
M2, gcc 564.0s → 512.4s(−9%) 18.6s → 9.9s(−47%) 5.59s → 1.69s(−70%)
M2, clang 616.1s → 569.4s(−8%) 18.6s → 8.2s(−56%) 6.62s → 1.74s(−74%)

見出しの「36%/70%/94%」は、いずれも EPYC・gcc・allmodconfig の値です。8コアの M2 ではフルビルドの削減は9%にとどまる一方、インクリメンタルは半分、no-op は3分の1以下になっています。コア数が少ないほどコンパイル自体が支配的になるので、フルビルドの効きは小さい。逆に、直列の尾は機械の大小によらず存在するので、インクリメンタルと no-op はどの機械でも大きく効く——表はそう読めます。

投稿者が何を検証したか

カバーレターの「Testing」節の要旨です。速度の主張と同じくらい、ここが重要です。

  • x86 以外に arm64・arm・riscv・powerpc64・s390・loongarch で allmodconfig をビルド。arm64・arm・s390・loongarch では、生成される System.map が旧 mksysmap の出力と同一
  • x86・arm64・arm・riscv・loongarch・powerpc64・s390・m68k・parisc64 のカーネルが QEMU で起動し、System.map の全 text シンボルが /proc/kallsyms にリロケート後のアドレスで存在し、モジュールのロード/アンロードが通る
  • CONFIG_MODVERSIONS・CONFIG_EXTENDED_MODVERSIONS・CONFIG_MODULE_SRCVERSION_ALL を有効にした x86 カーネルが起動し、モジュールを扱える。外部モジュールは in-tree と O= の両方でビルド可
  • 23コミットすべてが x86 defconfig で個別にビルドできる
  • 「ビルド工程の一部は変わったが、すべてのツールは以前と同一に機能するはず」

第三者の追試(発言者に帰属)

  • Florian Fainelli(Broadcom)、9月9日:「AMD EPYC 9454P のサーバーで、arm64 の defconfig を make -j97 で走らせて 13% 程度の改善」
  • Nathan Chancellor(kbuild 共同メンテナ)、9月12日:80コアの Ampere Altra で 6時間21分42秒 → 5時間31分15秒(−13.22%)、32コアの AMD 機で 3時間38分55秒 → 3時間13分18秒(−11.7%)。「機械ごとにビルドの組み合わせ(build matrices)は違うが、異なる環境で似た数字が出ているのはよい」

いずれも投稿者の環境より控えめな数字で、それがむしろ信頼できます。「あらゆる環境で36%」ではなく、「直列の尾が全体に占める割合ぶんだけ速くなる」というのが実態です。


🔧 3. 中身を見る — 23パッチのうち技術的に面白いもの

カバーレターは23本を「基本的には、単一スレッドの処理をできる限り並列化し、ビルドに使うコードの効率を上げる」と要約しています。以下、コミットメッセージを読んで、何がどう変わったかを1つずつ追います。数字はすべて投稿者の128スレッド Threadripper での計測です。

3-1. mksysmap を C で書き直し、nm をやめる(08)

System.map を作る scripts/mksysmap は、30個のパターンからなる sed スクリプトでした。リンクのたびに nm -n vmlinux | sed -f mksysmap を通し、その出力を kallsyms が読む。x86-64 の allmodconfig では 250 MiB のファイルに対して nm を3回走らせ、毎回50万行を書いて読む。llvm-nm で1パス0.5秒、GNU nm で0.2秒、さらに解析が乗ります。

パッチ08はこれを丸ごとやめ、kallsyms が ELF ファイルのシンボルテーブルを直接読むようにしました。新しい scripts/kallsyms-sysmap.c(269行)は、sed の30パターンを C のテーブル(除外プレフィックス・サフィックス・完全一致名)に移植し、nm が付ける型文字(T、t、d、b など)を ELF のセクションフラグから再現し、nm -n と同じ「アドレス順、同じなら名前順」で並べ替えます。scripts/mksysmap(94行)は削除。

肝心なのは互換性で、コミットメッセージには「System.map は GNU nm でも llvm-nm でも nm | mksysmap とバイト単位で同一(x86 の2構成、arm64・arm・s390・loongarch の defconfig)」とあります。出力を変えずに工程を減らした、という種類の改善です。

3-2. kallsyms の出力をバイナリに(04)— Linus が「もっと先へ」と言った場所

kallsyms はシンボル名を圧縮した表をアセンブリのソース(.byte の羅列)として吐き、それをアセンブラに通してオブジェクトにします。x86-64 で15.8万シンボルなら 37 MiB の .S ファイルで、アセンブルに0.57秒。これがビルド1回につき2〜3回走る。

パッチ04は、バイト単位の表をバイナリファイルに書き出して .incbin で取り込む形にしました。.S は9.8 MiB+2.6 MiB の .bin になり、アセンブル時間は0.16秒。オブジェクトは同一です。

Linus はここに反応しました(9月9日)。要旨は「速くはなったが、根本の馬鹿らしさは直っていない。この kallsyms が生成するファイルはすぐにアセンブルされる以外の用途がなく、人間が読むことは一度もない。libelf はもうビルドの必須要件なのだから、オブジェクトファイルを直接書けばいい」。そしてこう続けます。

But when there’s a LLM that was used to find these things and help fix them up, and it’s something this mechanical and the result really isn’t ever human-readable and never has been, I feel like the obvious step would be to just ask the little helper bot to switch the whole kallsyms to using libelf-devel and writing an object file directly. (だが、こういう箇所を見つけて直すのに LLM を使ったのなら、しかもこれほど機械的で、結果が人間可読だったことなど一度もない代物なら、当然の次の一手は、その小さな助手ボットに「kallsyms 全体を libelf を使ってオブジェクトファイルを直接書くように切り替えて」と頼むことだと思う)

「誰もこの手のごてごてした細部に付き合いたくないし、ELF ライターを書く労力もかけたくない。だが LLM がいるなら話は別だ」という言い方で、LLM を使うなら作業量の壁を理由にした妥協はしなくていい、と読める返信です。

3-3. make が依存関係を読む時間を C で削る(10・11)

no-op ビルドで14秒かかっていた m の正体がこれです。各オブジェクトの .cmd ファイルには、そのファイルが依存するヘッダの一覧が書かれていて、1オブジェクトで千個を超えることがざらにあります。ツリーにほとんど変更がないとき、make は「この千個のヘッダは更新されていないか」を1本のスレッドで延々と確かめます。

先にパッチ10が、各オブジェクトが「組み込みかモジュールか、どの複合オブジェクトに属するか」を何度も計算し直していた部分をキャッシュにします(ディレクトリ内のオブジェクト数に対して O(n²) に伸びていて、310オブジェクトの amdgpu で特に痛かった、とあります)。そのうえでパッチ11は scripts/basic/depcheck.c(442行)を新設し、この確認を C でやらせます。ディレクトリ内の各ターゲットの .cmd を読み、依存先ごとに stat() を1回だけ呼び、「依存先がすべて存在し、ターゲットより古い」ものについては保存済みコマンドラインだけの断片を生成する。make はその断片を読むだけで済みます。失敗したら従来の .cmd 方式に戻る、という逃げ道つき。amdgpu ドライバのディレクトリでは、make が読む量が5分の1、読み込みは380ms→10ms、そのディレクトリの処理が2.2秒→0.4秒です。

Linus はここに「昔の記憶」を書き添えました(9月9日)。要旨は「ずっと前にカーネルビルドのプロファイルを取ったとき、.cmd の中で設定ヘッダに $(wildcard ...) を使っているせいで make の仕事が増えていた記憶がある。あれはパターンを合わせたいからではなく、存在しない設定ヘッダで make に文句を言わせないための唯一の方法だった。四半世紀前のコードで、以来誰も手を付けようとしていない。今 fixdep.c からその生成を外してみたが、ビルドは何も気にしなかった。もう丸ごと不要なのかもしれない」。改善を歓迎するだけでなく、自分の記憶にある別の芽を差し出す返信です。

3-4. *.mod.c をやめてアセンブリで出す(15・16)— no-op を82%削った本丸

これが allmodconfig の no-op 短縮の主役です。modpost はモジュール1個につき1つの <module>.mod.c を生成します。中身は .modinfo 文字列、__this_module 記述子、エクスポートシンボル表、CONFIG_MODVERSIONS なら CRC。このファイルは「ふつうのカーネル C ファイルとして」コンパイルされます——-include の前置き、linux/module.h のインクルード、fixdep が生成する数百のヘッダ依存、objtool の実行、LTO ならリンクまで。

x86-64 allmodconfig では 11,189個の *.mod.c がそれぞれ CPU 時間0.24秒、モジュール仕上げ全体で 6,300 CPU 秒=128スレッドで64秒。しかも *.mod.o.cmd が 1.3 GiB 生成され、以後のビルドは毎回それを読み直す。no-op が遅い理由の大半がここでした。

パッチ15は記述子をアセンブリ(*.mod.S)で出すようにしました。struct module のサイズと配置、フィールドのオフセットは新設の scripts/mod/module-offsets.h から取ります。すると linux/module.h も、数百ヘッダの依存も、objtool もいらない。結果、make modules を全 *.mod.o と *.ko を消した状態から走らせると 64.5秒(6,306 CPU 秒)→ 28.5秒(518 CPU 秒)。no-op は11.0秒→1.9秒(−82%)。

ここでも互換性の確認が丁寧です。「.modinfo・.gnu.linkonce.this_module・__ksymtab*・__kcrctab*・__versions 等のセクションとそのリロケーションが、clang allmodconfig(CONFIG_COMPILE_TEST 無効)の 8,135モジュールすべてでバイト単位で同一」「違うのはコンパイラが周囲に足していたもの(__UNIQUE_ID_* のローカル、KASAN のコンストラクタ、x86 の .note.gnu.property)だけで、いずれもビルドに影響しない」。

続くパッチ16は副作用への対処です。仕事が小さくなりすぎて 約22,000個の数ミリ秒ジョブを make が配り切れない。そこで modules.order を128個ずつに分割して並列に走らせる。make modules は28.9秒→15.9秒。

Linus の反応(9月9日)は3-2と同じ方向で、「linux/module.h をインクルードしないのが最大の勝ちで、あとは AS を経由してオブジェクトを作るという回り道に意味があるとは思えない。この asm ファイルを見たい人間はいない。オブジェクトを直接生成する方が自然だ」。そして本音を一行。

I’ll also be honest: part of why I do these suggestions is that I do think it would be faster to skip the intermediate assembler step, but a big part of it is that I don’t love the random turds our build creates. Getting rid of the *.mod.c files would be a cleanup of our strange build. (正直に言うと、こういう提案をする理由の一部は中間のアセンブラ工程を飛ばす方が速いと思うからだが、大部分は、うちのビルドがまき散らす雑多なゴミが好きじゃないからだ。*.mod.c を消せるなら、この奇妙なビルドの掃除になる)

3-5. modpost の srcversion 計算を並列化(13・17)— そして v2 で落ちた

CONFIG_MODULE_SRCVERSION_ALL が有効だと、modpost は各モジュールのソースをハッシュして srcversion を作ります。x86-64 の allmodconfig では 20万個のファイルを1つずつ開いて、直列にハッシュしていました。パッチ13でバイト単位からファイル単位のハッシュに変え、パッチ17でスレッドプールを使って並列化。「2つ合わせて allmodconfig の modpost 実行時間がほぼ半分」「Module.symvers と全 *.mod.S はバイト単位で同一」。

ところがレビューで、Petr Pavlu 氏(SUSE)から「srcversion のサポート自体が別の系列で削除される予定(ビルド ID が同じ役割を果たすので不要)。今この2本を磨くのは無駄になる」(要旨)と指摘があり、投稿者は9月11日に「了解、v2 ではこの2本を落とし、カバーレターに依存関係を明記する」と返しています。実際、9月14日の v2 では2本とも外れ、カバーレターの性能数値は「module_ver_remove v2 系列を当てた上で」測ったものになりました。LLM が見つけて人が仕上げた最適化が、「その機能ごと消す」という上流の判断で不要になる——こういうことが普通に起きるのがレビューです。

3-6. objtool が DWARF のリロケーションで手を止めないようにする(18・19)

objtool は vmlinux.o の命令を解読し、すべてのジャンプ・コールの行き先を解決します。その過程でリロケーションを「行き先」で引くハッシュを持つのですが、パッチ18のコミットメッセージによれば、allmodconfig で 約900万個のリロケーションをハッシュに入れ、そのうち約820万個は DWARF(デバッグ情報)セクションのものでした。DWARF のリロケーションは行き先で引かれることが一度もない。ハッシュを汚し、キャッシュミスを増やしていただけです。

パッチ18は、DWARF セクションはインデックスもハッシュもしない(万一引かれたら線形探索に落とす仕組みを添えて)、セクションごとに64バイト窓のリロケーションキャッシュを持つ、「決して戻らない関数(dead end)」の判定結果を関数ごとに1回だけ記憶する、の3点。「objtool の出力は x86_64 の defconfig・allmodconfig、gcc・clang でバイト単位で同一」。続くパッチ19で命令の解読と分岐先の解決を複数スレッドに分け、allmodconfig のインクリメンタルで −17%(28.4秒→23.7秒)。

Linus はカバーレターへの返信で「objtool の変更はかなり大きく、objtool の人たちの承認が要る」と注文を付けています。マージの経路として、ここは kbuild ツリーとは別扱いになる見込みです。

3-7. pigz があれば使う(23)— いちばん小さく、いちばん効く

最後のパッチはたった3ファイル、30行です。128コアの Threadripper で 36 MiB の vmlinux.bin を gzip -9 すると1.6秒、pigz なら0.09秒。gzip は並列化できないが、pigz は同じ機能を持つ並列実装で、そのまま置き換えられる。従来も KGZIP=pigz と環境変数で指定できましたが、これを「システムに pigz があれば既定で使う」に変えました。

-KGZIP = gzip
+KGZIP := $(if $(shell command -v pigz 2>/dev/null),pigz,gzip)

defconfig のインクリメンタルで −27%(7.4秒→5.4秒)。x86 のビルドは必ず vmlinux.bin の圧縮で終わるので、直列の尾の最後の7秒がそのまま消えます。再現可能ビルドについては「pigz 同士、gzip 同士なら出力はバイト単位で同一だが、gzip と pigz は互いに同じストリームを作らないので、同じツールを揃えること」と Documentation/kbuild/reproducible-builds.rst に追記しています。投稿者は Linus への返信でも「手元で試すなら pigz を入れないと全部の効果は出ない」と念を押しています。

23本の全体像

領域 パッチ 何をしたか(カバーレターの要約)
mksysmap 01–02 系列の前提になる2つのバグ修正
kallsyms 03–04 キャッシュとバイナリ出力で効率化
kbuild 05–06 nm の不要なソートをやめる、kallsyms の試しリンクにリロケーションを含めない
elf-parse/kallsyms 07–08 ELF 直読の下準備と、mksysmap の C 再実装
kbuild 09–12 .modinfo を非割り当てに、オブジェクト状態のキャッシュ、depcheck、コンパイラ探査を1回に
modpost 13–14 ファイル単位ハッシュ、セクション不一致判定のキャッシュ
modules 15–16 *.mod.c → *.mod.S、モジュール仕上げの分割
modpost 17 srcversion の並列計算
objtool 18–19 DWARF リロケーションの除外、並列解読
rust 20–22 rustc フロントエンドの並列化、依存の修正、C と並行ビルド
kbuild 23 pigz の既定化

合計で 47ファイル、2,884行追加、682行削除です(v1)。v2(21本)との番号の対応は §5 の表にまとめています。


🤝 4. 「LLM に何をさせ、人が何を握ったか」— カバーレターの原文

この記事の中心です。カバーレターの「LLM usage」節を、そのまま引用します。

== LLM usage ==

An LLM was used to first determine where the bottlenecks were then to figure out how to improve them.

It generated a lot of code, much of it hideous.

I extensively audited and rewrote a lot of it, and heavily edited commit messages, the cover letter and comments.x [原文ママ]

The LLM has also orchestrated build runs, testing, debugging and analysis.

I have manually checked for correctness in both build and running kernels generated with this series applied.

Performance improvements were also verified manually.

Since an LLM was used extensively, each commit carries an Assisted-by tag.

訳すとこうなります。

LLM を使って、まずボトルネックがどこにあるかを特定し、次にそれをどう改善するかを考えさせた。 大量のコードを生成したが、その多くは醜悪(hideous)だった。 私はそれを徹底的に監査して多くを書き直し、コミットメッセージ・カバーレター・コメントを大幅に編集した。 LLM はビルドの実行、テスト、デバッグ、分析のオーケストレーションも行った。 この系列を適用して生成したカーネルについて、ビルドと実行の両方で正しさを私が手作業で確認した。 性能の改善も手作業で検証した。 LLM を広範に使ったので、各コミットに Assisted-by タグを付けている。

分担を表にすると、次のようになります。

工程 LLM 人(投稿者)
ボトルネックの特定 ◎ プロファイルして「どこが遅いか」を出す 結果を読む
改善案 ◎ 「どう直すか」を考える 採否を判断
コード生成 ◎ 大量に書く(多くは hideous) 監査し、多くを書き直す
コミットメッセージ・コメント 下書き 大幅に編集
ビルド・テスト・デバッグの実行 ◎ オーケストレーション —
正しさの確認 — ビルドと実機起動で手作業
性能の検証 — 手作業
署名と責任 付けられない Signed-off-by

「探索と実行は機械に、判断と保証は人に」という分け方で、これは公式ドキュメントが求める線引きそのものです。Documentation/process/generated-content.rst は、ツール生成コンテンツを含む貢献に「どのツールを使ったか」「どの部分がツールの影響を受けたか」「どうテストしたか」を明らかにするよう求めていますが、このカバーレターにはその3点に対応する記述があります。

一方で書いていないこともあります。どの LLM(モデル名・ツール名)を使ったかは、カバーレターにもコミットにも書かれていません。タグも Assisted-by: LLM のみです。これは公式の書式(Assisted-by: LLM [TOOL1] [TOOL2])に沿った書き方で、公式ドキュメントはモデル名の明記を要求していません。プロンプトの内容も書かれていません(同ドキュメントは「短いプロンプトから大部分を生成したなら含める、長いセッションなら要約を」と推奨しています)。

投稿者自身の言葉 — 「洪水を受ける側」として

もう一つ重要なのが、なぜここまで透明に書いたか、を投稿者本人が説明していることです。Nathan Chancellor 氏が「これを全部明記してくれてありがとう」と書いたのに対する、9月11日の返信です。

Of course, I am on the receiving end of a flood of LLM patches in mm, so it’s important to me to be transparent and consistent.

I repeatedly tell people - audit what it makes with a human pass, fix up awful code/comments/commit msgs, make sure you understand it + on you to make upstreamable + obviously ack that you used it.

So what’s good for the goose is good for the gander :) (もちろん。私は mm で LLM パッチの洪水を受ける側にいるので、透明で一貫していることが自分にとって大事だ。私はいつも人にこう言っている——生成物は人間の目で監査しろ、ひどいコード・コメント・コミットメッセージは直せ、自分で理解しろ、上流に入れられる形にするのはお前の責任だ、そして当然、使ったことは明記しろ。だから、人に言うことは自分にも当てはまる)

「mm」はメモリ管理サブシステムで、2週間前の記事で扱ったネットワークと同じく、AI 由来パッチの流入先です。メンテナとして人に課している条件を、自分が投稿者に回ったときに一つ残らず守った——この投稿の透明性は、そういう位置から出ています。9月9日には別の返信で「LLM を使うのに格好の題材だった(ただし、私は今後も自分の変更を保守できなければならないし、そこには依然として基準があるので、大量の飼い慣らし・レビュー・監査・書き直しを伴って)」とも書いています。


🐧 5. Linus の返信と、スレッドの現在地(v1 → v2・2026年9月15日時点)

カバーレターへの返信(9月9日)

Linus Torvalds の返信は、冒頭の「単一スレッドのボトルネック」への一言から始まります。

.. you’re preaching to the choir. (……釈迦に説法だ)

そして allmodconfig の表に「非常に心強い。これはやるべきだ」。ただし個々のパッチへの反応は「数字の裏づけはなく、系列を自分のツリーに当てて試してもいない。パッチを読んだだけの反応だ」と断っています。続けて、LLM usage 節についてこう書いています。

This made me scared to look at the patches originally, and I held off in fear that the patches would be horrible and this build time improvement would be hugely controversial garbage code.

But: […]

None of the patches look at all horrible to me. You clearly excised the hideous parts. All of my reactions were of the type “this could probably be taken further” rather than me throwing my hands up in disgust. (これを読んで、最初はパッチを見るのが怖くなった。パッチがひどくて、このビルド時間の改善が大論争を呼ぶゴミコードになるのを恐れて手を止めていた。だが[「徹底的に監査して書き直した」の引用]——どのパッチも私にはまったくひどく見えない。醜悪な部分は明らかに切除されている。私の反応はすべて「これはもっと先まで行けるのでは」という種類のもので、嫌悪で両手を上げるようなものではなかった)

結論部分はこうです。

So the Rust parallelism thing clearly isn’t ready based on feedback from that quarter, but the rest looked safe and innocuous. I’m all for merging this, although it should obviously go in through the right channels. Mostly the kbuild tree, although some of it clearly would be other cases - the objtool change in particular is fairly substantial and needsobjtool [原文ママ] people to approve. It didn’t look all that contentious, but still..

Anyway, I’d love for this all to go in. Build times are a pet peeve of mine. (Rust の並列化はあちら方面の反応からして明らかにまだ準備ができていないが、残りは安全で無害に見えた。マージには全面的に賛成だ。もちろん正規の経路を通すべきで、大部分は kbuild ツリー、一部は別扱い——特に objtool の変更はかなり大きく、objtool の人たちの承認が要る。それほど論争的には見えなかったが、それでも。ともかく、これが全部入ってほしい。ビルド時間は私の積年の不満だ)

要約すると、賛成(ビルド時間は個人的な不満の種)、注文は「正規の経路で」「objtool は担当者の承認を」「Rust の3本は保留」、個別パッチへの提案は「アセンブリ経由をやめてオブジェクトを直接書け」(04・15)と「$(wildcard) の古い仕掛けを見直せるかも」(11)。LLM 生成という事実に対しては「怖かったが、読んだら問題なかった」——コードで判断した、という返信です。

v1 スレッドで起きたこと(9月8日〜13日)

v1 のスレッドは投稿から4日で89通を超えました。v2 に至るまでの要点です。

  • パッチ01・02(mksysmap のバグ修正)は Nicolas Schier・Nathan Chancellor 両氏のレビューを経て、9月10日に kbuild メンテナの Nicolas Schier 氏が kbuild ツリーの kbuild-fixes-unstable ブランチに適用。その後メインラインへ入り、7.3-rc3 に収録されています(コミット 281b61d408d4・59351365ac27)
  • 13・17(srcversion)は、機能そのものの削除が別系列で進んでいるため落とすことが決まりました(§3-5)
  • 20〜22(Rust)は、Rust for Linux 側の Björn Roy Baron 氏が「rustc の並列フロントエンドには再現性の問題が残り、最近までデッドロックや誤ったエラーもあった。明示的な要求なしに有効化するのは勧めない」、Miguel Ojeda 氏が「nightly でもまだ大きな問題があるなら、まだ入れないでおこう」
  • 16 に Nicolas Schier 氏の指摘でマージ時の取り違え(sumversion.c の変更)、04 に fwrite の戻り値チェックの指摘。投稿者は「v2 で直す」
  • Nathan Chancellor 氏は「取りやすいものから見た。残りは数週間かけて見るが、Plumbers の後になるかもしれない。kbuild の隅々に詳しい人の助けがほしい」
  • 報道は Phoronix が9月8日(米東部時間)、LWN.net が9月11日(購読者限定のため内容は引用しません)
  • 投稿者は9月11日に「Linus のコメントと、より深く考える必要のある指摘、それに Sashiko を見てから v2 を送る」と表明

v2(9月14日・21本)— 何が変わったか

9月14日 10:21(英国時間)、[PATCH v2 00/21] kbuild: significantly speed up kernel builds が投稿されました。カバーレターの変更履歴(v2 節)から、変更点を整理します。

変更 中身(v2 カバーレターの変更履歴・帰属は投稿者)
落ちた(上流に入った) v1 の 01・02(mksysmap の修正2本)。「upstream に取り込まれたので外した——thanks Nicolas!」。Linus の master にリベース(base-commit 704340f1cd0d)
落ちた(別系列に譲った) v1 の 13・17(srcversion のハッシュ化・並列化)。「同等の作業が上流で進んでいる」として module_ver_remove v2 系列へ
増えた 新 10/21:既存の toolchain 検査を init/Kconfig から init/Kconfig.toolchain へ移す(Nathan Chancellor 氏の要望。11/21 がそこに追記する土台)
Rust rustc 並列フロントエンド(v1 の 20 → v2 の 18)を KBUILD_RUST_THREADS で opt-in に変更。「出力がまだ再現可能でないため」(Björn・Miguel・Nicolas 各氏の指摘)。計画中の -j フラグの探査も削除
objtool v1 の 18 → v2 の 15:「dead end」キャッシュを外し、Josh Poimboeuf 氏の noreturn 系列に依存する形へ。objtool 自身が作るリロケーションセクションもハッシュ化。v1 の 19 を 16(命令ハッシュのサイズ決定)と 17(並列解読)に分割(Josh 氏の要望)
個別の修正 03(v1 の 04):ferror()/fclose() でエラー検査(David Laight 氏)/05(v1 の 06):link-vmlinux.sh で CONFIG_ARCH_VMLINUX_NEEDS_RELOCS を直接見て、パッチを小さく(Nathan 氏)/11(v1 の 12):-fno-stack-clash-protection を Makefile に戻して ppc32 を修正(Nathan 氏)/21:pigz をモジュールには使わず vmlinux のみに。1/21(v1 の 09・.modinfo)を先頭に移し「先に入れられるように」
Sashiko 由来の修正 09(v1 の 11):depcheck に ferror() 検査/13(v1 の 15):__this_module のフィールドをオフセット順で出力し CONFIG_RANDSTRUCT に対応/17(v1 の 19):並列解読のレース修正(call 先の解決を直列化・pv_ops にロック・命令ハッシュの解放)/20(v1 の 22):modules_prepare が複数ゴールの一つでも rust/ をビルド(後述)
性能数値の前提 「module_ver_remove v2 系列と Josh 氏の noreturn 系列を当て、make KBUILD_RUST_THREADS=8 -j $(nproc)、pigz ありで計測」と冒頭に明記
規模 47ファイル、+2,982/−865行(v1 は +2,884/−682)

v1 → v2 の番号対応(本文 §3 は v1 の番号で書いています)

v1 v2 v1 v2
01・02 —(上流入り) 13 —(別系列へ)
03・04 02・03 14 12
05・06 04・05 15・16 13・14
07・08 06・07 17 —(別系列へ)
09 01(先頭へ) 18 15
10・11 08・09 19 16・17(分割)
12 11 20〜22 18〜20
—(新設) 10 23 21

再計測の数字(投稿者・best of several runs・v1 と v2 のカバーレター)

構成 v1(9月8日) v2(9月14日)
allmodconfig フル・EPYC gcc 188.6s → 121.1s(−36%) 188.0s → 121.1s(−36%)
allmodconfig インクリメンタル・EPYC gcc 82.0s → 24.3s(−70%) 70.9s → 24.3s(−66%)
allmodconfig no-op・EPYC gcc 25.92s → 1.52s(−94%) 30.6s → 1.5s(−95%)
defconfig フル・EPYC gcc 31.2s → 20.6s(−34%) 28.7s → 20.6s(−28%)
defconfig インクリメンタル・EPYC gcc 19.3s → 9.2s(−52%) 18.6s → 9.2s(−51%)
defconfig no-op・EPYC gcc 1.47s → 0.66s(−55%) 1.7s → 0.66s(−61%)
defconfig フル・M2 gcc 564.0s → 512.4s(−9%) 519.3s → 512.4s(−1%)
defconfig インクリメンタル・M2 gcc 18.6s → 9.9s(−47%) 18.0s → 9.9s(−45%)
defconfig no-op・M2 gcc 5.59s → 1.69s(−70%) 6.4s → 1.7s(−74%)

v2 のカバーレターの見出し数字は「allmodconfig フル最大36%、インクリメンタル最大約70%、no-op 最大約90%」で、v1 から変わっていません。表を見ると after の値は v1 とほぼ同じで、動いているのは before の側です。before が動いた理由をカバーレターは説明していませんが、リベース先が 7.3-rc2 直後から 7.3-rc3 直後に変わり、前提の2系列(srcversion の削除・objtool の noreturn)を当てた上で測っていることから、比較の土台が変わったと読むのが自然です。M2 の defconfig フルが −9% から −1% に縮んだのも、after(512.4s)は同じで before(564.0s → 519.3s)が縮んだためです。

v2 へのレビュー(9月14〜15日)

v2 のスレッドは投稿から1日半で58通(9月15日昼・英国時間の時点)。要点を発言者に帰属して並べます。

  • Kees Cook 氏(9月14日):「This is very nice!」としたうえで、①「いくつかの変更は、得られる効果に見合わない複雑さを足しているのでは」②Clang の CONFIG_LTO=y で試したか③「コミットログにはまだかなり手直しが要る。LLM の冗長さの問題が多くのログに出ている——たとえばログの80%を、ある処理の全手順の背景説明に費やしてから、ようやく実際の変更に入る。人間ならもっと簡潔に書くだろう」④3パスの kallsyms を1パスにする問題こそ LLM で解けるかもしれない、と4点。別の返信で「pigz の変更など、いくつかは切り出して先に入れられる」とも
  • 投稿者の返信(同日):「コミットの大半は私が書き直した。つまりこれは私のコミットメッセージの書き方への手厳しい批評ということになる :)」「具体的にどのメッセージか指摘してもらえれば痩せさせる」「CONFIG_LTO_CLANG_THIN で *.mod.S が正しく動くことは確認した」。kallsyms の1パス化は「LLM によれば allmodconfig で約8秒、defconfig で2〜3秒の削減」だが「本当に低い枝の果実をまず入れてから」
  • Linus Torvalds 氏(9月14日):kallsyms について「3パス版でさえ常に決定的だったわけではない。何年にもわたって時々失敗の報告があった。壊れやすいことは確かだ」。objtool の 15/21 には「素朴な疑問だが、そもそも全命令をハッシュに入れる必要があるのか。call・branch・return・endbr と分岐先だけでよいのでは。next ポインタで辿れば……」と提案し、「馬鹿げているか、それとも『馬鹿げてはいないが直すのが痛すぎる』か?」
  • Josh Poimboeuf 氏(objtool メンテナ)(同日):find_insn() の利用者は分岐先・alternatives・注釈つき命令など多く、「どの命令をハッシュすべきか事前に決めるのは『直すのが痛すぎる』と『不可能』の間」。「Peter と私で大きな性能問題はすでに直した。保守性を犠牲にしてまで最後の一滴を絞る動機は薄い——メンテナの帯域も貴重な資源」。15/21 には「ハッシュ+線形の二重フォールバックは要らないのでは」「klp-post-link.c に初期化漏れがある」
  • Arnd Bergmann 氏(9月15日):kallsyms のパス数の話に「リンカが新種のシンボルを作るたびに壊れる。数年に1回のペース」と過去の修正3件を列挙
  • Miguel Ojeda 氏(Rust for Linux)(9月15日):18/21 のコミットメッセージが「LWN の記事を混乱させた」——各クレートは既に可能な範囲で並列にビルドされており、このフラグは別の話。「今この時点で Kbuild 変数を足すことには賛成しかねる。名前も『threads』ではなく『frontend jobs』で、将来のフラグ名も変わる」「危険を承知で使いたい人は今日でもフラグを渡せる」
  • 投稿者の返答(9月15日):Miguel 氏に「このコミットは落とすのが最善だと思う。v3 では既に落とした」「計測には KRUSTFLAGS=-Zthreads=8 を使ったとカバーレターに書く」。Josh 氏には「その通り。v3 ではリロケーションのハッシュを丸ごと撤去した——objtool が追加するリロケーションは結局オフセット順で来るので、フォールバックは線形だけで足りる。gcc/clang の allmodconfig と defconfig で vmlinux.o がバイト単位で同一なこと、klp-build が動くことを確認した」。Linus 氏には「Josh に従うが、v3 でハッシュを落としたので『2つのうち1つ』は達成 ;)」

つまり9月15日の時点で、v2 はレビュー中のまま v3 の準備が始まっています。Reviewed-by/Acked-by のタグは、9月15日昼までの v2 スレッドには付いていません。

Sashiko — AI レビューボットの報告は「多くが幻覚」、でも4件は取り込んだ

v2 のカバーレターには、v1 の記事では扱わなかった名前が出てきます。Sashiko です。

Checked all of the hallucinated sashiko reports. Replied inline to emails to keep a record of them but not going to repeat here, unless people want a list. (幻覚を含む sashiko の報告をすべて確認した。記録として各メールにインラインで返信したが、要望がなければここでは繰り返さない)

Sashiko は、sashiko-bot@kernel.org から sashiko-reviews@lists.linux.dev というメーリングリストにパッチのレビュー結果を投稿する AI レビューです(結果は sashiko.dev でも閲覧できます。運営主体は本記事では確認していません)。v1 の投稿当日、9月8日 21:10〜21:43(UTC)に各パッチへの報告が自動で流れ、たとえばパッチ04には「バイナリファイルを "w" で開いているので改行を変換するホストで壊れるのでは」と書かれています。objtool メンテナの Josh Poimboeuf 氏は9月12日、パッチ19のレビューで「注意深く見る必要がある。Sashiko のレビューを見たい」と書いており、メンテナ側も道具として当てにしていることがわかります。

投稿者は9月13日の夕方に9件の報告を順に読み、1件ずつ返信しました。判定はこうです(各返信に帰属)。

v1 パッチ 投稿者の判定(返信の要旨) v2 への反映
04 「Linux カーネルは POSIX ホストを要求し、"b" は no-op。ナンセンス」 なし
06 「--emit-relocs の有無で結果が同一なことは実測で確認済み。この主張は誤り」 なし
11 「ナノ秒解像度で比較するものは無い(POSIX の要件)」と退けつつ、ferror() の検査は「有効、fixdep と kallsyms に合わせて直す」 09/21 に反映
15 「有効だった。オフセット順で並べるよう v2 で修正」 13/21 に反映(CONFIG_RANDSTRUCT 対応)
16 「ar はカーネルをビルドできる環境なら必ずある。GNU make は空のターゲットリストを受け付ける。100% 幻覚」 なし
19 5点のうち「修正した」「有効。ThreadSanitizer はさらに見つけた」の2点を採用、残り3点は「エラーパスは objtool を終了させるのでリークしない。ナンセンス」 17/21 に反映(レース修正)
20 「jobserver があれば上書きしない。-j1 ならメモリは増えるが数百 MB 程度で実害はない」 なし
22 「有効、v2 で直す」 20/21 に反映
23 「Nathan の指摘と同じで、v2 で対応済み」 (Nathan 氏由来)

9件のうち、採用は4件、全否定が3件、部分否定または実害なしが2件。カバーレターの「Sashiko hallucinated a lot of the report, and missed some stuff thread sanitizer found(Sashiko は報告の多くを幻覚し、ThreadSanitizer が見つけたものを見落とした)」は、19 についての記述です。

ここで見ておきたいのは、検証のコストを誰が払ったかです。AI 由来パッチの洪水を扱った記事で問題になったのは、生成のコストが投稿者に、検証のコストがメンテナに乗る非対称でした。今回は逆で、AI が出したレビュー報告を読み、幻覚を切り分け、有効な指摘だけ取り込む作業を投稿者自身が引き受けています(9件で約2時間・返信の時刻から)。その結果、CONFIG_RANDSTRUCT の順序問題や並列解読のレースのような、人間のレビュアーがまだ指摘していなかった実バグが v2 で直った——一方で、同じ道具が「POSIX ホストで "b" は no-op」という基本を知らずに警告も出す。AI レビューの報告は「読む人が検証する前提の下書き」であって、それ以上でも以下でもない——投稿者の返信の並びが、そのままこの道具の使いどころを示しています。

スレッドの現在地(2026年9月15日時点)

項目 状況
マージ 未マージ・v2(21本)がレビュー中。投稿者は9月15日に v3 の準備を表明(rustc 並列フロントエンドの1本を落とす・objtool のリロケーションハッシュを撤去)
メインラインに入った分 v1 の 01・02(mksysmap のバグ修正)。7.3-rc3 に収録(281b61d408d4・59351365ac27)。v2 からは外れた
落ちた分 v1 の 13・17(srcversion)。module_ver_remove v2 系列へ
v3 で落ちる予定 18/21(rustc 並列フロントエンド)。Miguel Ojeda 氏の指摘を受けて投稿者が表明
経路 大部分は kbuild ツリー。objtool の 15〜17 は objtool メンテナ(Josh Poimboeuf 氏)のレビュー下。Kees Cook 氏は「pigz など一部は切り出して先に」
開いている論点 コミットログの冗長さ(Kees 氏)/pigz を必須依存にして jobserver(scripts/jobserver-exec)で -j を尊重させるか(Kees 氏の提案)/kallsyms の1パス化(投稿者は「将来の課題」)
レビュータグ v2 スレッドに Reviewed-by/Acked-by は9月15日昼までに無し

系列がこのまま丸ごと入るわけではなく、バグ修正は先に、明らかに安全なものは順次、大きいものは担当者の承認を経て、不要になったものは落とす——典型的なカーネルのレビュー工程が、LLM が関与したパッチに対してもいつも通りに回っています。v1 から v2 への差分は、まさにその工程の記録です。

🗓️ 続報について

v3 の投稿、kbuild ツリーへの適用、メインラインへのマージがあれば本記事に追記します。上の表の「時点」は本文更新時に更新します。

🗓️ 2026年10月1日追記:v3 と v4

v3(9月17日・20本) の主な変更は次のとおりです(カバーレターの変更履歴。帰属は投稿者)。

  • rustc 並列フロントエンドの1本(v2 の 18/21)を削除。フラグ名がまだ定まらず、KRUSTFLAGS=-Zthreads=8 で同じ挙動が得られるため(Miguel Ojeda 氏の指摘)
  • objtool の 15/20 でリロケーションのハッシュを撤去し、セクションごとに逐次組み立てる方式へ(Josh Poimboeuf 氏・Linus の指摘)
  • 並列化を --link の段(vmlinux.o の objtool 処理)に限定(Kees Cook 氏)
  • pigz に make の jobserver を使わせ、専用の変数 KPGZIP を定義。再現可能ビルドの文書の追記は外した(Kees 氏)
  • depcheck と modfinal の分割まわりは Sashiko の指摘で補強

v4(9月23日・22本) では、kbuild ツリーのコミット 36d4a11b56aa と Kees 氏の cc-option-str 系列の上にリベースし、カバーレターに依存関係を明記しました。新しい 4/22 は、既存の sorttable のバグ(後続のパッチで表に出うる)を直す1本で、きっかけは Sashiko の問いかけです(投稿者は「分析は誤りだが、sorttable を疑ったのは正しい」と書いています)。M2 の数値は Linus の指摘で修正されました。v4 のパッチには Kees 氏らの Reviewed-by が付き、9月24日には Nicolas Schier 氏も 01/22 と 20/22 に Reviewed-by を返しています。見出しの数字(EPYC・gcc の allmodconfig で 188.0秒 → 121.1秒、−36%)は v2 から変わっていません。10月1日時点で、kbuild ツリーへの適用とメインラインへのマージはまだです。


🖥️ 6. 手元で測ってみた — Ubuntu 26.04 の自宅サーバーで

投稿者の3台はいずれも筆者の手元にはない構成です。そこで、26.04.1 への更新を記録した自宅サーバー——2014年の Core i7-4790K、4コア8スレッド——で、同じ base commit に系列を当て、defconfig のフル/インクリメンタル/no-op を before/after それぞれ3回測りました。投稿者は「数回の最良値」ですが、ここでは3回の中央値を主に載せ、最良値も併記します。手順書は AI が書き、実行と記録は人間がやりました(2026年9月12日 19:16〜20:14、約1時間)。

🗓️ この節の時点と条件

2026年9月12日の実測です。対象は 7.3-rc2 直後の base commit 28924df2a08f に v1 の23パッチをすべて当てたツリー。9月14日に投稿された v2(21本)では測り直していません。 v2 で外れた4本(mksysmap の修正2本は上流入り・srcversion の2本は別系列へ)と opt-in になった rustc 並列は、いずれも x86_64 defconfig・gcc の数字にはほぼ効かない要素で、投稿者自身の v2 再計測でも defconfig の after 値は v1 とほぼ同じです(§5 の表)。v3 の準備も始まっているので、測り直すならその後に一度、と考えています。測ったのは x86_64 defconfig・gcc のみで、allmodconfig と clang は測っていません。

環境

項目 値
CPU Intel Core i7-4790K @ 4.00GHz(Haswell・4コア8スレッド・2014年)
メモリ 22GB
ストレージ SATA SSD(TS256GSSD370・256GB)。ソースとビルド生成物はここ
OS/ホストカーネル Ubuntu 26.04.1 LTS/7.0.0-31-generic
gcc/make/ld gcc 15.2.0(Ubuntu 15.2.0-16ubuntu1)/GNU Make 4.4.1/GNU ld 2.46
pigz 2.8。after ではパッチ23が自動的に使う。before は gzip
ソース base commit 28924df2a08f(7.3-rc2 直後)+ 23パッチ(v1)。b4 am で Reviewed-by ごと取得し、47ファイル、+2,884/−682行が当たったことを確認
.config x86_64_defconfig(両ツリーで同一)。ccache なし。KBUILD_BUILD_TIMESTAMP を固定
周波数ガバナ schedutil → performance に固定
並列度 -j8(nproc の値)
開始時の状態 load average 0.47/Package 39℃。自宅サーバーなので Docker コンテナが常駐(止めずに計測)

測り方

  • 両ツリーで make mrproper → make defconfig のあと、ウォームアップとしてフルビルドを1回(結果に含めない)
  • フル:make clean(.config は保持)→ make -j8。3回。熱でクロックが落ちないよう各回の間に60秒あける
  • インクリメンタル:投稿者と同じ touch mm/vma.c → make -j8。3回
  • no-op:何も変えずに make -j8。3回
  • 時間は /usr/bin/time -v の Elapsed。user/system time・CPU 使用率・最大 RSS も同時に記録

結果(defconfig・-j8・3回の中央値、括弧内は最良値)

種別 before after 差(中央値)
フル(make clean 後) 373.59s(373.14s) 364.63s(364.43s) −2.4%
インクリメンタル(touch mm/vma.c) 22.27s(22.12s) 11.74s(11.67s) −47.3%
no-op 3.12s(3.10s) 1.27s(1.26s) −59.3%

フルは 6分13.6秒 → 6分04.6秒、インクリメンタルは 22秒 → 12秒、no-op は 3.1秒 → 1.3秒です。3回のばらつきは全種別で1%未満(フル 373.14〜373.62s、インクリメンタル 22.12〜22.32s、no-op 3.10〜3.17s)でした。

同じ defconfig・gcc で並べると、投稿者の M2 MacBook Pro(8コア)はフル 564.0s → 512.4s(−9%)、インクリメンタル 18.6s → 9.9s(−47%)、no-op 5.59s → 1.69s(−70%)です。インクリメンタルの削減率は手元と同じ −47%、no-op は M2 のほうが大きく、フルは手元のほうが小さく出ました(allmodconfig は手元で測っていないので並べません)。

/usr/bin/time -v の内訳も載せます。次の考察は、この表を根拠にしています。

種別(before → after) user time system time CPU 使用率
フル 2,522s → 2,515s 245s → 244s 741% → 756%
インクリメンタル 30.8s → 20.4s 5.9s → 4.7s 165% → 213%
no-op 11.1s → 5.1s 3.6s → 2.5s 470% → 598%

(3回の中央値。CPU 使用率は「user+system を経過時間で割った値」で、8スレッドが常に埋まっていれば800%)

考察 — 事実と推測を分けて

① フルビルドが −2.4% に留まった理由。 測れた事実は、user time が 2,522s → 2,515s とほとんど変わっていないことです。つまり、コンパイルの仕事量は before と after で同じで、縮んだ約9秒は「並列に走れなかった時間」の削減分です。概算するとこうなります。user+system の合計は before で約2,766秒、8スレッドが常に埋まっていれば 346秒で終わる計算なのに、実測は 374秒——差の約28秒が「8本埋まっていない時間」、すなわち直列の尾です。after では同じ計算が 345秒に対して 365秒で、差は約20秒。尾が28秒から20秒に縮んだ、という読みです(尾の間もスレッドは完全に空いてはいないので、あくまで概算)。ここからは推測ですが、この機械で defconfig を -j8 で回すと6分のうち5分半以上がコンパイルで、23パッチが削る objtool・modpost・kallsyms・gzip の絶対量は最初から十数秒〜数十秒しかない。コア数が少ないほどフルビルドはコンパイル支配になり、尾を削っても全体はほとんど動かない——§2 で表から読んだとおりの結果です。

② インクリメンタルと no-op は半分前後に。 事実として、インクリメンタルは 22.27s → 11.74s(−47.3%)、no-op は 3.12s → 1.27s(−59.3%)で、投稿者の主張(直列の尾の削減)が、12年前の4コア機でもそのまま出ました。内訳を見ると、インクリメンタルは user time が 30.8s → 20.4s と CPU の仕事量そのものが3分の2に減り、同時に CPU 使用率が 165% → 213% と並列度も上がっています。「無駄な仕事をやめる」と「直列を並列に」の両方が効いた形です。no-op は user time が 11.1s → 5.1s と半分以下、最大 RSS(time -v の Maximum resident set size=もっとも大きかった1プロセス)は約64MB → 約31MB でした。手元では工程別の時間は取っていないので、§1 の ASCII 図のように「objtool が何秒、modpost が何秒」と分解することはできません。ただ、no-op でやることはほぼ make が依存関係を読み直す処理なので(§1 の図でも before の no-op はほとんど m)、パッチ10・11(依存確認を C の depcheck に)の効果と符合する——これは推測です。

③ allmodconfig の −36% は、defconfig では出ない。 これは推測です。allmodconfig は1万個超のモジュールを作る構成で、modpost・*.mod.c のコンパイル・srcversion の計算は、モジュール数に比例して尾を長くします。投稿者の EPYC で allmodconfig の no-op が 25.92s もかかっていたのは、この尾の長さです。defconfig はモジュールにされるものが少ないので、削れる尾もそのぶん短い。手元で allmodconfig を測っていないため、§2 の表と各パッチの説明からの見立てにとどめます。

④ 常駐コンテナの影響は見えなかった。 事実として、Docker コンテナを止めずに測っても3回のばらつきは1%未満で、各回の開始時の load average(1分平均)は、直前のウォームアップの余韻が残るフル1回目(6.3・8.3)を除いて 1.7〜3.9 の範囲でした。フルの各回の間に置いた60秒の待ちで、2回目以降は 2〜3 まで落ちています。中央値と最良値の差もすべて 0.5s 以内なので、この条件では常駐サービスは結果に効いていないと見てよさそうです。

⑤ pigz は after だけで有効。 事実として、pigz 2.8 を入れた状態で測っているので、after ではパッチ23がそれを自動的に使い、before はパッチがないので gzip のままです。これは投稿者が示した条件(全効果を見るには pigz を入れておく)どおりで、after の数字には pigz の分が含まれています。pigz 単体の寄与(KGZIP=gzip で after を測り直す)は切り分けていません。

📌 自分の機械で見当を付けるなら

フルビルドの短縮を期待するより、日常のインクリメンタルと no-op が半分になる、と読むのが実感に近い——手元の結果はそう言っています。コア数が少なく defconfig 相当の構成なら、フルは数%で、体感はほぼ変わりません。逆に、1ファイル直して make を打つ22秒が12秒に、何も変えずに打つ3秒が1.3秒になる。これは開発中に何十回も打つ操作なので、こちらのほうが効きます。モジュールの多い構成とコア数の多い機械ではフルにも効く(投稿者の表)。どの機械でも、pigz は入れておくこと。


📌 筆者の見方(カーネル開発は専門外ですが)

筆者はカーネル開発が本業ではなく、ふだんは ESP32 の組み込みと、この記事を含むサイト運営が中心です。そのうえで今回いちばん引っかかったのは、カバーレターの分担表が、当サイトで記事を作っている体制とほとんど同じ形をしていたことでした。当サイトの記事は、AI が一次資料を集めて下書きを書き、人間がそれを読んで差し戻し、実機で確かめる部分は人間が手を動かします。「探索と実行は機械に、判断と保証は人に」という線の引き方は、まさに自分が毎日やっていることでした。

ただ、同じではない点が二つあります。一つは、握る深さです。当サイトの人間も下書きを監査して直し、足りなければ差し戻しますが、直すのは事実の裏づけや枠組みや見せ方で、直した記事をその後ずっと保守するわけではありません。Stoakes 氏の場合は「監査して、書き直して、自分が保守できる状態にする」ところまでが仕事です。9日の返信で「私は今後も自分の変更を保守できなければならない」と書いているとおり、対象がコードで、自分の名前で Signed-off-by を付け、その先ずっと責任を負うからです。生成物が「出して終わり」か「以後ずっと自分のもの」かで、人が握るべき深さが変わる——記事とカーネルパッチの差はそこにある、と受け止めました。

もう一つは、Assisted-by です。この系列は23コミット全部に付いていて、どこまでが機械でどこからが人か、読む側が最初から知っていて読める。当サイトの記事には、その1行に当たるものがありません。今のところ「AI と人が作っている」とサイト全体として言っているだけで、記事ごと・段落ごとの帰属はない。Linus が「怖かったが、読んだらひどくなかった」と書けたのは、事前に「hideous な部分は切除した」と知らされていたからで、帰属の1行があるから、読む側が構えを決められる。ここは、専門外の筆者がカーネルから素直に持ち帰りたいところです。

最後に、実測を人間がやることについて。この記事の §6 は、AI が手順書を書き、人間が自宅サーバーで約1時間かけて数字を出しました。投稿者が「性能の改善も手作業で検証した」と書いたのと同じ理由です。数字は AI に書かせるものではなく、手元の機械で出すもの。LLM がボトルネックを見つけるのは数分でも、それが自分の機械で本当に速いかを確かめるのは1時間かかる——2週間前に「生成が安くなったぶん検証を省いた投稿の迷惑さが増幅された」と書いた自分としては、ここだけは省けません。

まとめ

観点 内容
何が起きたか 2026年9月8日、Lorenzo Stoakes (ARM) が [PATCH 00/23] kbuild: significantly speed up kernel builds を投稿(47ファイル、+2,884/−682行)。9月14日に v2(21本・+2,982/−865行)を投稿
数字(投稿者の計測) allmodconfig フル 188.6s→121.1s(−36%)、インクリメンタル 82.0s→24.3s(−70%)、no-op 25.92s→1.52s(−94%)。いずれも2×EPYC 9754・gcc・best of several runs。8コアの M2 ではフル −8〜9%、no-op −70〜74%
第三者の追試 Broadcom の Fainelli 氏が EPYC 9454P で約13%、kbuild メンテナの Chancellor 氏が Ampere Altra で −13.2%、32コア AMD で −11.7%
手元の実測(9/12・§6) Ubuntu 26.04.1・Core i7-4790K(4コア8スレッド)・defconfig・-j8・3回の中央値:フル 373.59s→364.63s(−2.4%)、インクリメンタル 22.27s→11.74s(−47.3%)、no-op 3.12s→1.27s(−59.3%)。v1・7.3-rc2 ベース
何を変えたか 直列の尾を削る:mksysmap を C で再実装し nm を廃止、kallsyms をバイナリ出力に、依存確認を C(depcheck)に、*.mod.c を *.mod.S に、objtool の DWARF リロケーションを除外・並列化、pigz を既定に
LLM の使い方 ボトルネックの特定・改善案・コード生成・ビルドとテストのオーケストレーションを LLM が担当。「多くは hideous」で、投稿者が監査・書き直し・編集。正しさと性能は手作業で確認。全23コミット(v2 の21本も全部)に Assisted-by: LLM
Linus 「怖くて見なかったが、どれもひどくない。醜悪な部分は切除されている」「マージに全面的に賛成。正規の経路で。objtool は担当者の承認を」。04・15 には「アセンブリ経由をやめてオブジェクトを直接書け」と提案
v2 と Sashiko(9/14〜15) v2 で mksysmap 修正2本は上流入り(7.3-rc3)、srcversion 2本は別系列へ、rustc 並列は opt-in に(v3 で落とす予定)。AI レビュー Sashiko の9件の報告は「多くが幻覚」だが、CONFIG_RANDSTRUCT の順序・並列解読のレースなど4件を投稿者が検証して採用。Kees Cook 氏は「コミットログに LLM の冗長さ」と指摘
現在地(9/15) 未マージ・v2 レビュー中・v3 準備中。Reviewed-by は v2 スレッドにまだ無し
書いていないこと 使った LLM のモデル名・ツール名・プロンプトはカバーレターに記載なし(公式書式は要求していない)

投稿者は mm サブシステムで AI 由来パッチの流入を受ける側のメンテナで、「人に言っていること(監査しろ、直せ、理解しろ、明記しろ)を自分にも当てはめた」と書いています。前回の記事で見た「洪水」と、今回の「大物パッチ」は、道具が同じで握り方が違うだけです。そして Linus の返信が示したのは、コミュニティがそれを「AI が書いたかどうか」ではなく「読んでひどいかどうか」で判断した、ということでした。


よくある質問(FAQ)

Q. このパッチを当てれば、自分のカーネルビルドも36%速くなりますか?

36%は「2ソケット EPYC 9754(512スレッド)・gcc・allmodconfig のフルビルド」での投稿者の計測値です。効くのはコンパイル以外の直列部分なので、コア数が少ない機械ほどフルビルドの効きは小さくなります(投稿者の8コア M2 で −8〜9%、第三者の追試で −11〜13%)。一方、インクリメンタルと no-op は直列部分が大半なので、機械の大小によらず大きく縮みます(M2 で no-op −70〜74%)。当サイトの4コア8スレッド機(defconfig)でも、フルは −2.4% にとどまる一方、インクリメンタル −47%、no-op −59% でした(§6)。また、pigz を入れていないと圧縮の分は効きません。

Q. もう Linux に入っているのですか?

いいえ(2026年10月1日時点)。9月14日の v2(21本)のあと、9月17日に v3(20本)、9月23日に v4(22本)が投稿され、レビュー中です。v4 には Reviewed-by が付き始めています。以下は v2 時点の経緯です。先行して、v1 の前提だったバグ修正2本(mksysmap)はメインラインに入り(7.3-rc3・コミット 281b61d408d4・59351365ac27)、そのぶん v2 からは外れています。srcversion 関連の2本は上流の別系列に譲って v2 で落ち、rustc 並列フロントエンドの1本は Rust for Linux 側の指摘で「v3 で落とす」と投稿者が表明しました。objtool の3本は objtool メンテナのレビューを受けて、v3 でリロケーションのハッシュを撤去する予定です。マージされればこの記事に追記します。

Q. どの LLM を使ったのですか?

カバーレターにもコミットメッセージにも書かれていません。タグは Assisted-by: LLM のみで、これは公式ドキュメントが定める Assisted-by: LLM [TOOL1] [TOOL2] の書式に沿ったものです。公式ドキュメントはモデル名の明記を要求していません。本記事も推測で補いません。

Q. LLM が書いたコードがそのままカーネルに入るのですか?

カバーレターによれば、そうではありません。LLM が生成したコードの「多くは hideous」で、投稿者が「徹底的に監査し、多くを書き直し」、コミットメッセージ・コメントも大幅に編集し、ビルドと実機起動で正しさを手作業で確認したと書いています。公式ポリシーでも、AI は Signed-off-by を付けられず、人間の提出者がすべてをレビューし全責任を負うと定められています。Linus の返信も「醜悪な部分は明らかに切除されている」と、人の手が入った後のコードを評価しています。

Q. 出力が変わってしまう心配はないのですか?

各パッチのコミットメッセージが「変わらないこと」を個別に示しています。mksysmap の C 再実装では System.map がバイト単位で同一、*.mod.S 化ではモジュールの各セクションとリロケーションが8,135モジュールでバイト単位で同一、objtool の変更では出力がバイト単位で同一、pigz は同じツール同士なら再現可能(gzip と pigz の混在は不可、と文書に追記)。これらは投稿者の検証であり、レビューでさらに確認が進んでいる段階です。

Q. 2週間前の「AI パッチ洪水」の記事と、どう違うのですか?

道具は同じ LLM ですが、握り方が違います。洪水側の問題は、生成コストが投稿者に、検証コストがメンテナに乗る非対称性でした。今回は投稿者自身が監査・書き直し・実機検証・帰属明記をすべて引き受け、レビュー側の Linus は「読んだらひどくなかった」とコードで判断しています。投稿者は mm サブシステムで洪水を受ける側のメンテナでもあり、「人に課している条件を自分にも当てはめた」と明言しています。

Q. 自分のマシンで試すには?

v1 なら、カバーレターの base-commit: 28924df2a08f440c73991b83028032c901de2ae4(メインライン 7.3-rc2 直後)にチェックアウトし、b4 am(Ubuntu 26.04 なら apt install b4)で系列を取り込んで git am します。v2 なら base-commit は 704340f1cd0dcef829eb62f5b48ae95a2ce17bdf(7.3-rc3 直後)で、投稿者の数字と同じ条件にするには module_ver_remove v2 系列と objtool の noreturn 系列も先に当てる必要があります(v2 カバーレター冒頭の「IMPORTANT NOTE」)。全効果を見るには pigz を入れておくこと。手順と手元の実測結果(4コア8スレッド機・defconfig でインクリメンタル −47%、no-op −59%、フル −2.4%)は §6 に載せています。マージ前の系列なので、常用のカーネルではなく試験用のツリーで試してください。


関連記事


参考