下载本文的PDF版本 PDF

将控制权交还给程序员:虚拟机的SIMD内在函数

在解释型语言中公开SIMD单元可以简化程序并释放大量未开发的处理器能力。

Jonathan Parri、Daniel Shapiro、Miodrag Bolic和Voicu Groza


服务器和工作站硬件架构持续改进,但解释型语言(最重要的是Java)未能跟上现代处理器的正确利用步伐。SIMD(单指令多数据)单元几乎在当前所有桌面和服务器处理器中都可用,但尤其在解释型语言中却被严重低估。如果多核处理器继续保持当前的增长模式,解释型语言的性能将开始落后,因为当前的本地编译器和语言提供了更好的自动化SIMD优化和直接SIMD映射支持。由于商用x86多核处理器中的每个核心都包含一个专用的SIMD单元,因此只要解释型语言环境中可用的SIMD单元仍然未被充分利用,性能差距就会呈指数级增长。

面向所有人的SIMD

软件设计和计算机架构已经见证了并行数据处理的演变,但它尚未在解释型语言领域得到充分利用。充分利用可用的系统架构和功能(尤其是SIMD单元)对开发人员来说可能非常具有挑战性。这些功能通常被忽视,转而采用成本高昂但可扩展的措施来提高性能,主要是增加处理能力。虚拟机和解释型语言一直在抽象化并远离底层系统架构。

SIMD指令被添加到现代处理器中以提高指令级并行性。在SIMD指令中,可以使用一个通用操作来操作多个且唯一的数据元素。SIMD单元通常包括一个额外的寄存器组,具有较大的寄存器宽度。这些单独的寄存器可以细分为保存不同数据类型的多个数据元素。

开发人员已经开始注意到CPU中的SIMD指令功能未得到充分利用。4 在解释型语言中,软件到硬件的映射部分是即时且实时发生的,这为彻底的指令级并行性分析和优化留下了很少的时间。字节码编译可以用于识别并行机会,但在许多实际场景中已被证明是无效的。详尽的自动化SIMD识别和向量化在JIT(即时)编译器中发生时计算量过大。

现在常见的是在本地语言中使用基于SIMD的指令集扩展(例如,AltiVec、SSE、VIS)、通用图形卡计算(例如,Nvidia CUDA、ATI STREAM)和内存模块来执行数组上的向量运算。AltiVec、SSE和VIS是众所周知的SIMD指令集。AltiVec常见于PowerPC系统,SSE常见于x86-64,VIS常见于SPARC。

我们建议将通用的用户已知并行操作调用直接映射到虚拟机内部的本地SIMD调用。通过允许在解释型语言中进行通用SIMD向量访问,用户可以在并行性方面获得更多控制权,同时仍然允许JIT编译器进行自动化SIMD向量化。未来的虚拟机开发和语言规范必须进行调整,以更好地利用SIMD单元。对SIMD的语言支持不会影响对不包含SIMD操作的处理器的支持。相反,当未检测到SIMD硬件时,虚拟机必须将通用调用转换为顺序指令:即现状。

资源利用率是云计算范例的关键原则,现在正吸引着许多公司。最大限度地提高云资源的利用潜力对于降低成本和提高性能至关重要。由于其普及性和互操作性,解释型语言(主要是Java)经常被选择用于云计算。云环境中的解释型语言不会向程序员公开处理器架构功能,因此,生成的代码很少针对目标平台处理器资源进行优化。更有效地利用现有数据中心资源肯定会降低成本。

Java、Flash、PHP和JavaScript等解释型语言都可能从这种方法中受益。关于在解释型语言中使用SIMD内在函数,有很多潜在的赞成和反对意见,但很明显,需要进行变革。

现有解决方案

随着现代处理器上的核心数量不断增长,可用的SIMD单元数量也在增长。大多数本地编译器都允许以内在函数的形式显式声明SIMD指令,而另一些编译器甚至更进一步,通过向量编译指示扩展编译器前端。5 这缩小了应用程序与底层架构之间的差距。一项研究表明,可以创建一个通用的宏集来调用许多不同的SIMD单元,包括MMX、SSE、AltiVec和TriMedia。13 这组名为MMM的宏为SIMD单元编程提供了抽象,使程序在硬件平台之间更具可移植性。尽管这种初始方法确实提供了代码可移植性,但它并未解决解释型语言的问题。编译器级别也提供了一种类似的方法。10 虽然某些编译器可以使用后期绑定在编译时选择性地专门化代码3,但更简单的方法是让用户在代码中显式表达并行性,从而在运行时解决并行性问题。

