内存减少 3%-7%!谷歌提出用于编译器优化的机器学习框架 MLGO


内存减少 3%-7%!谷歌提出用于编译器优化的机器学习框架 MLGO

MLGO使用强化学习来训练神经网络进行决策,这是一种用机器学习策略代替复杂策略的启发式方法。作为一个通用的工业框架,它将用于更多的环境,而不仅仅是内联和寄存器分配。

作者|钱,米尔恰·特罗芬

编译|刘秉义

编辑|陈

随着现代计算机的诞生,出现了如何编译更快更小的代码的问题。

编译是成本效益比最高的优化方法,更好的代码优化可以显著降低大型数据中心应用的运营成本。编译代码的大小对于部署在安全引导分区上的移动和嵌入式系统或软件至关重要,因为编译的二进制文件必须满足严格的代码大小预算。随着该领域的进展,越来越多复杂的启发式方法严重挤压了有限的系统空,阻碍了系统的维护和进一步改进。

最近的研究表明,通过用机器学习策略取代复杂的启发式方法,机器学习可以在编译器优化中释放更多的机会。然而,在通用和行业级编译器中采用机器学习策略仍然是一个挑战。

为解决这一问题,谷歌两位高级工程师钱和米尔恰·特罗芬提出了“机器学习指导下的编译器优化框架MLGO”,这是第一个将机器学习技术系统集成到LLVM(构建任务关键型高性能软件时无处不在的开源工业编译器基础设施)中的工业通用框架。

地址:https://arxiv.org/pdf/2101.04808.pdf

MLGO使用强化学习来训练神经网络进行决策,而不是LLVM中的启发式算法。根据作者的描述,LLVM上有两种MLGO优化:

1)通过内联减少代码量;

2)通过寄存器分配提高代码性能。

这两种优化都可以在LLVM资源库中获得,并且已经在生产中部署。

1

MLGO是如何工作的?

内联通过做出可以删除冗余代码的决定来帮助减少代码大小。在下面的示例中,调用方函数foo()调用被调用方函数bar(),后者本身调用baz()。内联这两个调用站点将返回一个简单的foo()函数,这将减少代码大小。

注意:内联通过删除冗余代码来减小代码大小。

在实际代码中,有成千上万个函数相互调用,从而形成一个调用图。在内联阶段,编译器遍历所有调用方-被调用方对的调用图,并决定是否内联调用方-被调用方对。这是一个持续的决策过程,因为之前的行内决策会改变调用图,从而影响后续的决策和最终的结果。在上面的例子中,调用图foo () → bar () → baz()需要在两边做出“是”的决定,以减少代码量。

在MLGO之前,内联/非内联的决策是通过启发式方法做出的,随着时间的推移,这种方法变得越来越难以改进。MLGO用机器学习模型代替了启发式方法。在遍历调用图的过程中,编译器通过在图中输入相关特征(即输入)来寻求神经网络关于是否内联特定调用者-被调用者对的建议,并按顺序执行决策,直到遍历整个调用图。

注意:内联大小策略的大小按百分比减少,X轴代表不同的软件,Y轴代表减少的百分比。“Training”是训练模型的软件,“InfraX”是不同的内部软件包。

MLGO的内联调整大小培训已经部署在Fuchsia上,这是一个通用的开源操作系统,旨在支持不同的硬件和软件生态系统,其中二进制大小是关键。这里,MLGO显示C++翻译单元的大小减少了6.3%。

2

寄存器分配

作为一个通用框架,我们使用MLGO来改进寄存器分配通道,从而提高LLVM中的代码性能。寄存器分配解决了将物理寄存器分配给活动范围(即变量)的问题。

随着代码的执行,不同的有效范围在不同的时间完成,释放的寄存器用于后续处理阶段。在下面的示例中,每个“加法”和“乘法”指令都要求所有操作数和结果都在物理寄存器中。实时范围x分配给绿色寄存器,并在蓝色或黄色寄存器的实时范围之前完成。X完成后,绿色寄存器变为可用,并分配给实时范围t。

在代码执行的过程中,不同的范围在不同的时间完成,释放的寄存器用于后续的处理阶段。在下面的示例中,每个“加法”和“乘法”指令都要求所有操作数和结果都在物理寄存器中。活动范围x分配给绿色寄存器,并在蓝色或黄色寄存器的实时范围之前完成。X完成后,绿色寄存器变为可用,并分配给实时范围t。

转载请注明原文地址:https://juke.outofmemory.cn/read/1747845.html

最新回复(0)