JavaScript中的微时序

mwc*_*wcz 88 javascript

JavaScript中是否有任何具有微秒分辨率的计时功能?

我知道Chrome 的timer.js,我希望有其他友好浏览器的解决方案,如Firefox,Safari,Opera,Epiphany,Konqueror等.我对支持任何IE都不感兴趣,但是答案包括 IE受欢迎的.

(鉴于JS中毫秒级的准确性很差,我不会屏住呼吸!)

更新:timer.js通告微秒分辨率,但它只是将毫秒读数乘以1,000.通过测试和代码检查验证.失望.:[

Nic*_*icJ 119

正如Mark Rejhon的回答中所提到的,现代浏览器中有一个API可以将亚毫秒分辨率的定时数据暴露给脚本:W3C高分辨率定时器,又名window.performance.now().

now()Date.getTime()在两个重要方面比传统方式更好:

  1. now()是一个亚毫秒分辨率的双精度,表示自页面导航开始以来的毫秒数.它返回小数中的微秒数(例如,1000.123的值是1秒和123微秒).

  2. now()是单调增加的.这很重要,因为Date.getTime()可能在后续呼叫中向前跳甚至向后跳.值得注意的是,如果OS的系统时间更新(例如原子钟同步),Date.getTime()也会更新. now()保证总是单调增加,因此它不受操作系统的系统时间的影响 - 它将始终是挂钟时间(假设你的挂钟不是原子的......).

now()可以在几乎每个地方使用new Date.getTime(),+ new Date并且Date.now()是.唯一的例外是,Datenow()时代不混合,如Date基于UNIX的时期(自1970年以来的毫秒数),而now()就是因为你的页面导航开始的毫秒数(所以它会比小得多Date).

now()Chrome stable,Firefox 15+和IE10支持.还有几种填充剂.

  • `new Date.getTime()`不是一个东西.`new Date().getTime()`是. (4认同)
  • 我的挂钟*是*原子的. (3认同)
  • 重温我的**年 2012** 评论。performance.now() 现在通过 Meltdown/Spectre 解决方法再次有点模糊。由于安全原因,一些浏览器严重降低了 performance.now()。我认为我的技术可能已经在大量合法的基准测试用例中重新获得了一些相关性,但受到计时器模糊的限制。也就是说,某些浏览器现在具有一些 2012 年不存在的开发人员性能分析功能/扩展。 (3认同)

Mar*_*hon 20

现在有一种在javascript中测量微秒的新方法:http: //gent.ilcore.com/2012/06/better-timer-for-javascript.html

但是,在过去,我发现了一种粗略的方法,即在毫秒计时器中获得0.1毫秒的JavaScript精度.不可能?不.继续阅读:

我正在进行一些需要自检定时器精度的高精度实验,并发现我能够在某些系统上使用某些浏览器可靠地获得0.1毫秒的精度.

我发现在快速系统上的现代GPU加速网络浏览器中(例如i7四核,其中几个内核空闲,只有浏览器窗口) - 我现在可以相信定时器是毫秒准确的.实际上,它在空闲的i7系统上变得如此准确,我已经能够可靠地获得相同的毫秒,超过1,000次尝试.只有当我尝试加载额外的网页或其他内容时,毫秒精度才会降低(并且我能够通过进行前后时间检查来成功捕获自己降低的精度,看看是否我的处理时间突然延长到1毫秒或更长 - 这有助于我使可能受CPU波动影响太大的结果无效.

它在i7四核系统的某些GPU加速浏览器中变得如此准确(当浏览器窗口是唯一的窗口时),我发现我希望能在JavaScript中访问0.1ms精度计时器,因为准确性现在终于到了在一些高端浏览系统上,这种定时器精度对于需要高精度的某些类型的小众应用是值得的,并且应用程序能够自我验证精度偏差.

显然,如果你进行多次传球,你可以简单地运行多次传球(例如10次传球)然后除以10以获得0.1毫秒的精度.这是获得更好精度的常用方法 - 执行多次传递并将总时间除以传球次数.

但是......如果由于异常独特的情况我只能进行特定测试的单一基准测试,我发现通过这样做我可以得到0.1(有时是0.01ms)精度:

初始化/校准:

  1. 运行一个繁忙的循环,等待计时器递增到下一毫秒(将计时器对准下一毫秒间隔的开始)这个繁忙的循环持续不到一毫秒.
  2. 在等待定时器递增时运行另一个忙循环以递增计数器.计数器告诉您在一毫秒内发生了多少计数器增量.这个繁忙的循环持续一整毫秒.
  3. 重复上述步骤,直到数字变得超稳定(加载时间,JIT编译器等).4. 注意:数字的稳定性使您可以在空闲系统上获得可达到的精度.如果需要自检精度,可以计算方差.某些浏览器的差异较大,而其他浏览器的差异较小.更快的系统更大,慢速系统更慢.一致性也各不相同.您可以确定哪些浏览器比其他浏览器更一致/更准确.较慢的系统和繁忙的系统将导致初始化过程之间的差异更大.如果浏览器没有给出足够的精度以允许0.1ms或0.01ms的测量,这可以让您有机会显示警告消息.定时器偏移可能是一个问题,但某些系统上的某些整数毫秒定时器会非常准确地增加(在点上非常正确),这将导致您可信赖的非常一致的校准值.
  4. 保存最终计数器值(或最后几次校准通过的平均值)

将一次传递标准化为亚毫秒精度:

  1. 运行一个繁忙的循环,等待计时器递增到下一毫秒(将计时器对准下一毫秒间隔的开始).这个繁忙的循环持续不到一毫秒.
  2. 执行您想要精确确定时间基准的任务.
  3. 检查计时器.这给你整数毫秒.
  4. 运行最后一个忙循环以在等待定时器递增时递增计数器.这个繁忙的循环持续不到一毫秒.
  5. 将此计数器值除以初始化的原始计数器值.
  6. 现在你得到毫秒的小数部分!!!!!!!!

警告:不建议在Web浏览器中使用繁忙的循环,但幸运的是,这些繁忙的循环每次运行的时间不到1毫秒,并且只运行了几次.

诸如JIT编译和CPU波动之类的变量会增加大量的不准确性,但是如果你运行几个初始化过程,你将完全动态重新编译,并最终计数器达到非常准确的状态.确保所有繁忙循环对于所有情况都是完全相同的功能,因此繁忙循环中的差异不会导致差异.在开始信任结果之前,确保所有代码行都被执行了几次,以允许JIT编译器已经稳定到完全动态重新编译(dynarec).

事实上,我目睹某些系统的精确度接近微秒,但我还是不相信它.但是在一个空闲的四核系统中,0.1毫秒的精度看起来非常可靠,我是唯一的浏览器页面.我来到一个科学测试案例中,我只能进行一次性传球(由于发生了独特的变量),并且需要精确计时每次传球,而不是平均多次重复传球,这就是我这样做的原因.

我做了几次预通过和虚拟通过(也用于解决dynarec),验证0.1ms精度的可靠性(保持稳定几秒),然后让我的手离开键盘/鼠标,同时基准测试发生,然后做了几次通过后验证0.1ms精度的可靠性(再次保持稳定).这也验证了在前后之间没有发生诸如电源状态变化或其他因素之类的事情,从而干扰了结果.在每个基准测试通道之间重复预测试和后测试.在此之后,我几乎可以肯定其间的结果是准确的.当然,不能保证,但它表明在某些情况下在Web浏览器中可以精确<0.1ms的精度.

此方法仅适用于非常非常小的情况.即便如此,它实际上也不会100%无限保证,当与多层内部和外部验证结合使用时,您可以获得非常可靠的准确度,甚至科学准确性.

  • 大多数浏览器降低了 Performance.now() 实现的精度,以暂时缓解缓存计时攻击。我想知道这个答案对于安全研究是否还有意义。 (4认同)
  • 过去以高精度进行计时比较复杂,因为我们只有`Date.now()`或`+ new Date()`.但是现在我们有了`performance.now()`.虽然很明显你找到了一些很酷的方法来破解更多功能,但这个答案基本上已经过时了.此外,不建议任何与繁忙循环相关的内容.只是不要这样做.我们不需要更多. (3认同)
  • 重温我自己的评论。哇,我在Performance.now()之前的**年**中发布了以上内容。但是现在,Meltdown / Spectre的解决方法又使它有点模糊了。由于安全原因,某些浏览器已严重降低了performance.now()。我认为上述技术可能已经重新获得了很多相关的基准测试用例的相关性,但受到计时器模糊限制。 (2认同)