解释型语言不会以透明的方式向程序员公开向量功能。这正成为一个重要问题,因为高性能计算越来越多地使用Java而不是Fortran等语言来执行。2 AMD的Aparapi1 是解决解释型语言性能差距的一种解决方案,它提供线程级并行性和对显卡加速的访问,但不支持SIMD。英特尔还在其最新的英特尔数学核心库中以库包的形式公开了一些本地SIMD支持。6

有一种观点认为,与其使用标准化的API或虚拟机扩展,不如编写自己的自定义本地接口来访问SIMD。当今最简单的解决方案之一是使用运行时配置文件查找Java代码中的热点,并将JNI(Java本地接口)调用添加到有问题的代码中,从而有效地将低效操作卸载到更快的本地代码。不幸的是,这种方法仅在程序员已知处理器架构时才有效,并且在升级到新架构时会增加兼容性问题。

变革的理由

在解释型语言中支持包含预映射向量内在函数的理由是更快的应用程序运行时、更低的成本、更小的代码大小、更少的编码错误以及更透明的编程体验。

硬件不断变化,但解释型语言并未跟上这些变化的步伐,通常仅依赖于默认数据路径。将SIMD指令集成到虚拟机及其匹配的语言规范中,可以更大程度地利用可用资源。直接向量操作映射将提高SIMD单元的利用率,因此代码将运行得更快。如今和未来的多处理器将为每个处理器包含一个SIMD硬件核心,从而放大顺序代码和并行代码之间的差距。例如,在英特尔的Core i7-920中,这是一款具有四个物理核心的x86-64处理器,每个核心都包含一个SSE 4.2指令集扩展。虚拟机可以同时利用四个SSE单元,在吞吐量方面优于四个单处理器核心。

随着亚马逊和谷歌等云计算提供商开始站稳脚跟,资源利用率已成为关键问题。这些组织事先不知道潜在的客户端工作负载;因此,编程语言提高资源利用率将带来巨大的好处。随着在这些集群上运行的解释型语言的改进,更轻松地扩展云的需求减少了,从而节省了相应的成本。

随着用户获得对向量化数据类型的更多控制权,利用SIMD操作的编码体验变得更加透明。代码大小(以代码行数衡量)将减少,因为现在可以在虚拟机内部而不是每个程序内部执行向量上的SIMD操作。这与堆栈、队列、数组、哈希映射、字符串和其他数据结构减小代码大小的原因相同。这些类正在封装和抽象复杂性。这种封装和抽象也意味着更少的编码错误。当最先进的技术要求用户进行本地接口调用并编写C/C++代码以显式访问SIMD指令时,标准化的API和提议的虚拟机集成避免了复杂的调试,而是公开了SIMD内在函数。

解决SIMD包含方面的担忧

可以通过将本地SIMD映射添加到目标平台的虚拟机来实现平台兼容性。应该始终存在一个默认映射,如果适当的硬件不可用,则在运行时将SIMD操作映射到顺序代码。

来自Oracle的HotSpot JVM(Java虚拟机)等虚拟机已经包含在运行时识别SIMD机会的优化。JIT编译器必须以接近实时的速度运行,因此,无法花费大量时间在运行时查找最佳SIMD映射。用Java编写的简单SIMD操作很容易被JVM拾取,但是更复杂的向量操作序列很容易被忽略。11 许多复杂的应用程序无法很好地转换为优化编译器并行SIMD代码。我们认为,开发人员通常知道哪些操作可以并行执行,并且应该能够以标准化的方式对它们进行编码,从而利用可用的SIMD功能。

例如,考虑一个并行加法指令,该指令显式使用SIMD单元来添加两个已知数据类型的数组

jSIMD_API.add(foreground_pixel_blue,background_pixel_blue,foreground_pixel_blue);

用户知道操作的源和目标是相同类型和长度的数组,并且当可以将SIMD操作序列链接在一起时,这种类型的操作最有利,从而避免了SIMD和主CPU寄存器文件之间的传输。

