找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3289

积分

1

好友

443

主题
发表于 5 小时前 | 查看: 1| 回复: 0

Anthropic 最近发布了一篇引人注目的博客,介绍了他们完全使用 Claude Opus 4.6 构建的一个 C 编译器,并称之为 CCC (Claude‘s C Compiler)。团队声称它能够编译 Linux 内核,整个过程仅由人类通过编写测试用例来引导。这听起来相当有趣,也值得我们去验证这一说法,并将其与业界标准的 GCC 进行一番深入的基准测试。

Anthropic官方发布的Claude C编译器文章截图

CCC 的源代码可以在其 GitHub 仓库 找到。它完全用 Rust 编写,支持 x86-64、i686、AArch64 和 RISC-V 64 架构。其前端、基于 SSA 的 IR、优化器、代码生成器、窥视优化器、汇编器、链接器以及 DWARF 调试信息的生成,都是从零开始实现的,没有任何编译器特定的依赖。对于 AI 而言,这无疑是一项巨大的工作量。

编译流程简述:编译器、汇编器与链接器

在开始对比之前,有必要先了解一下编译一个 C 程序时究竟发生了什么。这个过程通常涉及四个主要阶段。

C程序编译的四个阶段流程图

  1. 预处理器:处理 #include#define 等指令,接收源代码并生成扩展后的源代码。
  2. 编译器:将预处理后的源代码翻译成汇编语言。这是最复杂的部分,涉及 C 语言的理解、类型检查、优化、寄存器分配等。
  3. 汇编器:将汇编语言转换为机器码(目标文件)。它必须精确知道目标 CPU 架构的指令编码。
  4. 链接器:将一个或多个目标文件合并成一个可执行文件。它负责解析文件之间的引用、设置内存布局并生成最终的二进制文件。

为什么构建一个优秀的编译器如此困难?

编写一门编程语言本身已经很具挑战性,而构建一个编译器则是另一个维度的难题。编程语言定义了规则,而编译器必须理解这些规则,将其翻译成机器指令,为速度和体积进行优化,处理不同 CPU 架构的边缘情况,并且每次都能生成正确的代码。

GCC 自 1987 年开始开发,近 40 年的工作中凝聚了成千上万贡献者的智慧。它支持数十种架构,实现了数百种优化,并修复了数不清的边缘案例。仅仅是优化过程(如寄存器分配、函数内联、循环展开、向量化、死代码消除、常量传播)就代表了多年的博士级研究。这也是它如此普及和强大的原因。

因此,CCC 能够编译真实的 C 代码本身已经非常值得注意。但这同时也解释了为何它的输出质量目前还远不如 GCC。构建一个能正确解析 C 语言的编译器是一回事,而构建一个能生成高效机器代码的编译器则是一个完全不同的挑战。

测试对象选择:SQLite 与 Linux 内核

Linux 内核是全球最复杂的 C 代码库之一,有数百万行代码,使用了大量 GCC 特定扩展、内联汇编、复杂的链接脚本。它并不是一个新编译器理想的入门测试对象。

相比之下,SQLite 则是一个更纯粹、标准化的选择。它以单一的合并 .c 文件分发,是经过充分测试的自包含标准 C 代码。如果一个编译器能正确处理 SQLite,那它就能应对很多其他项目;反之,则没有必要测试更大的项目。

因此,本次测试涵盖了这两个项目:SQLite 用于验证编译器的正确性和运行时性能;Linux 内核则用于测试其扩展性和兼容性。

测试环境与方法论

测试设置:

  • 虚拟机:2 台基于 Debian 的 Proxmox 虚拟机,每台配置 6 vCPU, 16GB RAM, 100GB NVMe 磁盘。
  • GCC:GCC 14.2.0 (Debian 14.2.0-19)。
  • CCC:Claude‘s C Compiler,通过源码构建,启用 --features gcc_m16 选项以处理 16 位启动代码。
  • 内核:Linux 6.9 (x86_64 defconfig)。
  • SQLite:SQLite 3.46.0 合并版。

CCC 通过一个包装脚本 (ccc_wrapper.sh) 将 .S 汇编文件路由给 GCC 处理(因为 CCC 不处理汇编),所有 .c 文件则由 CCC 处理。

方法论: 编译器通常从以下几个维度衡量,测试也围绕这些方面设计:

  1. 编译代码的时间
  2. 编译后代码的大小
  3. 编译后代码的执行速度
  4. 编译器自身的内存使用
  5. 生成代码的稳定性(错误与崩溃概率)

公平比较原则:

  1. 相同的硬件规格。
  2. 相同的源代码(内核配置与 SQLite 版本)。
  3. 测试都运行到完成,不提前终止。
  4. CCC 在必要时得到帮助(如通过 gcc_m16 功能处理启动代码)。
  5. 使用相同的基准测试脚本。

结果总览

指标 GCC CCC 比率/备注
内核构建时间 73.2 分钟 42.5 分钟 CCC 未能完成链接
内核构建结果 成功生成 vmlinux 链接失败
内核峰值内存 831 MB 1,952 MB CCC 高出 2.3倍
SQLite 编译 (-O0) 64.6 秒 87.0 秒 CCC 慢 1.3倍
SQLite 二进制大小 1.55 MB 4.27 MB CCC 大 2.7倍
SQLite 运行时 (-O0) 10.3 秒 2 小时 06 分 CCC 慢 737倍
SQLite 运行时 (-O2) 6.1 秒 2 小时 06 分 CCC 慢 1,242倍
编译器内存使用 272 MB 1,616 MB CCC 高出 5.9倍
崩溃/段错误测试 5/5 通过 5/5 通过

需要特别注意,只有在与 GCC 的 -O2 优化级别(耗时7分多钟)对比时,CCC 的编译时间才会显得“快5倍”,但这仅仅是因为 CCC 完全跳过了优化工作。在公平的 -O0 (无优化) 对比中,CCC (87秒) 实际上比 GCC (65秒) 慢了约 25%。

Linux 内核 6.9 编译测试

Linux Kernel 6.9 编译性能对比图

指标 GCC 14.2.0 CCC
实际构建时间 73.2 分钟 42.5 分钟 (仅编译.c文件)
用户态CPU时间 379.7 分钟 192.3 分钟
峰值内存使用 831 MB 1,952 MB
编译的C文件数 2,844 2,844
编译器错误 0 0
链接器错误 0 40,784
最终结果 成功生成 vmlinux 链接失败

发生了什么?
CCC 成功编译了 Linux 6.9 内核中的 每一个 C 源文件,且没有任何编译器错误(0错误,96警告)。对于一个完全由 AI 构建的编译器来说,这确实令人印象深刻。

然而,在链接阶段,构建失败了,产生了约 40,784 个“未定义引用”错误。错误主要分为两类:

  1. __jump_table 重定位错误:CCC 为内核跳转标签(用于静态键/追踪点)生成了错误的重定位条目。
  2. __ksymtab 引用错误:CCC 为内核模块导出生成了格式错误的符号表条目。

这些是链接器可见的错误,源于 CCC 在重定位/符号生成阶段的缺陷,而非 C 语言编译错误。这也印证了链接器是整个工具链中最复杂的部分。

内核编译期间系统资源使用监控图

SQLite 3.46 基准测试

SQLite 3.46 全方位基准测试对比图

编译表现

指标 GCC -O0 GCC -O2 CCC
编译时间 64.6 秒 7 分 23 秒 1 分 27 秒
编译器峰值内存 272 MB 370 MB 1,616 MB
生成的二进制大小 1.55 MB 1.40 MB 4.27 MB

一个关键发现:CCC 使用 -O0-O2 标志编译出的二进制文件字节完全一致 (4,374,024 字节)。CCC 虽然有 15 个 SSA 优化过程,但它们在任何优化级别下都会执行。-O 标志被接受但被完全忽略,没有分级优化。

为何这很重要?
当使用 GCC -O2 编译时,它会执行几十个额外的优化过程:指令选择、寄存器分配、循环展开、函数内联、死代码消除、向量化等。GCC 花费 7 分钟进行这些优化,效果显著:-O2 二进制运行速度比 -O0 快 1.7 倍。
CCC 则完全没有这些优化工作。将“CCC 编译时间”与“GCC -O2 编译时间”对比,就像比较黑白打印机和彩色打印机。黑白打印机更快,但完成的是完全不同的任务。

运行时性能

指标 GCC -O0 GCC -O2 CCC
总运行时间 10.3 秒 6.1 秒 2 小时 06 分
用户态CPU时间 9.68 秒 5.46 秒 7,518 秒
程序峰值内存 7.4 MB 7.0 MB 9.6 MB

CCC 编译的 SQLite 在功能上是正确的——所有查询结果与 GCC 版本一致,5 个崩溃/边缘情况测试也全部通过。但它的运行速度极慢

逐查询性能剖析

