为什么 sin 在 WebAssembly 中比在 Java 脚本中慢?

问题描述 投票:0回答:1

我有一些非常简单的基准测试,通过 Catch2 运行,并使用 -O3 进行编译:

emscripten 3.1.37

我预计 JavaScript 和 WebAssembly 之间不会有太大差异,但有:

BENCHMARK("cpp sin only") { double sum = 1.0; for (int t = 0; t < 2000000; ++t) { sum += sin(double(t)); } return sum; }; #ifdef __EMSCRIPTEN__ BENCHMARK("js sin only") { EM_ASM_DOUBLE({ let sum = 1; for (let i = 0; i < 2000000; i++) { sum = sum + Math.sin(i); } return sum; }); }; #endif

原生,用
chrome: benchmark name samples iterations est run time mean low mean high mean std dev low std dev high std dev ------------------------------------------------------------------------------- cpp sin only 100 1 7.93775 s 79.3856 ms 79.147 ms 79.7195 ms 1.43061 ms 1.10437 ms 1.97222 ms js sin only 100 1 2.21506 s 22.1354 ms 22.0064 ms 22.3 ms 742.138 us 614.746 us 901.128 us

编译,我得到24.2ms。


据我了解,JavaScript 对所有数字都使用双精度浮点数。所以比较应该是公平的。在 C++ 版本中使用 float 时,在 chrome 中会达到 12 毫秒,但这仍然较慢(且精度较低)。 FF 约为 30 毫秒。
  • 也许 JavaScript 使用不太精确但更快的 sin 和 sqrt 实现?添加
  • GCC 12.3.0 不会提高 double 的性能。 Chrome 中的快速数学浮动变得与 JavaScript 一样快,在 FF 中仍然在 30 毫秒左右。
    
    
    WebAssembly 是否在优化器中没有获得足够多的时间?这可以解释为什么 FF 的速度慢得多。但 emscripten 不应该负责大部分优化吗?
  • 这可能是某种防止崩溃/幽灵的保护措施吗?
更新

(我根据评论中的请求运行了几个额外的基准测试):

g++12 比 clang15 快一点,但在 10% 以内
  • 不同版本之间 sqrt 的性能几乎相同(在示例中存在 sqrt 和 sin 之前)
  • 大部分时间都在罪恶中度过。
  • 将迭代次数增加到 200 万次,使 JS 速度提高约 4 倍。将其增加到 500 万,将领先优势提高到 10 倍。 JS 的速度仍然与原生 C++ 大致相同。
  • 请注意,Catch2 执行了 100 次基准测试。上述代码的运行时间约为1s。
  • 我验证了,并不像JS使用float那么简单。 WebAssembly C++ 计算与 JS 结果完全匹配。
  • 使用 123456789042+1000000 将 gcc、clang Native、WebAssembly C++ 和 JS 的运行时间提高了约 3-4 倍(WebAssembly 与 JS 的相对性能保持不变)。
  • 参考,这是我使用的代码:
  • https://pastebin.com/Mu2barB6
  • ,这是 chrome 的结果:https://pastebin.com/Hbte7yRj
更新2:

在用户21489919

评论

之后,我向emscripten报告了该问题

webassembly emscripten
1个回答
-1
投票

您可以通过使用 .c 而不是 .cpp 和 #include

.

来双重确保使用常规双精度。

© www.soinside.com 2019 - 2024. All rights reserved.