我们从行业和研究人员那里听到的另一个阻力来源是使用专用显卡进行GPGPU(通用图形处理器计算)的可能性。这项技术的示例包括Nvidia的CUDA和ATI的STREAM。在Flash的上下文中,Adobe最近宣布其ActionScript现在可以使用Nvidia显卡。8 对于那些拥有支持所需功能的显卡的用户来说,这种替代方法是合理的。不幸的是,这意味着用户必须购买外部显卡,这通常很昂贵并且需要额外的功耗。在云计算环境中,这可能会增加大量的显卡以及相关的成本。另请注意,每个事务都需要系统总线访问,而SIMD单元就在处理器芯片上,并且几乎随每个处理器一起提供。未来几代处理器可能会在芯片上包含GPU,但在现有基础设施实现这一点之前,SIMD是一个唾手可得的成果,尚未充分利用以获得每个核心的更多计算量。最重要的是,能够实现这种壮举的GPU不如处理器分布广泛。英特尔凭借其集成显卡产品占据了50%的市场份额。12 随着多核系统变得越来越突出,使用多个SIMD单元的可能性变得更加清晰。

反对在解释型语言中包含SIMD内在函数的论点可以通过标准化的并行虚拟机扩展和规范轻松克服。希望这些想法将在未来的语言演变中变得容易获得。

在Java中使用SIMD

为了响应解释型语言中对SIMD的需求,我们设计了一个名为jSIMD的API,用于使用各种数据类型的向量化数据将Java代码映射到SIMD指令。JNI是Java中提供的一项功能,允许访问本地代码。它在后端用作程序员熟悉的Java API和编译为本地代码的SIMD映射之间的桥梁。以图像处理程序为例,我们观察到比传统Java代码快34%。早期对更简单和纯粹数学结构的测试已产生两到三倍的加速。11

图1显示了API的概述。一旦构建了向量操作事务,用户代码就会告诉API启动所需的操作。API识别可用的操作系统和SIMD单元,以便决定何时在Java中执行API调用,以及何时将调用传递给具有用于并行执行的SIMD映射的动态库。如果可以进行并行执行,则API会向动态库发出JNI调用,动态库对Java内存空间中的数据执行SIMD指令。SIMD本地库可以通过gcc或使用预打包的二进制文件为不同的目标架构重新编译。通用源代码已用于促进简单的交叉编译。

High-level Overview of the jSIMD API

动机示例

考虑一个动机示例,该示例使用jSIMD API来获得比开箱即用的Java解决方案更快的速度。Alpha混合用于在视频处理中创建过渡效果或混合两个单独的图像,它是可以通过使用SIMD指令适度加速的算法示例之一。有许多这样的并行数据处理应用程序很容易使用SIMD范例编写。SIMD任务的示例(本质上是并行的)包括3D图形、实时物理、视频转码、加密和科学应用程序。这些应用程序的选定版本通常由虚拟机中的自定义本地代码支持,而我们的解决方案使程序员能够表达任何算法,而不仅仅是内置于解释器中的算法。

我们使用英特尔的VTune性能分析器7 获得了执行配置文件,该分析器可用于分析各种可执行应用程序。我们使用它来观察JVM单独执行的SSE调用的数量和类型。一个alpha混合程序使用几个标准尺寸的图像(640 x 480 - 1920 x 1080像素)执行;在配备2-GB DDR2 RAM的英特尔酷睿2双核E6600和运行Windows XP Pro SP3的系统上,每个测试执行1,000个样本。使用jSIMD导致平均加速34%,并且如预期的那样进行了大量SSE调用。此外,在使用开箱即用的Java解决方案时,没有执行SIMD指令,而使用jSIMD API时的结果表明,已完成的SIMD指令数达到数百万,并且每帧节省了几毫秒。对于视频转码,这是一个显着的性能提升。已完成的SIMD指令数与像素计数之间的线性关系意味着API在大小规模上都运行良好。

这些观察结果表明,公开SIMD内在函数将通过调用更多SIMD指令来缩短执行时间。当前的jSIMD实现产生的加速低于预期水平,这是基于我们使用的数据类型和处理器在SSE中最多四个并发操作。考虑到无需更改底层系统架构,并且对用户代码的更改相对简单自然,因此加速仍然显着。由于无法保证数组在JVM9 中保持固定(由于垃圾回收器),因此偶尔会发生内存复制,这已通过分析得到证实。

使其成为现实

