提速Rust编译器!

Nethercote是一位研究Rust编译器的软件工程师。最近,他正在探索如何提升Rust编译器的性能,在他的博客文章中介绍了Rust编译器是如何将代码分割成代码生成单元(CGU)的以及rustc的性能加速。

他解释了不同数量和大小的CGU之间的权衡以及Rustc是如何使用LLVM并行化代码生成和优化的。此外,Nethercote还探索了一些形成和排序CGU的替代方法,并报告了他的实验结果。

Nethercote发现,很多时候,无法在编译速度、内存占用、编译体积和质量上都实现提升,一个指标的提升,经常伴随另一个性能指标的下降。尽管他没有发现比现有方法更明显的改进,但还是希望在未来继续研究这个问题。

如何提升Rust编译器速度?这篇文章或许能帮助到你!

1、LLVM:Rust编译加速的秘诀

Rust的MIR是HIR到LLVM IR的中间产物,将MIR转换为LLVM IR,然后将其传递给LLVM,从而生成机器代码。在此过程中,LLVM能通过处理多个模块实现并行。Rustc使用LLVM加速Rust的编译。我们称其中的每个模块为“代码生成单元(CGU)”。

图片

图:时间位于 x 轴上,每条水平线代表一个线程。主线程显示在顶部,标有 PID。它在开始时处于活动状态,时间足以产生另一个标记为 的线程rustc。rustc底部显示的线程在大部分执行过程中都处于活动状态。还有 16 个 LLVM 线程标记opt cgu.00为 到opt cgu.15,每个线程都会在短时间内处于活动状态。

CGU实际上是如何形成的呢?粗略地说,Rust 程序由许多函数组成,这些函数形成一个有向图,其中从一个函数到另一个函数的调用构成了一条边。我们需要将这个图分割成块(CGU),这是一个图分区问题。我们希望创建大小大致相等的 CGU(因此 LLVM 处理它们所需的时间长度大致相同),并最大限度地减少它们之间的边数(因为这使 LLVM 的工作更轻松,并带来更好的代码质量) 。

实际上,由于我们上面看到的阶梯效应,我们不希望 CGU 的大小完全相同。理想的情况是 CGU 大小存在与梯度相匹配的轻微梯度。这样,所有 CGU 将完全相同地完成处理,以实现最大程度的并行化。

合并之前的CGU(9个)

合并之前的CGU(9个)

Nethercote认为在合并之前“调整”CGU可能会有所帮助,在某些情况下将函数从一个CGU移动到另一个。例如,如果在CGU A中被调用f的叶函数(即不调用任何其他函数的叶函数)在CGU B中有一个调用方g,那么将f从A移动到B是有意义的,从而去除CGU间的边。(还有其他类似的情况涉及非叶函数,移动也有意义)。我实现了这一点,它给出了一些适度的改进,但我目前还没有决定它是否值得额外的复杂性。

调整之后的CGU(5个)

调整之后的CGU(5个)

在实现这一点的同时,我还花了一些时间来可视化调用图。我从GraphViz开始。这些图表对于非常小的程序来说看起来不错,但对于较大的程序来说,它们很快就变得无法读取和导航。我在Mastodon上抱怨过这一点,并得到了使用d2的建议,d2速度较慢,但图形可读性更强。

图片

2、后端并行方法的软肋

图划分是一个 NP 难题。有几种常见的算法,实现起来相当复杂。相反,rustc 做了一些更简单的事情。首先简单地为每个 Rust 模块创建一个 CGU:模块中的每个函数都放入同一个 CGU 中。然后,如果 CGU 数量超过限制(默认情况下,非增量构建为 16 个,增量构建为 256 个),它会重复合并两个最小的 CGU,直到达到限制。这种方法简单、快速,并以有用的方式利用特定领域的知识——程序模块往往提供良好的自然边界。

所有这一切都依赖于测量 CGU 大小的方法。目前使用CGU中的MIR语句的数量来估计LLVM处理CGU需要多长时间。这里有很大的设计空间,有许多其他可能的形成和规划CGU 的方法。

图片

这种转换对Rust众多语法糖进行了脱糖,并且极大精简了Rust的语法(但并非其语法子集),是观察和分析Rust代码的常用手段,尤其是在控制流图和借用检查等方面。

在这篇文章的最后,Nethercote提供了几个数据集的链接,每个数据集都记录了编译rust -performance基准时每个CGU的测量值。这些数据集包括许多测量静态代码大小的输入(独立变量),例如,函数数量和MIR数量等。

