QEMU SIMD Code Generation
文章目录
介绍了目前QEMU通过TCG对SIMD指令翻译的方式,以及需要优化的地方
主要参考两篇论文
- Improving SIMD Code Generation in QEMU(DATE 2015)
- Effective and retargetable SIMD translation in a dynamic binary translator(Wiley Software: Practice and Experience 2018)
这两篇论文出自同一团队:Institute of Information Science Academia Sinica, Taiwan Province and MOST in Taiwan Province
如有侵权,立即删除
1. SIMD指令发展
-
现代处理器均支持SIMD指令来提升性能,比如x86架构的MMX,MME和AVX指令集扩展,ARM的NEON指令集扩展
-
**应用程序和编译器对于ARMv7的NEON指令集扩展支持性并不是很好。**比较SPEC2006 fp测试集(使用交叉编译器 arm-linux-gnueabihf-gcc-4.8 编译),很多测试集被编译后几乎不包含NEON指令集,即使是x86的SSE指令集扩展,SPEC2006的SSE指令包含率也不高
- 如图,对于ARM架构,GemsFDTD、zeusmp_sfp、GemsFDTD_sfp和
-
**SIMD指令集架构差异很大。**即使是统一架构下,如ARM,不同版本的SIMD指令集的寄存器数量,是否支持双精度浮点运算都不相同;不同架构下的SIMD指令集扩展差异更大,如下表
2. Challenges in SIMD generation
2.1 SIMD架构自身问题
-
编译器对SIMD指令支持不完善
- 主要体现在ARMv7的NEON指令集扩展,此问题已经在ARMv8的NEON指令集扩展得到改善
-
硬件厂商不断提高SIMD能力,扩展SIMD指令集,使得架构差异很大。包括两类:
- 相同架构不同版本之间
- 不同指令集架构之间
这是DBT不关注SIMD指令翻译的主要原因,版本迭代太频繁
2.2 现代DBT翻译SIMD的问题
以QEMU TCG为例,从两个维度来分析DBT翻译SIMD所面临的问题:
2.2.1 翻译方式
QEMU主要以两种方式翻译指令:IR和Helper Function
- 一般使用IR来翻译简单的指令,比如访存指令、跳转指令以及Int运算指令等
- 优点:翻译速度快
- 缺点:如果IR set太过复杂会影响整体翻译效率,携带信息不能太大
- 使用Helper Function来翻译复杂指令,如浮点指令和SIMD指令
- 优点:可扩展性,稳定性高。例如一些硬件结构的缺失,造成两个体系结构指令天然无法翻译执行,使用Helper Function可以解决
- 缺点:在Call Helper Function之前,QEMU需要将当前CPUState存入Memory中,带来巨大性能开销
2.2.2 翻译结果
QEMU将SIMD指令翻译成线性的标量指令,如一个4组int加法运算指令,QEMU调用4次Helper Function将其翻译成4个host int加法指令,然后由Host cpu执行4次。可见,带来的缺点:
- 多次Helper Function调用,带来巨大性能开销
- 将SIMD指令翻译成多个标量指令,并没有充分利用到Host CPU的SIMD处理能力
3. 优化现代DBT翻译SIMD指令方式
介绍上述两篇论文对SIMD指令翻译的优化方式,第二篇论文是对第一篇论文的延续
3.1 Improving SIMD Code Generation in QEMU
目前支持:
- Guest: ARMv7和IA32
- Host: x86
这篇论文作者使用两种方式来改进QEMU翻译SIMD指令:Helper Function和Vector IR。由于Helper Function带来的性能开销太大,作者也不再继续讨论,所以我们直接讨论第二种方法
-
Vector IR方式
-
从字面意思上来看,似乎作者扩展了QEMU的IR set,来专门翻译SIMD指令。虽然这是作者的初衷,但并没有真正扩展IR set
-
TCG IR有两个buffers来优化TCG翻译,一个是存储IR的opcode,一个是存储IR的参数,也就是寄存器号
在2015年,QEMU TCG并没有采用Guest 寄存器与Host 寄存器映射的方式,而是通过将Guest 寄存器映射到Guest CPUState然后存储在Host Memory里。显然,前者的性能更好。
-
作者修改了Vector IR的第二个参数Buffer的存储内容,改为存储Guest CPUState和Guest SIMD registers的offset,因此不再需要从register number -> register offset这一步计算,提高了指令翻译性能
-
通过Buffer改进,不仅对QEMU翻译SIMD指令带来性能提升,同时也提高了对浮点指令的翻译性能,结果如下
从上图看出,有的benchmark加速比相当高,有的几乎没有性能提升,这主要与benchmark的SIMD指令含量和编译器编译出的SIMD指令含量有关系
此外,一个SIMD指令一般最多同时运行4个运算,为什么加速比会超过4呢。这是因为上述方式改进了浮点指令的翻译性能。作者因此关闭了QEMU对浮点指令翻译在此方式上的收益,又测试了一次性能,发现加速比在2.0x-3.0x之间。
- 不足之处:
- 仍然是将SIMD指令翻译成一系列多个标量指令,无法利用Host CPU的SIMD处理能力
- 没有解决SIMD指令更新迭代的问题,例如x86的SSE(128 bit)到AVX(256 bit)转换并没有实现
3.2 Efficient and retargetable SIMD translation in a dynamicbinary translator
目前支持:
- Guest: ARMv7、ARMv8和IA32
- Host: x86
结合Helper Function和IR的好处,采用混合的方式
- 对于较通用的SIMD指令集,采用扩展IR指令集方式
- 对于复杂的SIMD指令集,采用Helper Function的方式。为了减少Helper Function带来的性能开销,新的Helper Function将采用内联函数的方式
虽然从实验结果来看,此文对SIMD指令翻译性能提升显著,但是作者是在自己改进的一款基于QEMU的模拟器(HQEMU)来实现本文工作的,因此通用性不高
4. 总结
除了上述两篇论文的优化SIMD指令翻译方向外,业界还主要围绕以下两种方向对SIMD指令翻译进行优化:
- 聚焦于平台。如2.1所述,因为SIMD指令集的通用性很差,很多工作都是点对点开展,比如从x86 SSE指令集(short)到x86 AVX指令集(long)映射
- 聚焦于寄存器映射。如果Guest寄存器和Host寄存器之间没有映射的话,比如call helper function之前,需要将Guest State保存到memory,并且需要同步,带来性能开销。