SIMD 代表 单指令多数据,是指对多个数据元素同时执行操作。例如,SIMD 加法指令可以并行添加多个值。SIMD 是一个非常流行的技术,用于加速图形、音频、编解码器、物理模拟、密码学和许多其他领域的计算。
除了提供性能之外,SIMD 还可以降低功耗,因为它使用更少的指令来完成相同的工作量。
SIMD.js
SIMD.js 是 Intel、Google 和 Mozilla 正在为 JavaScript 开发的新 API,它引入了几种用于执行 SIMD 计算的新类型和函数。例如,Float32x4 类型表示 4 个打包在一起的 float32 值。API 包含用于对这些值一起操作的函数,包括所有基本算术运算,以及用于重新排列、加载和存储这些值的运算。其目的是让浏览器直接实现此 API,并提供利用底层硬件中 SIMD 指令的优化实现。
目前重点是支持使用 SSE 的 x86 平台和使用 NEON 的 ARM 平台。我们也对支持其他平台的可能性感兴趣,可能包括 MIPS、Power 等。
SIMD.js 最初源自 Dart SIMD 规范,并且它正在快速发展,成为一个更通用的 API,并涵盖更多用例,例如需要更窄整数类型的用例,包括 Int8x16 和 Int16x8,以及饱和运算。
SIMD.js 是一个相当低级的 API,预计将在此之上编写库以公开更高级的功能,例如矩阵运算、超越函数等等。
除了在普通 JS 中可用之外,还有工作正在进行,将 SIMD.js 添加到 asm.js 中,以便它可以从 asm.js 程序中使用,例如由 Emscripten 生成的程序。在 Emscripten 中,SIMD 可以通过内置的自动矢量化、通用 SIMD 扩展 或 新的(仍在增长)Emscripten 特定 API 来实现。Emscripten 还将实现流行的标头(例如 <xmmintrin.h>)的子集,并使用 SIMD.js API 的包装器,作为在某些情况下简化移植 SIMD 代码的额外方法。
当今的 SIMD.js
SIMD.js API 本身正在积极开发中。该 ecmascript_simd github 仓库 目前用作临时规范,并提供了一个 polyfill 实现,以提供该功能,尽管当然没有提供 SIMD API 在现有浏览器上的加速性能。它还包括一些 基准测试,这些基准测试也用作基本 SIMD.js 用法的示例。
要查看 SIMD.js 的实际运行情况,请查看 与 IDF2014 关于 SIMD.js 的演讲配套的演示页面。
该 API 已提交给 TC-39,TC-39 已将其批准为第 1 阶段(提案)。工作正在进行中,为后续阶段做准备,这些阶段将涉及提出更接近最终 API 的内容。
Firefox Nightly 中的 SIMD.js 实现正在积极开发中。Internet Explorer 将 SIMD.js 列为 “正在考虑中”。还有一个 Chromium 分支中的原型实现。
短 SIMD 和长 SIMD
SIMD 的用途之一是加速对大型数据数组的处理。如果您有一个包含 N 个元素的数组,并且您希望对数组中的每个元素执行大致相同的事情,则可以将 N 除以平台提供的任何 SIMD 大小,并运行该数量的 SIMD 子例程实例。由于 N 非常大,我将这类问题称为长 SIMD 问题。
SIMD 的另一个用途是加速对数据集群的处理。RGB 或 RGBA 像素、XYZW 坐标或 4×4 矩阵都是此类集群的示例,我将用这些类型的类型表示的问题称为短 SIMD 问题。
SIMD 是一个广泛的领域,短 SIMD 和长 SIMD 之间的界限并不总是清晰的,但在高层面上,这两种风格截然不同。即使用来描述它们的术语也出现了分裂:在短 SIMD 世界中,将标量值复制到向量值中每个元素的操作称为“splat”,而在长向量世界中,类似的操作称为“广播”。
SIMD.js 主要是“短”风格 API,非常适合短 SIMD 问题。SIMD.js 也可用于长 SIMD 问题,并且它仍然会比普通标量代码提供显著的速度提升。但是,它的固定长度类型不会实现当今一些 CPU 的最大性能,因此仍然有空间开发另一个解决方案来利用可用的性能。
可移植性和性能
SIMD.js 的许多部分都存在着一种自然矛盾,即希望拥有一个跨所有重要平台一致运行的 API,以及希望让 API 在每个平台上尽可能快地运行。
幸运的是,有一组核心操作在各种平台上非常一致。这些操作包括大多数基本算术运算,并构成 SIMD.js 的核心。在这一组中,几乎不会产生任何开销,因为许多相应的 SIMD API 指令直接映射到单个指令。
但是,还有许多操作在一个平台上运行良好,而在其他平台上运行不佳。这些可能会导致意外的性能下降。SIMD.js API 的当前方法是专注于可以用尽可能少的性能下降完成的事情。它还专注于提供可移植的行为。总之,其目标是确保在一个平台上运行良好的程序也很可能在另一个平台上运行良好,并且运行良好。
在 SIMD.js 的未来迭代中,我们预计将扩展范围,并包括更多功能以及查询底层平台功能的机制。类似于 WebGL,这将允许程序确定哪些功能可用,以便它们可以决定是回退到更保守的代码,还是禁用可选功能。
总体愿景
SIMD.js 将加速当今各种需要大量计算的应用程序,包括游戏、视频和音频处理、科学模拟等等,并且这些应用程序可以在 Web 上运行。应用程序可以直接使用 SIMD.js API,库可以使用 SIMD.js 公开应用程序可以使用的高级接口,而 Emscripten 将用流行的 SIMD 习语编译 C++,生成优化的 SIMD.js 代码。
展望未来,SIMD.js 将继续发展,提供更广泛的功能。我们希望最终在 SIMD.js 旁边提供一个长 SIMD 风格的 API,这两个 API 可以像 OpenCL 组合显式向量类型和底层编程模型的隐式长向量并行性一样协同工作。
关于 Dan Gohman
我在 Cray、Apple 和 Google 工作过,在各种环境中开发过几种不同的编译器。我目前是 Mozilla 研究团队的一员,主要从事 asm.js、SIMD.js 和 Emscripten 的工作。
关于 Robert Nyman [荣誉编辑]
技术布道师和 Mozilla Hacks 编辑。发表关于 HTML5、JavaScript 和开放 Web 的演讲和博客。Robert 坚信 HTML5 和开放 Web,并且自 1999 年以来一直在从事 Web 前端开发工作 - 在瑞典和纽约市。他还会定期在 http://robertnyman.com 上发表博客,并喜欢旅行和结识新朋友。
10 条评论