Nethercote试着用scikit-learn做一些基本的分析。并且,通过这些基本的分析,能让Nethercote仔细推敲到底应该搜集哪些测量值。

通过一系列的改进优化,他获得的最终数据集比刚开始时的数据更准确。但是,并没有通过这些数据获得多少实际的结果。实际上,每次我对测量的内容改变后都会得到完全不同的结果。

3、实现更快的Lexer

词法分析(lexical analysis)是编译器的第一个阶段,实现词法分析的代码称为lexer。

有人最近研究了logos(https://github.com/maciejhirsz/logos)这个在rust中广受欢迎的lexer。

此前,logos声称其目标是能比手动实现的lexer更快,作者提出了质疑,因为在他看来,通用性和性能无法兼得。因此,他一步步实现了lexer,探索了多种优化技巧,并与logos进行了多轮性能对比。

最终的结果表明,手动实现的基于状态机的lexer比logos实现了20%左右的性能提升。

4、从错误中学习:使用Rust实现DLL注入

Rust是一种注重安全性的编程语言,但在某些情况下,开发人员可能需要使用unsafe关键字来执行某些操作。unsafe可以提供更高的性能,但可能会牺牲安全性。因此,开发人员在使用时需要非常小心。几个使用unsafe的常见场景包括:访问裸指针、调用外部C函数等,并提供了一些建议和最佳实践,以确保在使用unsafe时不会引入潜在的安全隐患。

举个应用方面的例子:原来,作者一直在用C++编写逆向工具,但是,C++这门语言并不友好,于是研究了下如何使用Rust实现DLL注入的“工具”。

大致原理就是让Rust首先生成一个C样式的DLL,然后,使用unsafe操作裸指针,操作程序内存,最后实现DLL注入就可以了。

5、期待更准确的估计函数

Nethercote 希望具有数据分析专业知识的人可以做得更好,重点关注以下几个方面:

1)更匹配的估计函数

2)想要使编译器比现在更快,一个更好的估计函数也许不会达到预期的效果。我提出了一些更好的统计方法,但并没有提升编译速度,甚至变差。

3)CGU调度效果不可预测,你不能假设一个估计函数好几个百分点就会使编译器更快。话虽如此,我希望改进力度足够大,能够转化为实际的加速。

4)对于估计函数来说,最好高估CGU编译所需的时间,而不是低估。

5)我很担心过度拟合。数据集来自一台机器,但实际上,rustc会运行在不同的机器上,具有各种各样的体系结构和微体系结构。

6)这些数据集来自单一版本的rustc,使用单一版本的LLVM。我担心随着时间的推移准确性可能会漂移。

7)我更喜欢不太复杂且易于理解的估计函数。当前的函数非常简单,在大多数情况下只是增加了基本模块和语句的数量。例如:0大小的CGU应该别估计为花费非常接近于0的时间。

8)估计函数有一个明确的问题,即如果不考虑其内部公式,计算MIR语句可能非常不准确。特别是,单个MIR语句可能变得很长。举个例子:深度向量压力测试的MIR包含一条语句,该语句定义了包含超过100,000个元素的向量字面量。不出所料,当前的估计函数严重低估了编译这个基准所需的时间。

Nethercote最后提醒:希望以上的请求是合理的!

以下是上文提到的数据集:

  • 调试构建,主要基准测试

https://nnethercote.github.io/aux/2023/07/25/Debug-Primary.txt

  • 选择构建,主要基准

https://nnethercote.github.io/aux/2023/07/25/Opt-Primary.txt

  • 调试构建,二级基准测试

https://nnethercote.github.io/aux/2023/07/25/Debug-Secondary.txt

  • 选择构建,二级基准

https://nnethercote.github.io/aux/2023/07/25/Opt-Secondary.txt

  • 顺便说一句:在这些数据集中,主要基准测试比次要基准测试更重要,次要基准测试包括压力测试、微基准测试和其它不符合实际的代码。

相关内容拓展:(技术前沿)

近10年间,甚至连传统企业都开始大面积数字化时,我们发现开发内部工具的过程中,大量的页面、场景、组件等在不断重复,这种重复造轮子的工作,浪费工程师的大量时间。

针对这类问题,低代码把某些重复出现的场景、流程,具象化成一个个组件、api、数据库接口,避免了重复造轮子。极大的提高了程序员的生产效率。

推荐一款程序员都应该知道的软件JNPF快速开发平台,采用业内领先的SpringBoot微服务架构、支持SpringCloud模式,完善了平台的扩增基础,满足了系统快速开发、灵活拓展、无缝集成和高性能应用等综合能力;采用前后端分离模式,前端和后端的开发人员可分工合作负责不同板块,省事又便捷。

