发布于 2026-01-06 1 阅读
0

使用 WASM 还是不使用 WASM?WASM 基准测试案例分析 问题 基准测试 被污染的实现?结论

要不要加入WASM?

WASM 基准故事

问题

基准

被污染的实现?

结论

WASM 基准故事

Linkurious,我们构建了 Linkurious Enterprise,这是一个利用图表和图表可视化功能帮助全球企业和政府打击金融犯罪的 Web 平台。

Linkurious Enterprise 的主要特点之一是面向非技术用户的用户友好型图形可视化界面。

2015年,我们对JavaScript图形可视化库的现状感到不满,于是开始开发我们自己的库:Ogma。

Ogma 是我们开发的一款专注于网络可视化的 JavaScript 库,它提供了卓越的渲染和计算性能。您可能之前已经使用过其他工具(例如 D3.js 或 Sigma.js)在 JavaScript 中实现过网络可视化,但对我们来说,实现一些其他库所不具备的特定功能并提升某些性能指标至关重要,因此我们从零开始创建了 Ogma 可视化库。

问题

节点星系

Ogma 旨在与最先进的算法配合使用,以在网络可视化领域提供最佳性能,从一流的 WebGL 渲染引擎,到采用 WebWorkers 来提高库在长时间运行任务上的交互性,再到一流的图布局算法实现。

自首次发布以来,WebAssembly 就承诺提供媲美原生应用的出色性能,而开发者只需将源代码翻译成原生高性能语言,即可在 Web 上获得最佳效果。
经过一段时间以及 WebAssembly 方面更多的宣传之后,我们决定亲自尝试一下,并在正式加入(高性能的)WASM 阵营之前进行一次全面的基准测试。

图布局是此类研究的理想对象:它们对 CPU 要求很高,需要反复计算直到找到收敛的解决方案。WASM
的优势就在于,与 JavaScript 解释器相比,它能够在更低的层级上以更高的内存和 CPU 效率解决这类问题。

我们的调查

我们的研究首先着重于寻找一个能够对典型的图布局算法进行基准测试的候选算法,该算法能够使用类似的结构轻松移植到不同的编程语言中。
最终我们选择了n体算法:该算法通常是许多力导向布局算法的基准,也是布局流程中最耗时的部分。解决流程中的这一特定部分将极大地提升Ogma所实现的整个力导向算法的性能。

基准

正如马克斯·德·马尔齐在2019年夏天在他的博客中所说:

世上有谎言、弥天大谎和基准。

建立公平的基准测试往往是不可能的,因为很难重现现实世界的场景:为复杂的系统创造合适的运行环境总是极其困难的,因为在实验室基准测试中很容易控制外部因素,而在现实生活中,许多因素都会影响最终的“感知”性能。

在本例中,我们的基准测试将专注于一个定义明确的单一任务:n体算法。
这是一个定义清晰且广为人知的算法,被众多知名机构用于语言基准测试。

为了进行公平的基准比较,我们为不同的语言制定了一些规则:

  • 不同实现方式的代码结构应该类似。
  • 不允许多进程、多线程并发。
  • 不允许SIMD指令传输
  • 仅接受编译器的稳定版本。不允许使用 nightly 版本、beta 版本、alpha 版本或 pre-alpha 版本。
  • 请使用每种源语言的最新版本编译器。

规则一旦确定,就可以着手实现算法了。但首先,需要决定基准测试中将使用哪些其他语言:

JS竞争对手

WASM 是一种编译型语言,即使它被声明为“人类可读”的汇编代码,对我们来说,编写纯 WASM 代码也不是一个(理智上的)明智之举。因此,我们针对基准测试进行了一项调查,并选出了以下候选语言:

n体算法已用上述3种语言实现,并与JavaScript基线实现进行了对比测试。

在每次实现中,我们都将数据点数量保持在 1000,并使用不同的迭代次数运行算法。每次运行后,我们都测量了完成计算所需的时间。

基准测试的设置如下:

  • NodeJS 版本 12.9.1
  • Chrome 版本 79.0.3945.130(正式版本)(64 位)

  • clang 版本 10.0.0 - C 语言版本

  • emcc 1.39.6 - Emscripten gcc/clang 替代品 + 链接器

  • 货物 1.40.0

  • wasm-pack 0.8.1

  • AssemblyScript 版本 0.9.0

  • macOS 10.15.2

  • 2017 款 MacBook Pro Retina

  • 英特尔双核 i5 处理器,主频 2.3 GHz,8GB DDR3 内存,配备 256GB 固态硬盘

虽然这台机器不是进行基准测试的顶级机器,但我们正在测试一个 WASM 构建版本,该版本将在浏览器环境中运行,而浏览器通常无法访问所有核心和 RAM 内存。

