自Spectre和Meltdown以来如何在JavaScript中获得微秒时序

时间:2018-05-01 13:39:28

标签: javascript performance benchmarking

情况

在编写高性能JavaScript代码时,Chrome等人提供的标准分析工具并不总是足够的。它们似乎只提供功能级粒度,向下钻取并找到我需要的信息可能非常耗时。

在.NET中,StopWatch类给出了我所需要的:任意代码段的亚微秒分辨率计时。

对于JavaScript来说performance.now()曾经是测量性能的一种非常好的方法,但是为了响应Spectre和Meltdown,所有主流浏览器都将分辨率降低到甚至不到一毫秒。

performance.now()上引用MDN:

  

时间戳实际上不是高分辨率。为了减轻安全性   像Spectre这样的威胁,浏览器目前将结果舍入到   不同程度。 (Firefox开始四舍五入到2毫秒   Firefox 59.)有些浏览器也可能会稍微随机化时间戳。   在未来的版本中,精度可能会再次提高;浏览器开发者   仍在调查这些时间攻击以及如何最好地减轻攻击   它们。

问题

我需要微秒精度计时。在撰写本文时,浏览器似乎没有提供任何选项或标志来禁用这些安全措施。也许我在谷歌搜索错误的条款,但我遇到的唯一文章是安全问题的解释以及这些缓解如何解决它们。

我对这里的安全方面不感兴趣 - 我在自己的机器上对性能关键的JavaScript代码进行基准测试,我唯一关心的是我可以获得尽可能准确的测量结果尽可能少的努力。

现有解决方法

有两种选择:

  1. 安装尚未实施这些缓解措施的旧版浏览器
  2. 我必须将旧版本的FireFox用于基准测试,并将Chrome的新版本用于浏览。这是不切实际的,因为我需要在所有浏览器中进行测试(最好还是在所有浏览器中进行测试)。此外,旧的浏览器中没有实现新的优化,因此基准测试可能无用。

    1. 使用WebWorkers实现自定义计时器
    2. 我已经看过各种较旧的博客文章,但它们似乎都没有达到我所需要的高精度(毕竟,过去常常有performance.now()

      问题

      如何在不必使用旧浏览器版本,虚拟机等的情况下获得有效的前幽灵performance.now()

      JavaScript中是否有任何编码技术或库可以达到微秒精度?

      上述3种浏览器是否有禁用这些安全措施的选项或标志?

      我最终正在寻找一种方法来准确衡量不同代码片段相对于彼此的相对性能 - 所以如果有一个解决方案可以给我滴答,而不是微秒,这也是可以接受的只要它准确并且可以跨浏览器工作。

2 个答案:

答案 0 :(得分:2)

Firefox确实有一个名为privacy.reduceTimerPrecision的配置设置,它禁用了Spectre缓解措施。您可以使用Firefox的about:config页面(在地址栏中输入about:config)将其设置为false。

通过MDN上的提示了解了这一点。

答案 1 :(得分:1)

自 Firefox 79 起,如果您让服务器随页面发送两个标头,则可以使用高分辨率计时器:

<块引用>

从 Firefox 79 开始,如果您使用 Cross-Origin-Opener-PolicyCross-Origin-Embedder-Policy 标头跨源隔离文档,则可以使用高分辨率计时器:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

这些标题确保顶级文档不与跨源文档共享浏览上下文组。 COOP 流程 - 隔离您的文档,如果潜在攻击者在弹出窗口中打开它,则他们无法访问您的全局对象,从而防止一系列被称为 XS-Leaks 的跨源攻击。

参考:https://developer.mozilla.org/en-US/docs/Web/API/Performance/now

截至目前,该页面上还没有提到它,但通过一些小实验,我得出结论,当存在这些标头时,计时器的准确度为 20 微秒,比默认情况下获得的准确度高 50 倍。< /p>

(() => {
  const start = performance.now();
  let diff;
  while ((diff = performance.now() - start) === 0);
  return diff;
})();

这将返回 0.02 或非常接近 0.02 的值,有这些标题,没有 1。