提速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.mzph.cn/news/32903.shtml

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

相关文章

考虑微网新能源经济消纳的共享储能优化配置(Matlab代码实现

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

VSCode Remote-SSH (Windows)

1. VSCode 安装 VSCode 2. 安装扩展 Remote SSH Getting started Follow the step-by-step tutorial or if you have a simple SSH host setup, connect to it as follows: Press F1 and run the Remote-SSH: Open SSH Host… command.Enter your user and host/IP in the …

Sui网络的稳定性和高性能

Sui的最初的协议开发者设计了可扩展的网络,通过水平扩展的方式来保持可负担得起的gas费用。其他区块链与之相比,则使用稀缺性和交易成本来控制网络活动。 Sui主网上线前90天的数据指标证明了这一设计概念,在保持100%正常运行的同…

实现Jenkins自动发包配置

参考抖音:Java不良人 其中的视频演示代码 不推荐把jenkins端口一直开放,推荐使用时候放开(版本不太新,避免漏洞攻击) [rootVM-4-12-centos soft]# docker-compose -v Docker Compose version v2.19.1docker-compose.…

提升效率!云原生生态从业人员不可或缺的工具集合!

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

​ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639)​

ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639) 二、静态缓解(Static mitigation) 三、动态缓解(Dynamic mitigation) 一、ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639) Title TF-A披露基于cache前瞻…

92. 反转链表 II

92. 反转链表 II 题目-中等难度示例1. 获取头 反转中间 获取尾 -> 拼接2. 链表转换列表 -> 计算 -> 转换回链表 题目-中等难度 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点…

请求转发和请求重定向

目录 1. 定义层面 2. 请求方层面 3. 数据共享层面 4. 最终 url 层面 5. 代码实现层面 请求转发 请求重定向 在Java中&#xff0c;跳转网页的方式有两种&#xff0c;一种是请求转发&#xff0c;另一种是请求重定向&#xff0c;而实际上&#xff0c;这两种方式是有着明显…

JavaScript数据结构【进阶】

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录 使用 splice() 添加元素使用 slice() 复制数组元素使用展开运算符复制数组使用展开运算符合并数组使用 indexOf() 检查元素是否存在使用 for 循环遍历数组中的全部元素创建复杂的多维数组将键值对添加到对象…

APP外包开发的H5开发框架

跨平台移动应用开发框架允许开发者使用一套代码在多个操作系统上构建应用程序&#xff0c;从而节省时间和资源。以下是一些常见的跨平台移动应用开发框架以及它们的特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0…

从源码层面深度剖析Spring循环依赖 | 京东云技术团队

以下举例皆针对单例模式讨论 图解参考 https://www.processon.com/view/link/60e3b0ae0e3e74200e2478ce 1、Spring 如何创建Bean&#xff1f; 对于单例Bean来说&#xff0c;在Spring容器整个生命周期内&#xff0c;有且只有一个对象。 Spring 在创建 Bean 过程中&#xff0…

Vue在页面输出JSON对象,测试接口可复制使用

效果图&#xff1a; 数据处理前&#xff1a; 数据处理后&#xff1a; 代码实现&#xff1a; HTML: <el-table height"600" :data"tableData" border style"width: 100%" tooltip-effect"dark" size"mini"><el-…

前后端分离------后端创建笔记(上)

本文章转载于【SpringBootVue】全网最简单但实用的前后端分离项目实战笔记 - 前端_大菜007的博客-CSDN博客 仅用于学习和讨论&#xff0c;如有侵权请联系 源码&#xff1a;https://gitee.com/green_vegetables/x-admin-project.git 素材&#xff1a;https://pan.baidu.com/s/…

如何使用 ESP-01S 模块

如何使用 ESP-01S 模块 原始PDF文档 参考&#xff1a; 将 ESP-01 用作 WiFi shield的更好方法 (e-tinkers.com) How do I use ESP8266 ESP-01S WiFi Module with ESP-01S Adapter - Using Arduino / Programming Questions - Arduino Forum ESP-01S WiFi 模块 – 配置布线 -…

服务管理和计划任务

文章目录 服务管理计划任务 服务管理 systemctl 命令字 服务名 //配置服务与systemctl有关的命令字&#xff1a; 计划任务 一次性计划 at 时间 at now 5 min //当前时间五分钟后执行 at -l //列出计划任务 atrm 任务号 //删除计划任务执行完命令后Ctrld生效 周期性计…

Oracle数据迁移

问题描述&#xff1a; oracle数据库的所有表结构、数据、索引等需要需从测试库迁移到正式库。 解决步骤&#xff1a; oracle数据库迁移&#xff0c;主要通过expdp从测试库所在的源服务器将指定的数据表或数据源导出为一个或多个数据文件&#xff08;.dmp文件&#xff09;&…

添加SQLCipher 到项目中

文章目录 一、克隆下载SQLCipher二、手动导入1. 生成sqlite3.c2. 在项目中添加命令3. 添加 Security.framework 三、CocoaPods导入 SQLCipher官方地址 一、克隆下载SQLCipher $ cd ~/Documents/code $ git clone https://github.com/sqlcipher/sqlcipher.git二、手动导入 1.…

电商系统架构设计系列(八):订单数据越来越多,数据库越来越慢该怎么办?

上篇文章中&#xff0c;我给你留了一个思考题&#xff1a;订单数据越来越多&#xff0c;数据库越来越慢该怎么办&#xff1f; 今天这篇文章&#xff0c;我们来聊一下如何应对数据的持续增长&#xff0c;特别是像订单数据这种会随着时间一直累积的数据。 引言 为什么数据量越大…

【idea】点击idea启动没反应

RT 点击idea启动的时候没反应&#xff0c;接着百度报错&#xff0c;基本跟他们的也不一样。 首先我是做版本升级。其次&#xff0c;我之前是破解的。如果你也是跟我一样的话&#xff0c;那问题可能就处在破解上了 解决方式 首先&#xff0c;是跟大部分解决思路一样。先找到项…

分清性能测试,负载测试,压力测试这三个的区别

做测试一年多来&#xff0c;虽然平时的工作都能很好的完成&#xff0c;但最近突然发现自己在关于测试的整体知识体系上面的了解很是欠缺&#xff0c;所以&#xff0c;在工作之余也做了一些测试方面的知识的补充。不足之处&#xff0c;还请大家多多交流&#xff0c;互相学习。 …