性能
了解 CK 如何让专注的计算高效运行。
CK 面向数值计算内核:这类紧凑、计算密集的例程通常嵌入较大的应用中。下方在同一台机器上,用 CK、C++、Rust、Node.js 上的 JavaScript、Java,以及 Python 的 NumPy,运行相同的两项计算。对比的是这组具体实现与构建方式,不是对语言整体性能的排名。
同机性能对比#
首页图表对每项工作负载都选取六种语言的调优版。图中倍率标签为 JavaScript 调优版中位数除以所选调优版中位数,并作了显示舍入;因此 JavaScript 为 1.0×,柱状数据按速度从快到慢排序。柱长使用对数视觉刻度,以便容纳较大的性能差异,不能按线性比例解读。各实现采用的调优方法不同,图表并非在完全相同的优化级别下比较。下方两张表保留了两项工作负载中十二种实现的完整常规版和调优版数据。
每个数字是完整计算一次的运行时间中位数,单位为毫秒;越低越快。“常规”和“调优”指本测试中对应的具体实现,并不代表某种语言普遍的优化等级。
256 × 256 矩阵乘法#
| 实现 | 常规(毫秒) | 调优(毫秒) |
|---|---|---|
| CK | 9.315268 | 1.869669 |
| C++ | 9.329641 | 1.866093 |
| Rust | 9.685109 | 1.893518 |
| JavaScript(Node.js) | 11.875417 | 10.087641 |
| Java(OpenJDK 21) | 9.734412 | 3.116292 |
| NumPy(Apple Accelerate) | 0.094030 | 0.086155 |
1024 × 1024 高斯卷积(3 × 3)#
| 实现 | 常规(毫秒) | 调优(毫秒) |
|---|---|---|
| CK | 1.032351 | 0.597181 |
| C++ | 0.533230 | 0.532288 |
| Rust | 0.552982 | 0.547729 |
| JavaScript(Node.js) | 7.873651 | 2.203127 |
| Java(OpenJDK 21) | 1.595859 | 1.041701 |
| NumPy | 3.306759 | 3.443799 |
这两项计算呈现了不同的性能特点。矩阵乘法中,NumPy/Apple Accelerate 调优版最快,用时 0.086 毫秒;CK、C++ 和 Rust 调优版约需 1.87–1.89 毫秒,Java 为 3.116 毫秒,JavaScript 为 10.088 毫秒。NumPy 的 @ 会调用原生 Accelerate 矩阵库,因此这并不代表 Python 循环本身的速度。图像卷积中,调优 C++ 和 Rust 约需 0.53–0.55 毫秒,CK 为 0.597 毫秒,Java 为 1.042 毫秒,JavaScript 为 2.203 毫秒。NumPy 调优向量表达式用时 3.444 毫秒,略长于常规版的 3.307 毫秒。结果会随算法形态和库而变化,不代表对语言整体性能的排名。
测试条件#
测试机器为 Apple M5 Max,运行 macOS 25.6,架构为 arm64。CK 编译器版本记录在原始测量报告中;其他工具链版本为 Apple Clang 21.0.0、Rust 1.90.0、Node.js 24.14.0、OpenJDK 21.0.8、Python 3.12.14 和 NumPy 2.3.5。两项工作负载分别是 256 × 256 的 f64 矩阵乘法,以及对 1024 × 1024 的 f64 图像执行 3 × 3 高斯滤波。NumPy 矩阵乘法使用 Apple Accelerate 后端:常规版使用 A @ B,再将结果复制到给定输出;调优版使用 np.matmul(..., out=...)。卷积常规版使用会创建中间数组的 NumPy 向量表达式;调优版重复使用预分配的临时数组。C++、Rust 和 CK 使用 O3 构建;常规实现面向可移植 CPU 基线,调优实现启用本机 CPU 特性并采用连续访问矩阵行的循环顺序。JavaScript 和 Java 使用持续运行并预热的进程;Java 使用 OpenJDK 21。针对 NumPy 矩阵乘法所用的库调用,运行器通过环境变量请求 BLAS 使用单线程策略;实际 Accelerate 内部工作线程数未经独立确认。
每个实现都按交错顺序进行七轮测量,表中给出中位数。编译、进程启动、输入准备、初始化和输出哈希计算均不计入运行时间。JavaScript、Java 和 NumPy 的持续运行进程会将语言层面的重复循环与每次函数分派计入计时。计时前,会将每个实现的完整输出缓冲区与独立参考结果进行 SHA-256 对比;两项工作负载中的十二种实现均与参考结果匹配。矩阵乘法参考值:a70e525b589edae101181e5ad5f5acc36c8ce2e77fd54a7222a15faf9b4a62ac。卷积参考值:7744d264c90a3103680087a715d70ab36a8effc8e9a93e58ec0f0f85dbb4c71a。
详见 M5 Max 原始测量报告、可复现的基准测试方法,或查看首页性能图表。
结果取决于具体算法、库、编译器与运行时版本、机器和输入规模。特别是,NumPy 矩阵乘法结果包含对原生优化库的调用,其他矩阵实现则是直接编写的计算内核。应把这些数字视为对这组测试的可复现实测,而不是对其他应用的性能预测。做出性能判断前,应在目标机器上测量自己的代表性工作负载。
另一组在 AMD EPYC 上进行的历史 CI 测量报告(2026 年 9 月)仍可查阅。它采用不同的计算任务和机器,不应与上面的图表数值合并比较。
CK 为什么能高效运行#
编译为原生机器码#
ckc run 和 ckc build 会将 .ck 程序编译为适用于目标架构的原生机器码。常规构建使用可移植的 CPU 基线;针对特定 CPU 的变体需要主动选择。程序执行计算时不需要 CK 解释器。两条命令默认生成 O3 优化构建;O3 是编译器设置,不代表速度倍数。
按明确条件进行优化#
对于合适的循环,CK 可以使用 SIMD(单指令多数据)一次处理多个互不依赖的值,也可以减少重复工作。只有满足正确性条件且目标处理器支持时,编译器才会应用这些变换。存在数据依赖或不符合条件的循环会保留常规执行路径。
根据真实工作负载调优#
对于已经完成、且有代表性工作负载的程序,PGO 可以利用观察到的运行模式指导代码生成。它会增加构建步骤;只有测试负载接近程序的实际用法时才有帮助。先使用常规构建,再根据测量结果决定是否启用 PGO 或 CPU 变体。
继续学习#
链接到仓库的完整参考文档以 main 分支为准,可能包含尚未进入最新下载版本的功能。