Skip to content

【Zig 日报】自托管后端支持并行代码生成 #220

Open
@jiacai2050

Description

@jiacai2050

不到一周前,我们终于默认启用了 Linux 和 macOS 上 Debug 构建的 x86_64 后端。今天,我们对其进行了重大性能改进:我们进一步并行化了编译器流水线!

这些好处不会影响 LLVM 后端,因为它使用了更多的共享状态;事实上,它仍然仅限于一个线程,而在此更改之前,其他每个后端都能够使用两个线程。但是对于自托管后端,机器代码生成本质上是一个独立的任务,因此我们可以将其与所有其他任务并行运行,甚至可以并行运行多个代码生成作业。然后,生成的机器代码最终在链接器线程上粘合在一起。这意味着我们最终会得到一个线程执行语义分析,任意多个线程执行代码生成,以及一个线程执行链接。并行化这个阶段特别有益,因为 x86_64 的指令选择非常复杂,原因是该架构具有大量的扩展和指令。

这项工作最终形成了一个由我和 Jacob 创建的 PR#24124,几天前已合并。这是一项相当大的工作,因为需要重新设计编译器流水线的许多内部细节,以便将机器代码生成与链接器完全隔离。但最终一切都物有所值,因为性能得到了提升!使用自托管的 x86_64 后端,我们看到编译 Zig 项目的实际时间改进了 5% 到 50% 不等。例如,Andrew 报告说,他能够以 10 秒或更短的时间构建 Zig 编译器本身(不包括链接 LLVM,这会增加几秒钟的时间):

Benchmark 1 (32 runs): [... long command to build compiler with old compiler ...]
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          13.8s  ± 71.4ms     13.7s … 13.8s           0 ( 0%)        0%
  peak_rss           1.08GB ± 18.3MB    1.06GB … 1.10GB          0 ( 0%)        0%
  cpu_cycles          109G  ± 71.2M      109G  …  109G           0 ( 0%)        0%
  instructions        240G  ± 48.3M      240G  …  240G           0 ( 0%)        0%
  cache_references   6.42G  ± 7.31M     6.41G  … 6.42G           0 ( 0%)        0%
  cache_misses        450M  ± 1.02M      449G  …  451G           0 ( 0%)        0%
  branch_misses       422M  ±  783K      421M  …  423M           0 ( 0%)        0%
Benchmark 2 (34 runs): [... long command to build compiler with new compiler ...]
  measurement          mean ± σ            min … max           outliers         delta
  wall_time         10.00s  ± 32.2ms     9.96s … 10.0s           0 ( 0%)        ⚡- 27.4% ±  0.9%
  peak_rss           1.35GB ± 18.6MB    1.34GB … 1.37GB          0 ( 0%)        💩+ 25.7% ±  3.9%
  cpu_cycles         95.1G  ±  371M     94.8G  … 95.5G           0 ( 0%)        ⚡- 12.8% ±  0.6%
  instructions        191G  ± 7.30M      191G  …  191G           0 ( 0%)        ⚡- 20.6% ±  0.0%
  cache_references   5.93G  ± 33.3M     5.90G  … 5.97G           0 ( 0%)        ⚡-  7.5% ±  0.9%
  cache_misses        417M  ± 4.55M      412M  …  421M           0 ( 0%)        ⚡-  7.2% ±  1.7%
  branch_misses       391M  ±  549K      391M  …  392M           0 ( 0%)        ⚡-  7.3% ±  0.4%

作为另一个数据点,我测量了构建一个简单的“Hello World”所用时间缩短了 30%:

Benchmark 1 (15 runs): /home/mlugg/zig/old-master/build/stage3/bin/zig build-exe hello.zig
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           355ms ± 4.04ms     349ms …  361ms          0 ( 0%)        0%
  peak_rss            138MB ±  359KB     138MB …  139MB          0 ( 0%)        0%
  cpu_cycles         1.61G  ± 16.4M     1.59G  … 1.65G           0 ( 0%)        0%
  instructions       3.20G  ± 57.8K     3.20G  … 3.20G           0 ( 0%)        0%
  cache_references    113M  ±  450K      112M  …  113M           0 ( 0%)        0%
  cache_misses       10.5M  ±  122K     10.4M  … 10.8M           0 ( 0%)        0%
  branch_misses      9.73M  ± 39.2K     9.67M  … 9.79M           0 ( 0%)        0%
Benchmark 2 (21 runs): /home/mlugg/zig/master/build/stage3/bin/zig build-exe hello.zig
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           244ms ± 4.35ms     236ms …  257ms          1 ( 5%)        ⚡- 31.5% ±  0.8%
  peak_rss            148MB ±  909KB     146MB …  149MB          2 (10%)        💩+  7.3% ±  0.4%
  cpu_cycles         1.47G  ± 12.5M     1.45G  … 1.49G           0 ( 0%)        ⚡-  8.7% ±  0.6%
  instructions       2.50G  ±  169K     2.50G  … 2.50G           1 ( 5%)        ⚡- 22.1% ±  0.0%
  cache_references    106M  ±  855K      105M  …  108M           1 ( 5%)        ⚡-  5.6% ±  0.4%
  cache_misses       9.67M  ±  145K     9.35M  … 10.0M           2 (10%)        ⚡-  8.3% ±  0.9%
  branch_misses      9.23M  ± 78.5K     9.09M  … 9.39M           0 ( 0%)        ⚡-  5.1% ±  0.5%

顺便说一句,我非常喜欢一些好的 std.Progress 输出,所以我忍不住想说我现在多么喜欢看着编译器,看到它所做的所有工作:

即使有这些数字,我们在编译器性能方面仍然远未完成。未来对我们的自托管链接器的改进,以及将函数发出到最终二进制文件中的代码的改进,可能有助于加速链接,而链接现在有时是编译速度的瓶颈(您实际上可以在上面的 asciinema 中看到这个瓶颈)。我们还希望提高我们发出的机器代码的质量,这不仅使 Debug 二进制文件执行得更好,而且(可能与直觉相反)应该进一步加快链接速度。我们关注的其他性能工作包括减少编译器在编译结束时(其“刷新”阶段)所做的工作量,以消除另一个很大的开销,以及(在更遥远的未来)并行化语义分析。

也许最重要的是,增量编译——这是 Zig 项目多年来的长期投资——在某些情况下已经非常接近默认启用,这将允许对小的更改在几毫秒内重建。顺便说一句,请记住,只要您能接受可能的编译器错误,您现在就可以尝试增量编译并开始获得它的好处!如果您想了解更多相关信息,请查看跟踪问题。

闲聊够了——我希望你们都和我们一样对这些改进感到兴奋。Zig 的编译速度是有史以来最好的,并且希望是未来最差的 ;)

Parallel Self-Hosted Code Generation

加入我们

Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:

  1. 供稿,分享自己使用 Zig 的心得
  2. 改进 ZigCC 组织下的开源项目
  3. 加入微信群

Metadata

Metadata

Assignees

No one assigned

    Labels

    日报daily report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions