最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

performance - How to get microsecond timings in JavaScript since Spectre and Meltdown - Stack Overflow

programmeradmin1浏览0评论

The situation

When writing high-performance JavaScript code, the standard profiling tools offered by Chrome et al are not always sufficient. They only seem to offer function-level granularity and it can be quite time-consuming to drill down and find the information I need.

In .NET the StopWatch class gives me exactly what I need: sub-microsecond resolution timing of arbitrary pieces of code.

For JavaScript performance.now() used to be a pretty good way to measure performance, but in response to Spectre and Meltdown all major browsers have reduced the resolution down to not even a millisecond.

To quote MDN on performance.now():

The timestamp is not actually high-resolution. To mitigate security threats such as Spectre, browsers currently round the result to varying degrees. (Firefox started rounding to 2 milliseconds in Firefox 59.) Some browsers may also slightly randomize the timestamp. The precision may improve again in future releases; browser developers are still investigating these timing attacks and how best to mitigate them.

The problem

I need microsecond precision timings. At the time of writing, browsers don't seem to offer any options or flags to disable these security measurements. Maybe I'm googling the wrong terms but the only articles I come across are explanations of the security problems and how these mitigations address them.

I'm not interested in the security aspect here - I'm benchmarking performance-critical pieces of JavaScript code on my own machine and the only thing I care about is that I get as accurate measurements as possible with as little effort as possible.

Existing workarounds

Two options come to mind:

  1. Install an older version of a browser that doesn't have these mitigations implemented

I'd have to dedicate an old version of FireFox to benchmarking, and a new version of Chrome to browsing for example. That's not practical since I need to test in all browsers (and preferably also benchmark in all browsers). Also, new optimizations are not implemented in old browsers so the benchmarks would be potentially useless.

  1. Implement a custom timer using WebWorkers

I've seen various older blog posts on this but none of them seem to achieve the high precision that I need (after all, there used to be performance.now() for that).

The question

How do I get an effectively pre-Spectre performance.now() without having to resort to older browser versions, Virtual Machines and such?

Are there any coding techniques or libraries in JavaScript that achieve microsecond precision?

Are there any options or flags for the 3 aforementioned browsers that disable these security measures?

I'm ultimately looking for a way to accurately measure the relative performance of different pieces of code compared to one another - so if there is a solution that gives me ticks, rather than microseconds, that would be acceptable too as long as it's accurate and works across browsers.

The situation

When writing high-performance JavaScript code, the standard profiling tools offered by Chrome et al are not always sufficient. They only seem to offer function-level granularity and it can be quite time-consuming to drill down and find the information I need.

In .NET the StopWatch class gives me exactly what I need: sub-microsecond resolution timing of arbitrary pieces of code.

For JavaScript performance.now() used to be a pretty good way to measure performance, but in response to Spectre and Meltdown all major browsers have reduced the resolution down to not even a millisecond.

To quote MDN on performance.now():

The timestamp is not actually high-resolution. To mitigate security threats such as Spectre, browsers currently round the result to varying degrees. (Firefox started rounding to 2 milliseconds in Firefox 59.) Some browsers may also slightly randomize the timestamp. The precision may improve again in future releases; browser developers are still investigating these timing attacks and how best to mitigate them.

The problem

I need microsecond precision timings. At the time of writing, browsers don't seem to offer any options or flags to disable these security measurements. Maybe I'm googling the wrong terms but the only articles I come across are explanations of the security problems and how these mitigations address them.

I'm not interested in the security aspect here - I'm benchmarking performance-critical pieces of JavaScript code on my own machine and the only thing I care about is that I get as accurate measurements as possible with as little effort as possible.

Existing workarounds

Two options come to mind:

  1. Install an older version of a browser that doesn't have these mitigations implemented

