情况
在编写高性能JavaScript代码时,Chrome等人提供的标准分析工具并不总是足够的。它们似乎只提供功能级别的粒度,向下钻取并查找我需要的信息可能非常耗时。
在 .NET 中,StopWatch
类准确地给了我所需要的:任意代码段的亚微秒级分辨率计时。
对于JavaScript来说,performance.now()
曾经是衡量性能的好方法,但是为了响应Spectre和Meltdown,所有主流浏览器都将分辨率降低到甚至不到一毫秒。
引用 MDN on performance.now((:
时间戳实际上不是高分辨率。降低安全性 诸如Spectre之类的威胁,浏览器当前将结果四舍五入为" 不同程度。(Firefox 开始四舍五入到 2 毫秒 火狐 59.(某些浏览器也可能稍微随机化时间戳。 在将来的版本中,精度可能会再次提高;浏览器开发人员 仍在调查这些定时攻击以及如何最好地缓解 他们。
问题所在
我需要微秒级的精确计时。在撰写本文时,浏览器似乎没有提供任何选项或标志来禁用这些安全测量。也许我在谷歌上搜索了错误的术语,但我遇到的唯一文章是对安全问题的解释以及这些缓解措施如何解决这些问题。
我对这里的安全方面不感兴趣 - 我正在自己的机器上对性能关键型JavaScript代码进行基准测试,我唯一关心的是我以尽可能少的努力获得尽可能准确的测量结果。
现有解决方法
我想到了两个选项:
- 安装未实施这些缓解措施的旧版浏览器
例如,我必须将旧版本的FireFox用于基准测试,并将新版本的Chrome用于浏览。这是不切实际的,因为我需要在所有浏览器中进行测试(最好在所有浏览器中进行基准测试(。此外,新的优化不会在旧浏览器中实现,因此基准测试可能毫无用处。
- 使用 WebWorkers 实现自定义计时器
我已经看过各种关于此的旧博客文章,但它们似乎都没有达到我需要的高精度(毕竟,曾经有过这方面的performance.now()
(。
问题
如何获得有效的预 Spectre performance.now()
,而不必求助于较旧的浏览器版本、虚拟机等?
JavaScript 中是否有任何编码技术或库可以实现微秒级精度?
上述 3 种浏览器是否有任何选项或标志可以禁用这些安全措施?
我最终正在寻找一种方法来准确测量不同代码段的相对性能 - 所以如果有一个解决方案可以给我滴答声,而不是微秒,只要它是准确的并且跨浏览器工作,这也是可以接受的。
从 Firefox 79 开始,如果您让服务器随页面发送两个标头,则可以使用高分辨率计时器:
从 Firefox 79 开始,如果您使用
Cross-Origin-Opener-Policy
和Cross-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μs,这比您默认获得的精度高 50 倍。
(() => {
const start = performance.now();
let diff;
while ((diff = performance.now() - start) === 0);
return diff;
})();
对于这些标头,这将返回 0.02 或非常接近 0.02 的值,如果没有这些标头,则返回 1。Firefox 确实有一个名为 privacy.reduceTimerPrecision
的配置设置,可以禁用 Spectre 缓解。您可以使用 Firefox 的 about:config 页面将其切换为 false(在地址栏中键入 about:config
(。
通过 MDN 上的提示弄清楚了这一点。