在jSIMD API的开发过程中出现的一些问题是SIMD代码和常规Java代码之间的依赖关系,以及API的多次实例化。程序执行期间向量寄存器的完整性是另一个令人担忧的领域。我们发现,即使Java确实自行进行SIMD调用,JVM也不会中断对我们API的JNI调用,因此它不会即时替换SSE寄存器的任何内容。

除非减少内存和SIMD单元之间的数据传输,否则SIMD寄存器的使用效率低下。将SIMD操作列表视为事务可以进行进一步分析,权衡性能增益与开销成本。我们方法的一个缺点是,将SSE调用与常规Java代码交错可能会导致寄存器文件抖动。我们当前的解决方案要求程序员在一个连续的块中编写所有SSE代码,以便JVM在执行JNI调用时不需要执行。

当调用API执行一系列SIMD操作时,API使用简单的顺序列表调度算法将操作打包到事务中,然后通过引用将所有指令和数据传递给C程序,该程序执行SIMD指令。与常规Java代码的依赖关系(例如在API执行语句之前进行强制转换)必须在事务之外发生,除非它们是使用API完成的。依赖关系和反依赖关系解析将进一步提高执行时间和利用率。

展望SIMD的未来

解释型语言可以向程序员公开向量功能,结果将是更快、更小、更简单的代码,正如使用Java的这种方法的实际应用所证明的那样。此外,云计算基础设施中更好的SIMD利用率有可能显着降低成本。改进单个事务中的调度算法是未来的方向,这将确实提高性能和吞吐量。另一个明确的下一步是同时利用真实云计算基础设施中的多个核心。

我们的结果可以推广并包含在许多虚拟机中。例如,Flash显然将受益于开发人员对ActionScript计算段的进一步手动SIMD干预。PHP和JavaScript也可以从这种方法中获得好处,以提高Web应用程序的速度。更一般而言,如果您创建一个虚拟机,则应允许显式访问通用SIMD指令。既然您已经为服务器内部的SIMD单元付费,您不妨让程序员使用它。尽管这项工作仍在进行中,但我们相信它将在解释型语言中得到广泛采用。

用户可以轻松识别向量和数组上的并行操作。解释型语言不必强行在架构上不可知且不透明。虚拟机拥抱其底层架构的时候已经到来,以便数据中心和高性能应用程序可以充分利用可用的处理基础设施。可以合理地期望现有的虚拟机指令集包含通用SIMD操作。将一些控制权交还给程序员,特别是对于固有的并行向量操作,是迈向透明编程体验的简单一步。这个论点不应与古老的汇编语言与C语言的问题混淆。通用SIMD映射可以保留解释型语言中已经存在的抽象;用户始终不知道正在发生的确切硬件映射。用户只是被赋予了更多控制权来指定他们认为的并行代码,从而否定了实时算法方法所需的重新发现。

几乎在每个桌面和服务器处理器中都可用的SIMD单元都未得到充分利用,尤其是在使用解释型语言时。将更多控制权交给程序员和编程语法可以实现成功且简单的映射,从而提高性能。虚拟机必须解决当前集成SIMD支持的挑战。

参考文献

1. AMD。Aparapi; http://developer.amd.com/zones/java/aparapi/

2. Amedro, B., Bodnartchouk, V., Caromel, D., Delbé, C., Huet, F., Taboada, G. L. 2008。Java for HPC的现状。法国索菲亚·安提波利斯 Cedex; http://hal.inria.fr/docs/00/31/20/39/PDF/RT-0353.pdf

3. Catanzaro, B., Kamil, S. A., Lee, Y., Asanović, K., Demmel, J., Keutzer, K., Shalf, J., Yelick, K. A., Fox, A. 2010。SEJITS:通过选择性嵌入式JIT专业化获得生产力和性能。加州大学伯克利分校EECS系技术报告UCB/EECS-2010-23; http://www.eecs.berkeley.edu/Pubs/TechRpts/2010/EECS-2010-23.html

4. Cheema, M. O., Hammami, O. 2006。用于可重构架构的特定于应用程序的SIMD合成。微处理器和微系统 30 (6): 398 - 412。

5. Codeplay。VectorC编译器引擎; http://www.codeplay.com

6. 英特尔软件网络。2010。英特尔MKL V10.3中的英特尔AVX优化; http://software.intel.com/en-us/articles/intel-avx-optimization-in-intel-mkl-v103/

7. 英特尔软件网络。2010。英特尔VTune Amplifier XE; http://software.intel.com/en-us/intel-vtune/