SQLite 各查询性能对比及CCC慢速因子分析图

性能下降并非均匀。简单查询仅慢 1 到 7 倍,但涉及嵌套循环的复杂操作则呈指数级变慢:

查询 操作 GCC -O0 CCC 慢速因子
Q18 WHERE a NOT IN (SELECT a FROM test2) 0.047s 7,432s 158,129x
Q38 跨表连接 + GROUP BY 0.002s 52.5s 26,235x
Q19 WHERE a IN (SELECT a FROM test2) 0.020s 15.5s 777x
Q16 INNER JOIN ON (count) 0.003s 1.06s 354x
Q21 UPDATE … WHERE d < 50 0.016s 1.31s 82x
Q03 GROUP BY d ORDER BY COUNT(*) DESC 1.218s 8.39s 6.9x
Q01 插入 100K 行 0.065s 0.113s 1.7x
Q42 删除表 0.051s 0.057s 1.1x

显然,涉及嵌套迭代(子查询、连接)的操作慢了数个数量级,而简单的顺序操作仅略慢。

根本原因分析:为什么 CCC 的代码如此之慢?

  1. 严重的寄存器溢出
    现代 CPU 拥有少量高速的寄存器。优秀编译器会尽量将频繁使用的变量保存在寄存器中。当变量过多时,它们会被“溢出”到较慢的堆栈内存中。
    CCC 最致命的问题就是极度的寄存器溢出。SQLite 的核心函数 sqlite3VdbeExec 有上百个局部变量和一个巨大的 switch 语句。由于 CCC 缺乏良好的寄存器分配,它几乎将所有变量都溢出到堆栈。
    GCC -O0 生成的代码片段 (高效使用堆栈):

    movl    -8(%rbp), %eax      ; 加载循环计数器
    cmpl    -36(%rbp), %eax     ; 与 n 比较
    jl      .L6                  ; 条件跳转
    movl    (%rax), %edx         ; 直接从内存加载 a[i]
    cmpl    %eax, %edx           ; 在寄存器中比较

    CCC 生成的代码片段 (严重的内存搬运):

    movq    -0x1580(%rbp), %rax  ; 从很深的堆栈偏移量加载
    movq    %rax, -0x2ae8(%rbp)  ; 存到另一个很深的堆栈偏移量
    movq    -0x1588(%rbp), %rax  ; 加载下一个值
    movq    %rax, -0x2af0(%rbp)  ; 存到下一个偏移量
    ; ... 还有几十次类似的内存拷贝

    CCC 使用了深达 -0x2ae8 (约11KB) 的堆栈偏移量。每个操作都遵循 堆栈 -> 寄存器 -> 堆栈 的模式,使用 %rax 作为临时的传递寄存器。

  2. 优化标志 (-O2 等) 完全无效
    CCC 在所有优化级别下运行相同的 15 次 SSA 优化。

    $ diff <(ccc -O0 -S test.c -o -) <(ccc -O2 -S test.c -o -)
    (没有差异)

    这意味着 -O2 没有任何效果,每个 CCC 生成的二进制文件本质上都是 -O0 质量。

  3. 代码膨胀
    CCC 生成的代码量是 GCC 的 2.78 倍 (838,359 行汇编 vs 301,424 行)。更大的代码量导致更多的指令缓存未命中,进一步放大了寄存器溢出带来的性能惩罚。

  4. 损坏的帧指针与缺失的调试信息
    调试 CCC 编译的程序时,堆栈回溯显示帧指针数据损坏,且二进制文件中缺少内部函数符号,使得性能分析和调试几乎无法进行。

为何子查询慢了 158,000 倍?
NOT IN (子查询) 模式导致 SQLite 执行嵌套循环:外表的 10 万行,每一行都要扫描内表的 1 万行数据,总计约 10 亿次迭代,每次迭代都调用庞大的 sqlite3VdbeExec 函数。
由于 CCC 的每次迭代有约 4 倍的开销(寄存器溢出),加上 2.78 倍代码膨胀带来的额外缓存未命中,性能惩罚是复合性的,最终导致超过 10 万倍的总体慢速。

主要发现与总结

CCC 的成功之处:

  1. 正确性:成功编译了内核所有 C 文件 (0错误),并为 SQLite 所有查询生成了正确结果。
  2. 稳定性:所有测试未出现崩溃或段错误。
  3. GCC 兼容性:接受大多数 GCC 命令行标志,可作为替代品进行编译尝试。

