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:
- 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.
- 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.
process.hrtime
there. – Raynaraynah[benchmarking]
and[performance]
tags :P) – Sitkaswitch
statement you might well need nanosecond precision to get useful results. Some messy multi-threading stuff you hack up is not going to be worth the trouble vs. getting the JS implementation to give you high-rez time directly. For open source browsers it's definitely possible, it just might take a bit of work. The relative performance of the same x86 asm can be different on different hardware, too, so you don't want a timing method that also varies with CPUs making it impossible to tell what's what. (But beware of turbo / powersave CPU frequency variation either way) – SitkaTimeClamper::ClampTimeResolution
. But if there is, you wouldn't necessarily see it in that patch, because there was already a 5us limit before that. Anyway, looks easy to disable in the source. Changingstatic constexpr double kResolutionSeconds = 0.0001
to1.0
would work, or for lower overhead by makingTimeClamper::ClampTimeResolution
a no-op or leaving out calls to it. (And BTW,floor(time_seconds / kResolutionSeconds)
would be more efficient asfloor(time_seconds * (1.0/kResolutionSeconds))
to avoid runtime division. – Sitka