8. Nvidia。2009。Adobe和Nvidia宣布Flash Player的GPU加速; http://www.adobe.com/aboutadobe/pressroom/pressreleases/200906/060209AdobeandNvidia.html

9. Oracle。2010。Java 2 SDK 1.2版中引入的JNI增强功能; http://download.oracle.com/javase/1.3/docs/guide/jni/jni-12.html#GetPrimitiveArrayCritical

10. Orc(石油运行时编译器); http://code.entropywave.com/projects/orc/

11. Parri, J., Desmarais, J., Shapiro, D., Bolic, M., Groza, V. 2010。利用Java中的SIMD设计自定义向量操作API。加拿大电气和计算机工程会议(5月)。

12. Ranganathan, L. 2009。英特尔集成显卡上的3D游戏; http://software.intel.com/en-us/articles/3d-gaming-on-intel-integrated-graphics/

13. Rojas, J. C. 2003。用于便携式优化程序的多媒体宏。东北大学博士论文。

喜欢还是讨厌?请告诉我们

[email protected]

Jonathan Parri ([email protected]) 是渥太华大学的博士候选人,也是计算机架构研究小组的高级成员。他目前的研究重点是硬件/软件领域的设计空间探索,目标是嵌入式系统和传统系统。他曾担任过开发人员和技术作家到研究工程师等多种职务。

Daniel Shapiro ([email protected]) 是渥太华大学的博士候选人,也是计算机架构研究小组的高级成员。他的研究兴趣包括自定义处理器设计、指令集扩展、IT安全和生物医学工程。他在具有复杂算法集成的实时系统设计方面拥有丰富的行业经验。

Miodrag Bolic ([email protected]) 是渥太华大学信息技术与工程学院的副教授。他的研究兴趣包括计算机架构、射频识别和生物医学信号处理。他发表了80多篇期刊和会议论文,并编辑了一本书。他是渥太华大学计算机架构研究小组的主任。

Voicu Groza ([email protected]) 于1997年加入渥太华大学,目前在信息技术与工程学院工作。他是200多篇技术论文的作者和合著者。他的研究兴趣包括硬件/软件协同设计、生物医学仪器和测量以及可重构计算。他是渥太华大学计算机架构研究小组的联合主任。

© 2011 1542-7730/11/0200 $10.00

acmqueue

最初发表于Queue vol. 9, no. 2
数字图书馆中评论本文





更多相关文章

Bob Supnik - 模拟器:过去(和未来)的虚拟机
模拟器是“虚拟机”的一种形式,旨在解决一个简单的问题:缺少真实硬件。用于过去系统的模拟器解决了真实硬件的丢失问题,并在真实硬件消失后保留了软件的可用性。用于未来系统的模拟器解决了未来硬件设计的可变性问题,并促进了在真实硬件存在之前进行软件开发。


Poul-Henning Kamp, Robert Watson - 安全地构建共享系统
计算的历史以持续转型为特征,这种转型源于摩尔定律描述的性能大幅提升和价格大幅下降。计算能力已从集中式大型机/服务器迁移到分布式系统和商品桌面。尽管发生了这些变化,系统共享仍然是计算的重要工具。从桌面环境的多任务处理、文件共享和虚拟机到主机托管中心服务器级ISP硬件的大规模共享,在互不信任的各方之间安全地共享硬件需要解决意外和恶意损坏的关键问题。


Poul-Henning Kamp, Robert Watson - 安全地构建共享系统
计算的历史以持续转型为特征,这种转型源于摩尔定律描述的性能大幅提升和价格大幅下降。计算能力已从集中式大型机/服务器迁移到分布式系统和商品桌面。尽管发生了这些变化,系统共享仍然是计算的重要工具。从桌面环境的多任务处理、文件共享和虚拟机到主机托管中心服务器级ISP硬件的大规模共享,在互不信任的各方之间安全地共享硬件需要解决意外和恶意损坏的关键问题。


Mendel Rosenblum - 虚拟机的重生
虚拟机一词最初描述的是20世纪60年代的操作系统概念:一种具有计算机系统硬件(真实机器)外观的软件抽象。四十年后,该术语涵盖了广泛的抽象——例如,与现有真实机器不匹配的Java虚拟机。尽管存在差异,但在所有定义中,虚拟机都是程序员或编译系统的目标。换句话说,软件是为在虚拟机上运行而编写的。





© 保留所有权利。

© . All rights reserved.