CCC 的不足与局限:

  1. 极差的运行时性能:复杂操作慢 737 倍至 158,000 倍。
  2. 链接器不兼容:无法处理内核复杂的重定位需求,链接失败。
  3. 巨大的代码体积:二进制文件是 GCC 的 2.7-3 倍大。
  4. 高内存消耗:编译时内存使用是 GCC 的 5.9 倍。
  5. 伪优化支持-O0-O3 的输出完全相同。
  6. 缺失调试支持:缺乏 DWARF 信息,帧指针损坏,无函数符号。
  7. 编译速度:在公平的 -O0 对比中,CCC 比 GCC 慢约 25%。

总结评分

类别 胜者 备注
编译速度 GCC GCC -O0 比 CCC 快 25%
二进制大小 GCC CCC 的二进制大 2.7-3 倍
运行时速度 GCC CCC 慢 737 倍到 158,000 倍
编译器内存 GCC CCC 多消耗 2.3-5.9 倍 RAM
正确性/稳定性 平局 两者均通过所有测试
优化层级支持 GCC CCC 完全忽略 -O 标志
内核链接能力 GCC CCC 在链接阶段失败

一个尴尬的起点:无法编译 Hello World

在 Anthropic 发布 CCC 后的几小时内,GitHub 上就出现了 Issue #1 —— “Hello world 无法编译”。即使是 README 中的示例代码,在新安装的系统上也失败了:

$ ./target/release/ccc -o hello hello.c
/usr/include/stdio.h:34:10: error: stddef.h: No such file or directory
/usr/include/stdio.h:37:10: error: stdarg.h: No such file or directory
ccc: error: 2 preprocessor error(s) in hello.c

与此同时,GCC 顺利完成了编译。问题在于 CCC 的预处理器没有在正确的系统路径中查找编译器自带的头文件(如 stddef.h)。该问题获得了大量关注,许多人评论道“我的工作很安全”。截至目前,这个问题依然处于开放状态。

结论

Claude‘s C Compiler (CCC) 无疑是一个引人注目的成就。它证明了 AI 有能力从零开始构建一个功能基本正确的 C/C++ 编译器,并能编译像 Linux 内核这样复杂的项目中的数千个文件。

然而,它距离生产环境使用还有很长的路要走:

  1. 生成的代码效率极低,核心问题是糟糕的寄存器分配算法。
  2. “编译 Linux 内核”的声明需要加注:它成功编译了所有 C 文件,但未能成功链接生成最终的可执行内核。
  3. 优化系统形同虚设,无法产生不同优化级别的代码。

对于 Anthropic 证明 Claude 能构建复杂软件的目标而言,CCC 是一次巨大的成功。但对于任何追求高性能、高可靠性软件编译的开发者而言,GCC、Clang 等成熟的编译器依然是唯一务实的选择。

复现方法

前提条件

  • 两台虚拟机(建议 >=6 vCPU, 16GB RAM, 50GB 磁盘)。
  • Debian/Ubuntu 环境,安装 build-essential, cargo, git, flex, bison, bc, libelf-dev, libssl-dev

构建 CCC

git clone https://github.com/anthropics/claudes-c-compiler
cd claudes-c-compiler
cargo build --release --features gcc_m16

运行基准测试

# 内核测试
bash scripts/benchmark_kernel.sh gcc /usr/bin/gcc results/kernel_gcc
bash scripts/benchmark_kernel.sh ccc /path/to/ccc_wrapper.sh results/kernel_ccc

# SQLite测试
bash scripts/benchmark_sqlite.sh gcc gcc results/sqlite_gcc_v2
bash scripts/benchmark_sqlite.sh ccc /path/to/ccc_wrapper.sh results/sqlite_ccc_v2

生成图表

python3 -m venv .venv
.venv/bin/pip install matplotlib numpy
.venv/bin/python scripts/analyze.py

所有用于测试和对比的脚本、结果及图表均可在 compare-claude-compiler 仓库找到。


引用链接
[1] Building a C compiler with a team of parallel Clauses
[2] claudes-c-compiler GitHub Repository
[3] Issue #1: Hello world fails to compile
[4] compare-claude-compiler (基准测试代码仓库)

本文旨在提供深度的技术对比与分析,相关讨论欢迎在云栈社区的对应板块进行。




上一篇:C++虚函数指针初始化时机解析:构造函数中的静态绑定
下一篇:AI信息焦虑应对指南:如何搭建个人化工作流过滤系统
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-10 06:56 , Processed in 0.419231 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表