作者 | 江贺
整理 | Hana
作者简介:
江贺,大连理工大学软件学院教授,博士生导师,研究领域:智能软件工程(软件大数据处理、编译系统测试、工业软件测试)
个人主页:http://faculty.dlut.edu.cn/jianghe/zh_CN/index.htm
本次技术分享来自 SIG-编程语言测试技术沙龙,本文内容为提取讲演视频后的文章,视频也已经发布在 B 站,欢迎大家点开学习。
小程序,
哔哩哔哩,,编译器优化故障的测试与定位小程序
# Introduction #
今天想分享的主题是 编译器故障的检测和定位。
当前编译器的发展现状如下图示,大家可以看出编译器的发展趋势正在由通用型转向领域特定型。
编译环境发展现状
但是我们分析发现,这些编译器实际上依旧占据着主流的应用市场:
主流编译器流行度 —— 以 C/C++ 编译器为例
国内也涌现出很多的编译器:
国产编译器
神威睿智编译器 基于申威指令系统开发 [1] 了基于 GCC 和 Open64 的产品编译器,以及针对国产主机的二进制翻译系统(PowerPC/X86);
龙芯中科 也有基于自有架构后端定制了优化的编译器,包括基于 GCC 和 Open64 的产品编译器,以及 DigitalBridge 进程级二进制翻译系统(X86);
寒武纪 [2] 针对 AI 构建了自己的编译工具链,包括 CNCC(寒武纪 BANG C 语言编译器,基于 Clang 和 LLVM 开发)和 CNAS(寒武纪 MLISA 语言编译器);
华为也推出了自研的方舟编译器 [3]。
编译器的质量会大大影响其使用和流行程度,因此在做编译器的过程中,编译器的质量是一个非常重要的要求。
确保编译器的质量有两种方式:第一种方式就是做 可信验证,这种方式的好处在于它理论上是可以完全保证编译器质量的(如 CompCert [4]),但是无法规模化应用;更常用的办法是 对编译器做测试,虽然无法保证完备性,但它可以大规模化。
编译器可信验证 vs. 编译器测试
# 编译器测试
编译器测试一般会有三个阶段,
-
测试用例生成 如何生成测试用例来触发编译器故障
-
Test Oracle 问题 即测试准则问题 [5]。当输入测试用例后,编译器产生的输出与我们的预期输出是否一样
-
测试用例约减 当我们发现了一个编译器的故障后,广州房评通常来讲测试用例可能会很长,但是要提交给社区时,必须做一些相关的约减,将测试用例减到方便开发者阅读和定位的范围内(比如 20 行左右)。
编译器测试的一般流程
## 编译器测试的主要方法
这里简单介绍一下三种主流编译器测试技术:
Random Differential Testing (RDT) 即随机差异测试。简单说,就是用同个编程语言的不同的编译器(比如 GCC 和 LLVM)来进行比较,若编译器的行为不一致,则表示至少其中一个编译器是存在故障的。
Different Optimization Levels (DOL) 即优化级别测试。是 RDT 的一个变种,具体方法是对比同一个编译器的不同优化等级,若行为不一致,则表示至少有一种编译器优化存在故障。
Equivalent Modulo Inputs (EMI) [6] 即等价取模测试,由 UC Davis 的苏振东教授团队提出。EMI 的方法与 RDT 等不同,是对程序进行变换,然后观察被测编译器,是否会跑出不同的结果。
编译器测试的主要方法
# 编译器架构
编译器可以分为前端、中间层及后端。业界对编译器中间这一层的分析和测试比较多,针对前端和后端的分析测试在学术界相对不是特别多。工业界也是如此,由于后端架构的多样,中间代码到指令集的翻译需要适配不同的架构,这个过程需要很严肃的测试是否有故障;另外,像 LLVM 编译器的中间优化大概有 150 多个,丰告网GCC 大概有 250 个,中间优化对传统编译器来说是相当重要的一部分,同时也是出现故障可能性很大的一部分。
典型的编译器架构
正确地使用编译器优化对程序的性能(如执行速度、代码大小、功耗等)会有显著影响。
编译器优化对工业界的应用十分有意义,当你选择比较好的优化,包括优化的序列时,对程序最后的输出会有很大影响。比如通过编译器优化,甚至可以改进给定程序编译后的大小,程序执行速度,功耗等。对于嵌入式行业来说,代码的大小分分钟会影响到增减一个芯片的问题,所以优化带来的这些收益对于工业界是十分关键的。
编译优化选择(Phase Ordering Problem)
有关编译优化的选择,业界当前有两类主要的方法(如上图示):
-
第一种是 机器学习方法,即找出一些示例程序,结合不同的编译器优化序列,从而构建出训练样本,输入给算法进行学习;
-
另外一种是 演化计算方法,不需要有训练集,给定一个程序,将对其进行的优化序列编码为一个解,然后对优化序列进行交叉编译来迭代。
讲完前面一些背景之后