为了给基准测试增添一些趣味性,我们制作了每个实现的几个版本:一个版本中 n 体系统中的每个点都有一个 64 位数值坐标表示,另一个版本则有一个 32 位表示。

另一个需要考虑的因素可能是“双重”Rust实现:最初,基准测试中编写了一个“原始”的Rust“不安全”实现,没有使用任何特定的WASM工具链。后来,为了利用“wasm-pack”工具链,又开发了一个额外的“安全”Rust实现,该工具链承诺更容易集成JS,并在WASM中实现更好的内存管理。

数据分析

为了进行数据分析,我们测试了两种主要环境:Node.js 和浏览器环境(Chrome)。
两种基准测试均在“热机”状态下运行:即在每次基准测试运行前,垃圾回收器 (GC) 均未重置。实验结果表明,在每次测试后运行 GC 对测试结果没有明显影响。

AssemblyScript 源代码用于构建以下工件:

  • JS 基线实现
  • AssemblyScript WASM 模块
  • AssemblyScript asm.js 模块1

在Node.js中进行数据分析后,会显示以下场景:

Node.js

然后在浏览器中运行相同的测试套件:

铬合金

我们首先注意到的是,AssemblyScript 的“asm.js”版本运行速度比其他版本慢。这张图表不足以清晰地展示其他语言相对于 JS 实现的性能优劣,因此我们创建了以下图表来加以说明:

与 JS 基线 64 位版本的区别

与 JS 基线 32 位版本的区别

这里存在 32 位和 64 位之间的区别,这可能会导致这样一种想法:JS 数字可以同时使用这两种表示形式:JS 中的数字(我们的基准)始终是 64 位,但对于 WASM 编译器来说,这可能会产生一些差异。

尤其对于 32 位 AssemblyScript asm.js 构建来说,影响非常大。与 JS 基准版本以及 64 位版本相比,32 位构建版本的性能下降幅度很大。

由于 AssemblyScript 在图表中占据主导地位,很难看出其他语言与 JS 相比表现如何,因此我们创建了一个不包含 AssemblyScript 的图表摘要:

64 位系统,不含 AssemblyScript

32 位系统,不含 AssemblyScript

不同的数字表示似乎也会影响其他语言,但结果却有所不同:与 64 位 (double) 数字相比,C 在使用 32 位 (float) 数字时速度变慢,而 Rust 使用 32 位 (f32) 数字的速度始终比使用 64 位 (f64) 数字更快。

被污染的实现?

此时可能会出现一个问题:由于所有测试过的 WASM 构建版本都与 JS 实现的代码非常接近,那么是否有可能原生实现本身速度较慢,而 WASM 构建版本只是反映了这一点?

原生性能

原生版本的实现速度总是比对应的 JS 版本快。

观察发现,WASM 构建版本比其原生版本运行速度慢,性能损失在 20% 到 50% 之间——这是在迭代次数为 1000 次的简化基准测试版本上进行的测试:

C 与 WASM C
Rust 与 WASM Rust
Rust waspack

在上述测量中,原生测量还计算了引导时间,而 WASM 测量则剔除了该时间。

结论

我们使用 Rust(两种实现方式)测得的性能提升最高可达 20%,与基准 JavaScript 实现相比——这是平均水平。
这听起来像是 Rust 的优势,但实际上与所需的工作量相比,提升幅度非常小。
我们从中得到了什么启示?我们得出结论:精心编写 JavaScript 代码可以实现高性能,而无需转而使用其他语言。

学习新语言总是好事,但应该出于正确的理由:性能往往是“错误”的理由,因为性能更多地受到整体设计决策的影响,而非编译器或微基准测试的优化。
作为实践经验,我们曾将编程语言从 JavaScript 切换到 TypeScript 来编写我们自己的力导向布局算法:我们改进的是代码库的质量,而不是性能。我们在移植过程中测试了性能,结果只提升了 5%,这可能是由于算法重构所致——我们将在以后的博客文章中详细介绍。

如果你对性能和 JavaScript 感兴趣,你可能会对DotJS 2019 大会上的这个演讲很感兴趣,它得出了与我们类似的结果。


脚注

1:值得注意的是,“AssemblyScript asm.js 模块”实际上并不完全符合 asm.js 标准。我们尝试在模块顶部添加“use asm”注释,但浏览器拒绝了优化。后来,我们发现我们使用的 binaryen 编译器实际上并非以完全符合 asm.js 标准为目标,而是以某种高效的 JS 版 WASM 为目标。

文章来源:https://dev.to/linkuriousdev/to-wasm-or-not-to-wasm-3803