I'd have to dedicate an old version of FireFox to benchmarking, and a new version of Chrome to browsing for example. That's not practical since I need to test in all browsers (and preferably also benchmark in all browsers). Also, new optimizations are not implemented in old browsers so the benchmarks would be potentially useless.

  1. Implement a custom timer using WebWorkers

I've seen various older blog posts on this but none of them seem to achieve the high precision that I need (after all, there used to be performance.now() for that).

The question

How do I get an effectively pre-Spectre performance.now() without having to resort to older browser versions, Virtual Machines and such?

Are there any coding techniques or libraries in JavaScript that achieve microsecond precision?

Are there any options or flags for the 3 aforementioned browsers that disable these security measures?

I'm ultimately looking for a way to accurately measure the relative performance of different pieces of code compared to one another - so if there is a solution that gives me ticks, rather than microseconds, that would be acceptable too as long as it's accurate and works across browsers.

Share Improve this question edited Mar 2, 2023 at 12:35 sideshowbarker 88.1k29 gold badges214 silver badges211 bronze badges asked May 1, 2018 at 13:39 Fred KleuverFred Kleuver 8,0472 gold badges29 silver badges38 bronze badges 23
  • 2 Given what you're describing sounds like quite low level timings, presumably it's not totally dependent on running in a browser (where accessing the DOM, performing ajax etc will be orders of magnitude slower than any code that's running) - could you instead work within the node.js environment? You have process.hrtime there. – James Thorpe Commented May 1, 2018 at 13:47
  • 3 I think your best bet is to look for a knob somewhere that re-enables high precision timing in modern browsers; presumably they made it possible to enable for use-cases like yours. I don't know how, but I'd guess it's possible. You may have to build your own Firefox and Chromium from source with that option disabled, though. You mainly care about using this in your own browser on one or a few machines, because this is for benchmarking use. – Peter Cordes Commented May 1, 2018 at 14:06
  • 2 @PeterCordes JavaScript doesn't do threading, everything conceptually happens in a message loop in a single thread - while you have the likes of service workers now (which can be thought of as threads), you have to post messages between them - there's no guarantee as to how fast that message will be seen – James Thorpe Commented May 1, 2018 at 14:14
  • 1 @Mike'Pomax'Kamermans One example of what I want to benchmark is specific hot paths in a parser. Testing whether a switch statement with 100 cases is perhaps a few % faster than a switch statement with only 20 cases and 2-3 if-elses. The optimizations are very different in Chrome vs FireFox vs Edge. Sometimes in Chrome it cannot be optimized further, but in FireFox it can. Apart from this low-level example, there are also higher-level benchmarks I'm looking for which are still sub-millisecond. – Fred Kleuver Commented May 1, 2018 at 14:18
  • 2 Yeah you'd say so, but I've googled all over for disabling the precision restriction - the utter lack of results is what led me to ask this question. I think I found the commit in chromium: github.com/chromium/chromium/commit/… - looks pretty hard-coded to me. – Fred Kleuver Commented May 1, 2018 at 15:12
 |  Show 18 more comments

2 Answers 2

Reset to default 11

Since Firefox 79, you can use high resolution timers if you make your server send two headers with your page:

Starting with Firefox 79, high resolution timers can be used if you cross-origin isolate your document using the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers:

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

These headers ensure a top-level document does not share a browsing context group with cross-origin documents. COOP process-isolates your document and potential attackers can't access to your global object if they were opening it in a popup, preventing a set of cross-origin attacks dubbed XS-Leaks.

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

It's not mentioned on that page as of this moment, but with a little experiment, I've concluded that the accuracy of the timer is 20µs with those headers present, which is 50x better than the accuracy you get by default.

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

This returns 0.02 or a value very close to 0.02 with those headers, and 1 without.

Firefox does have a config setting called privacy.reduceTimerPrecision that disables the Spectre mitigation. You can switch it to false using Firefox's about:config page (type about:config into the address bar).

Figured this out via a hint on MDN.

发布评论

评论列表(0)

  1. 暂无评论