体验官网:https://www.jnpfsoft.com/?csdn,还没有了解低代码这项技术可以赶紧体验学习!

参考资料:

1.https://nnethercote.github.io/2023/07/25/how-to-speed-up-the-rust-compiler-data-analysis-assistance-requested.html

2.https://geo-ant.github.io/blog/2023/unsafe-rust-exploration/

3.https://nnethercote.github.io/2023/07/11/back-end-parallelism-in-the-rust-compiler.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/62355.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C语言]深入浅出,带你构建C语言宏观框架

导言: 本文章会带你基本了解C语言,对他有一个感性的认识,对其有一个框架,后期在对其进行更加细致的补充。 文章目录 C语言第一个函数变量局部变量 与 全局变量常量字符串 与 转义字符 头文件分支 与 循环注释数组关键字操作符宏指…

【Go语言】Golang保姆级入门教程 Go初学者chapter2

【Go语言】变量 VSCode插件 setting的首选项 一个程序就是一个世界 变量是程序的基本组成单位 变量的使用步骤 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zuxG8imp-1691479164956)(https://cdn.staticaly.com/gh/hudiework/imgmain/image-20…

HTTP代理授权方式介绍

在网络爬虫过程中,我们经常需要使用HTTP代理来实现IP隐藏、突破限制或提高抓取效率。而为了确保代理的正常使用,并避免被滥用,代理服务商通常会采用授权方式。在本文中,我们将介绍几种常见的HTTP代理授权方式,以帮助你…

【React学习】—jsx语法规则(三)

【React学习】—jsx语法规则(三) 一、jsx语法规则: 1、定义虚拟DOM,不要写引号, 2、标签中混入JS表达式要用{} 3、样式的类名指定不要用class,要用className 4、内联样式,要用style{{key:value}…

奋斗四个月,我要上西工大

距离考研初试还有135天,今天我参观了西北工业大学,看到了《何尊组雕》,让我肃然起敬。 西北工业大学,国防七子,我也不知道自己能否够得着,也许只有时间能带给我答案。 在过去三年的积累中,我的…

iOS开发-WebRTC本地直播高分辨率不显示画面问题

iOS开发-WebRTC本地直播高分辨率不显示画面问题 在之前使用WebRTC结合ossrs进行推流时候,ossrs的播放端无法看到高分辨率画面问题。根据这个问题,找到了解决方案。 一、WebRTC是什么 WebRTC是什么呢? WebRTC (Web Real-Time Communicatio…

微信小程序如何配置并使用less?

1,检查微信开发者工具(工具版本1.03)————这步很重要不然后面按步骤实行后会发现急死你也还是不管用,我之前死在过这一步,所以大家不要再次踩坑了 ~ ~ 。。。 2,在VScode中下载Less插件 3,…

Unity-Shader-高亮Highlight

常用Shader-高亮,可动态调整高亮颜色、高亮强度范围/等级、高亮闪烁速度、高亮状态 Shader "CustomShader/Highlight" {Properties{_Color("Color", Color) (0.9044118,0.6640914,0.03325041,0)_Albedo("Albedo", 2D) "white…

服务器时钟同步

服务器时钟同步 文章目录 服务器时钟同步背景windows时钟同步Linux机器上的时钟同步Centos时钟同步Ubuntu系统时钟同步 查看是否同步的命令 背景 运维,XXX服务器慢了2秒,导致XXX业务没有正常执行,请立即排查为啥会有时钟不同步的问题。 首先…

外网通过ipv6访问家里设备

目录 1.需要整体理解如何在外网连接家里设备。 2.路由器打通ipv6。 3.移动光猫配置ipv6。 4.test-ipv6.com测试成功,但是ping不通 还是ping不通,提出如下可能 5.动态域名解析(ddns-go) a.dns服务商权限设置 b.IPv6设置 c…

全排列——力扣46

文章目录 题目描述解法:回溯题目描述 解法:回溯 //version 1 vector<vector<int>> permute(<

nodejs+vue+elementui招聘求职网站系统的设计与实现-173lo

&#xff08;1&#xff09;管理员的功能是最高的&#xff0c;可以对系统所在功能进行查看&#xff0c;修改和删除&#xff0c;包括企业和用户功能。管理员用例如下&#xff1a; 图3-1管理员用例图 &#xff08;2&#xff09;企业关键功能包含个人中心、岗位类型管理、招聘信息…