New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 158234 link

Starred by 35 users

Issue metadata

Status: Fixed
Owner:
Last visit > 30 days ago
Closed: Sep 2014
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Windows
Pri: 2
Type: Bug


Sign in to add a comment

window.performance.now does not support sub-millisecond precision on Windows

Reported by jra...@gmail.com, Oct 28 2012

Issue description

UserAgent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.16 (KHTML, like Gecko) Chrome/24.0.1305.3 Safari/537.16

Steps to reproduce the problem:
1. Visit http://jcode.org/test_timers.html which shows several timing results for a function computing F30 of the fibonacci series.

The first set of results is timed using the Date.getTime() API and the second set is timed using the window.performance.now() (or window.performance.webkitNow()) API.

What is the expected behavior?
The window.performance.now() results should millisecond results where the fractional part is non zero:

    20.9453 milliseconds

What went wrong?
On Windows the result is always truncated or rounded to the nearest millisecond:

    13.0000 milliseconds

I checked Chrome on Linux and the result correctly shows sub-millisecond precision and so does Firefox on Windows.

Did this work before? N/A 

Chrome version: 24.0.1305.3  Channel: dev
OS Version: 6.2 (Windows 8)
 
Showing comments 14 - 113 of 113 Older
Not to increase pressure but just to add another reason that we need this to the list; yesterday the Maps team was lamenting the lack of sub-ms precision in the timer because it makes it harder for them to do performance measurements and it makes the JavaScript job scheduler much less accurate. I'm sure they'd appreciate this being fixed too!
Labels: -Mstone-26
This seems like a totally reasonable request.  I assume we're just waiting for the results from Simon's field trial before moving forward with this code change?
Project Member

Comment 17 by bugdroid1@chromium.org, Mar 10 2013

Labels: -Area-Internals Cr-Internals
Is the field trial going in for M27? When will we know if it's reasonable to implement?

Comment 19 by zar...@gmail.com, Mar 14 2013

Been waiting for this one to get fixed since reading Paul Irish announcement/article in mid 2012 (http://updates.html5rocks.com/2012/08/When-milliseconds-are-not-enough-performance-now).

What's the hold up? Is it that this issue just got buried and forgotten?
When's the M27 branch? I haven't started. I won't get to it for at least another week. Is anyone else interested in writing it?
FYI, M27 branch is in just a few days.
Did this make M27?
Nope, not in M27, but I started on the field trial today. We'll probably start small and whitelist a few known good configurations, then try to expand that whitelist.
Any news or updates? I've been contacted by a partner who ran into this. Thanks!
The code review for the experiment is here:

https://codereview.chromium.org/13583007/

With that, we can figure out which subset of users will be able to enable high res time. Then we can try actually switching them over and see what breaks. So it'll be a bit before this is done.

Even so, in the end, it's likely that we'll only be able to enable high res time for a subset of Windows users. Probably, Vista or better with modern CPUs only.
Thanks for the info!
Project Member

Comment 27 by bugdroid1@chromium.org, Apr 30 2013

------------------------------------------------------------------------
r197431 | simonjam@chromium.org | 2013-04-30T19:46:05.537839Z

Changed paths:
   A http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/metrics/time_ticks_experiment_unittest.cc?r1=197431&r2=197430&pathrev=197431
   A http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/metrics/time_ticks_experiment_win.h?r1=197431&r2=197430&pathrev=197431
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/chrome_browser.gypi?r1=197431&r2=197430&pathrev=197431
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/cpu.cc?r1=197431&r2=197430&pathrev=197431
   M http://src.chromium.org/viewvc/chrome/trunk/src/tools/metrics/histograms/histograms.xml?r1=197431&r2=197430&pathrev=197431
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/cpu.h?r1=197431&r2=197430&pathrev=197431
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/metrics/metrics_service.cc?r1=197431&r2=197430&pathrev=197431
   A http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/metrics/time_ticks_experiment_win.cc?r1=197431&r2=197430&pathrev=197431
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/chrome_tests_unit.gypi?r1=197431&r2=197430&pathrev=197431

Create a field trial to test if we can detect good QPC implementations.

We'd like to use QPC (TimeTicks::HighResNow) for all uses of TimeTicks. It's
likely this will only work on some subset of Windows systems. This field trial
is meant to determine if an implementation is good and if our heuristics are
able to detect a good implementation.

This particular CL checks for an Intel CPU parameter that indicates rdtsc is
consistently incremented. Firefox uses the same check. I hope to determine that
this is in fact correct and on which versions of Windows QPC calls rdtsc
directly.

We can add more heuristics later.

BUG= 158234 

Review URL: https://chromiumcodereview.appspot.com/13583007
------------------------------------------------------------------------

Comment 28 by maurerj@google.com, Jun 12 2013

What is the status of this experiment and getting this enabled?
Status: Started
We have the all-clear to implement it on canary channel. We'll slowly expand out to other channels as we get additional data.

For now, it's limited to users with non-stop TSC processors. That's about 50% of canary channel, but probably drastically less on stable channel.

Those that don't support non-stop TSC will still only have 1ms resolution (at best).

Comment 30 by maurerj@google.com, Jun 12 2013

Do you have ETA when it will be available in canary?  This is blocking us
from doing some needed deep level performance tracing for windows chrome.

~Jennifer
Do you just need this for local testing? It'd be easy to hack into a build.

Otherwise, gimme a couple of days. I'm juggling a bunch of stuff.

Comment 32 by maurerj@google.com, Jun 13 2013

Need to test across multiple computers, so would be better to spend the time actually getting it in canary - if we can get it in by end of next week that would be great.  If not, then might be worth getting a hacked build.
It looks like we've got a trickle of users on dev channel whose high-res clocks tick backwards occasionally. That means we'll have to put the brakes on this until we can figure out how to identify them.

In the meantime, if you need it, a patch to force high res time on is available here: https://codereview.chromium.org/16896018/

Or I can dump a build somewhere.
Blockedon: chromium:254211

Comment 35 Deleted

Comment 36 by marky...@gmail.com, Jul 26 2013

A very good test of performance debugging of performance.now is:
http://www.testufo.com/#test=animation-time-graph&scale=2&ppf=2

Internet Explorer does the best job, while FireFox 24+ beta does pretty well, while Chrome looks very "granular".  

I do, however, want to compliment Chrome's long-time proper support 120fps animations on 120Hz computer monitors at http://www.testufo.com/browser.html for the TestUFO motion tests at http://www.testufo.com ... (I am the creator of these browser motion tests).
Simonjam -- high-resolution clocks clicks backwards because of different synchronization between cores of a CPU.  Thread affinity to a core fixes the occasional "backwards clock tick" problem.  Alternatively, another simple fix is simply to reject the high-res clock tick if it's less than last tick (fallback to last tick if less than 1ms, fallback to Date().getTime() if more than 1ms).  This is just a simple one-line "if" statement.  
A different excellent test that demonstrates the useful of accurate sub-millisecond JavaScript performance self-profiling, works well in IE10+ and FF24+:
http://www.testufo.com/#test=animation-time-graph&scale=5&ppf=2&measure=animation

I have hereby attached an image of three graphs generated by IE10, FireFox24, and Chrome (28,29,30 looks the same).  The precision is ugly only in Chrome.

Again, backward ticks is simply microsecond differences between CPU cores -- especially whenever there's a thread context switch of the system clock measuring thread; SOLUTION: Fixed via thread affinity or via a simple IF statement check to reject backward ticks.

(Image attached)
image-graph-of-performance-now-IEvsFFvsCHROME.png
124 KB View Download
Project Member

Comment 39 by bugdroid1@chromium.org, Aug 13 2013

------------------------------------------------------------------------
r217172 | simonjam@chromium.org | 2013-08-13T02:45:59.498583Z

Changed paths:
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.h?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/profiler/tracked_time.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time.h?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/renderer_host/render_process_host_impl.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/browser_child_process_host_impl.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/test/test_suite.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/chrome_browser_main_win.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/app/content_main_runner.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time_win.cc?r1=217172&r2=217171&pathrev=217172
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.cc?r1=217172&r2=217171&pathrev=217172

Enable high resolution time for TimeTicks::Now on Windows Canary

This should be unnoticeable, except for improved resolution in places such as window.performance.now().

The feature is enabled if the user is running Canary channel or has manually specified the --enable-high-resolution-time flag. This will only work if the CPU has a non-stop TSC and isn't a broken Athlon processor. UMA data show this is a safe combination.

The flag is propagated to renderer processes so that they know to enable it too.

BUG= 158234 

Review URL: https://chromiumcodereview.appspot.com/16896018
------------------------------------------------------------------------
Project Member

Comment 40 by bugdroid1@chromium.org, Aug 13 2013

------------------------------------------------------------------------
r217226 | nhiroki@chromium.org | 2013-08-13T09:30:11.576201Z

Changed paths:
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/renderer_host/render_process_host_impl.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/browser_child_process_host_impl.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/test/test_suite.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/chrome_browser_main_win.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/app/content_main_runner.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time_win.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.h?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/profiler/tracked_time.cc?r1=217226&r2=217225&pathrev=217226
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time.h?r1=217226&r2=217225&pathrev=217226

Revert 217172 "Enable high resolution time for TimeTicks::Now on..."

There is a suspicion that this might break some tests:

MessageLoopTest.PostDelayedTask_InPostOrder_2,
StatsTableTest.StatsCounterTimer
TimeTicks.Deltas

http://build.chromium.org/p/chromium.win/builders/XP%20Tests%20%282%29/builds/30128
http://build.chromium.org/p/chromium.win/builders/Win7%20Tests%20%28dbg%29%281%29/builds/21737

> Enable high resolution time for TimeTicks::Now on Windows Canary
> 
> This should be unnoticeable, except for improved resolution in places such as window.performance.now().
> 
> The feature is enabled if the user is running Canary channel or has manually specified the --enable-high-resolution-time flag. This will only work if the CPU has a non-stop TSC and isn't a broken Athlon processor. UMA data show this is a safe combination.
> 
> The flag is propagated to renderer processes so that they know to enable it too.
> 
> BUG= 158234 
> 
> Review URL: https://chromiumcodereview.appspot.com/16896018

TBR=simonjam@chromium.org

Review URL: https://codereview.chromium.org/22984005
------------------------------------------------------------------------
Project Member

Comment 41 by bugdroid1@chromium.org, Sep 10 2013

------------------------------------------------------------------------
r222396 | simonjam@chromium.org | 2013-09-10T23:36:08.575506Z

Changed paths:
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/test/test_suite.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/chrome_browser_main_win.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/app/content_main_runner.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time_win.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.h?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/profiler/tracked_time.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/threading/platform_thread_win.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time.h?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/renderer_host/render_process_host_impl.cc?r1=222396&r2=222395&pathrev=222396
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/browser_child_process_host_impl.cc?r1=222396&r2=222395&pathrev=222396

Enable high resolution time for TimeTicks::Now on Windows Canary

This should be unnoticeable, except for improved resolution in places such as window.performance.now().

The feature is enabled if the user is running Canary channel or has manually specified the --enable-high-resolution-time flag. This will only work if the CPU has a non-stop TSC and isn't a broken Athlon processor. UMA data show this is a safe combination.

The flag is propagated to renderer processes so that they know to enable it too.

BUG= 158234 

Review URL: https://chromiumcodereview.appspot.com/23147002
------------------------------------------------------------------------
Thanks James. Have you been able to verify this is working in Canary?
Seems to be. I was going to enable it everywhere after the branch.
Cc: jbau...@chromium.org
James, if I understand the UMA stats correctly, they do not provide any visibility into the performance of QPC when cpu.has_non_stop_time_stamp_counter() is false. Is that correct? If so, can we collect a separate set of stats for when cpu.has_non_stop_time_stamp_counter() is false?

Also, can we collect data for TimeTicks::Now() and keep a histogram of whether the calls to TimeTicks::Now() or HighResNow() are faster?
That's correct, Brian.

Please feel free to add things to the experiment. I have all the data I need from it in its current form.

I intended to expand on it, so that we could find other CPUs that are good even if they don't have the non-stop TSC bit. I haven't gotten around to that yet.
Project Member

Comment 47 by bugdroid1@chromium.org, Oct 25 2013

------------------------------------------------------------------------
r230968 | simonjam@chromium.org | 2013-10-25T06:39:17.153547Z

Changed paths:
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.cc?r1=230968&r2=230967&pathrev=230968
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.h?r1=230968&r2=230967&pathrev=230968
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/renderer_host/render_process_host_impl.cc?r1=230968&r2=230967&pathrev=230968
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/browser_child_process_host_impl.cc?r1=230968&r2=230967&pathrev=230968
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/chrome_browser_main_win.cc?r1=230968&r2=230967&pathrev=230968
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/app/content_main_runner.cc?r1=230968&r2=230967&pathrev=230968

Use HighResNow whenever possible on Windows.

This has been enabled on Canary channel for sometime now and seems to be
safe there. We also now have data from stable channel showing there are
no unexpectedly buggy CPUs out there. This should be safe to turn on for
all users with adequate CPUs, which is the majority of them.

BUG= 158234 

Review URL: https://codereview.chromium.org/41953002
------------------------------------------------------------------------
Status: Fixed
This is now fixed in the general case. I'll file a separate bug to experiment with CPUs that lack a non-stop TSC.
Labels: M-32
Project Member

Comment 50 by bugdroid1@chromium.org, Oct 25 2013

------------------------------------------------------------------------
r231152 | scottmg@chromium.org | 2013-10-25T23:38:45.098708Z

Changed paths:
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/browser_child_process_host_impl.cc?r1=231152&r2=231151&pathrev=231152
   M http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/chrome_browser_main_win.cc?r1=231152&r2=231151&pathrev=231152
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/app/content_main_runner.cc?r1=231152&r2=231151&pathrev=231152
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.cc?r1=231152&r2=231151&pathrev=231152
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/public/common/content_switches.h?r1=231152&r2=231151&pathrev=231152
   M http://src.chromium.org/viewvc/chrome/trunk/src/content/browser/renderer_host/render_process_host_impl.cc?r1=231152&r2=231151&pathrev=231152

Revert 230968 "Use HighResNow whenever possible on Windows."

Speculative revert. Appears to be causing problems on webgl gpu bots
(unsure of root cause), and possible some XP test bots (TimeTicks::Now
non-monotonic).

TBR=awong@chromium.org, kbr@chromium.org, simonjam@chromium.org

BUG= 311646 

> Use HighResNow whenever possible on Windows.
> 
> This has been enabled on Canary channel for sometime now and seems to be
> safe there. We also now have data from stable channel showing there are
> no unexpectedly buggy CPUs out there. This should be safe to turn on for
> all users with adequate CPUs, which is the majority of them.
> 
> BUG= 158234 
> 
> Review URL: https://codereview.chromium.org/41953002

TBR=simonjam@chromium.org

Review URL: https://codereview.chromium.org/45783003
------------------------------------------------------------------------
Blockedon: chromium:312429 chromium:312432
Cc: simonjam@chromium.org
Labels: -M-32
Owner: ----
Status: Available
This was reverted. I've filed bugs for the two problems that were uncovered.
James, think you'll be able to get to this before you head out?
WARNING: I have a laptop that *sometimes* reports an *incorrect* QueryPerformanceFrequency.

I figured this out in an Internet download speed test application that was sometimes producing incorrect results.  After a lot of research and trial and error, I tracked it down to a power plug issue.  When the laptop is plugged in after booting on battery (or unplugging after booting up on power), there was a QPC bug.

After all, who questions QPC numbers that are properly increasing (and who checks to see if they don't match wall clock time by 20%)?  But the QPC timing results were either:

1) 100% accurate (boot power mode matched current power mode)
2) 20% underestimate (running on battery after booting on power)
3) 25% overestimate (running on power after booting on battery)

You 'should' implement a sanity check on QPC returned values -- that they 'match' wall clock results.  Here is the pseudocode (hopefully you get the idea) for what I used:

returnQPC
  qpcNow = getQPC()
  qpcDelta = qpcNow-qpcLastCheck
  if (qpcDelta > 1 second)
    qpcLastCheck = qpcNow
    doSanityCheck    
  return qpcNow

doSanityCheck
  wallNow = getWallClockTime()
  if (abs((wallNow-wallLast)-qpcDelta)>34ms)
    if (--warpsInRow<0)
      QPC is in time warp and NOT ACCURATE, no longer user QPC
    else
      do nothing, assume wall clock adjusted to network time
  else
    warpsInRow = 5;
  wallLast = wallNow;

Cc: fmea...@chromium.org
Nope, not gonna happen from me. We need to fix two blocking bugs first. I think Fadi volunteered over e-mail.

Jerry, it'd help a lot if we knew your CPUID. We have a small blacklist of known bad ones where we fall back to normal resolution. I'd be curious if yours is already on there or if we need to add more.

Comment 55 Deleted

"Intel(R) Pentium(R) 4 CPU 3.20 GHz"
That one is not in our blacklist, I will check if it needs to be added to be added to the list.
Blocking: chromium:319630

Comment 59 by rschoen@google.com, Nov 28 2013

Fadi, are you indeed taking this on? What about the blockers?
Cc: -fmea...@chromium.org
Owner: fmea...@chromium.org
Yes, as well as the blockers but I will not be working on it for a few weeks. Help is appreciated.
FWIW, I don't think it's necessarily a huge problem to do continuous self-recalibration (self-check for monotonically upticking, and re-calibrate/compensate whenever something seems wrong).  System performance varies anyway (e.g. SpeedStep) so the number of operations done per clock ticks always varies, so occasional erratic upticking is far less evil than a downwards tick; it just 'looks' like a momentary system pause or system speedup that can easily be caused by other causes (e.g. SpeedStep or background processes)

I argue that this is a reasonable fix that would unblock a lot of things.  Even if all the blockers are fixed, what's not to say a cosmic ray might cause an unwanted backtick?  I think it is okay to just add a backtick check, and a block of reasonable compensate/recalibrate code whenever backticks (or sudden surges) are detected.
+1 -- having infrequent and slightly incorrect high precision times is way
better than having no high precision times at all.
Yes, my above suggestion of multiplexing multiple timers (a high-precision timer and a low-precision timer) by using the low-precision timer as a backup to malfunctions in the high-precision timer:

- My suggestion is theoretically OS independent 
- My suggestion eliminates the need for a blacklist.
- My suggestion guarantees coverage of unforseen issues (e.g. cosmic rays, RFI, undervoltage, laptop power management switches, future operating system bugs, etc) 
- My suggestion eliminates the need to fix  Issue 95738 , Issue 312429,  Issue 312432  first
- For more than a year, Google is now the ONLY browser of big five without high-precision time.
- My suggestion is easier.
- My suggestion is more stable.
- My suggestion is more testable.
- My suggestion is an easy sell to your boss/manager at Google.
image-graph-of-performance-now-IEvsFFvsCHROME.png
114 KB View Download
There are two issues with the high-res timestamp on Windows:

1) Sometimes it's not monotonic. Chrome's multi-process architecture gets in the way of easy workarounds here. In a single process application, it is more straightforward to adjust the timestamp in the ways that @blurbusters has suggested in #61. However, Chrome needs to compare timestamps across processes and any workarounds would need to coordinate all processes to synchronize their decisions.

2) On some systems, taking a high-res timestamp has so much overhead that Chrome slows down by more than 10% in some use cases. This is a huge blocker for which we need a good heuristic so we can avoid that hit in performance.

Instead of trying to use high-res timestamps everywhere, maybe we can make quicker forward progress by just trying to enable high-res timestamps for window.performance.now and related code? (See  issue 315334  for related work.)

Web apps shouldn't have to compare timestamps across processes, which helps us avoid the first issue for now. We might be able to avoid the second issue if the performance hit has been from enabling high-res timestamps in other parts of Chrome's code base.
Hmm, good points.

Yes, it is reasonable to split out performance.now() separately of all the low-resolution (millisecond) timers.  Initially, since applications that intentionally call it, is wanting high-precision time, and it will likely be called only at select times (e.g. at the start and end of an animation frame, or to benchmark a task).

You might need to wrapper it in a sanity check so that performance.now() stays in reasonable sync with the low-resolution timer, so you don't run into instances where simultaneous JavaScript reads of the low-resolution (e.g. Date.getMilliseconds()) and high-resolution timers (e.g. performance.now()) don't diverge by more than a +/- 1 millisecond error.   You wouldn't want to get a 998 millisecond difference in consecutive Date.getMillisecond() 1-seconds-apart, while getting 1002 milliseconds in consecutive performance() called 1-seconds apart.  You could simply use the low-resolution timer as a rangecheck for the high resolution timer (if deviations exceeds 1 millisecond, switch to using the low resolution timer).

Then you've pretty much unblocked performance.now().  You can keep timer accuracy on a per-process basis, rather keeping timer accuracy on a global basis, simplifying things greatly.   Javascipt don't have access to other browser processes, so this is a nonissue.   

You could even keep using a global low-resolution timer, while having a per-process high resolution timer reads for when JavaScript does a performance.now() -- it would not even matter if a different tab's JavaScript performance.now() diverges from another window's JavaScript performance.now() by a few microseconds -- as they would not interfere with each other -- you just range-check the high resolution timer to make sure it keeps monotonically upticking and stays in sync (within a millisecond) of the low resolution timer.
>>"You could simply use the low-resolution timer as a rangecheck for the high resolution timer (if deviations exceeds 1 millisecond, switch to using the low resolution timer)."

Or whatever self-recalibration is done (e.g. letting the low-resolution timer push around the high-resolution timer value around, in order to keep both values in lockstep of each other less than +/- 1ms).
Labels: Cr-Blink-Performance-APIs

Comment 68 Deleted

It seems that somebody is doing work in Chrome 33 Canary to achieve submillisecond precision.  It's frequently switching between millisecond precision and submillisecond precision, but this is a big improvement (even for the millisecond precision graph).

Here's 4 graphs:
Scale 10ms, ultra high precision (this occurs if you wait 5 seconds with no other windows open)
Scale 10ms, low precision (this occurs after a delay such as a stutter, like clicking-and-holding the title bar for a moment)

And because the graph was flatter than expected, I had to stretch the scale to make fluctuations more visible:
Scale 2ms, ultra high precision (this occurs if you wait 5 seconds with no other windows open).
Scale 2ms, low precision (this occurs after a delay such as a stutter, like clicking-and-holding the title bar for a moment)

The first graph (scale 10ms, ultra precision) is the flattest I've ever seen; better than IE and FireFox.  Chrome 33 is easily achieving 100 microsecond precision now.  But it seems to scurry very quickly back to millisecond precision, maybe it's using too-aggressive thresholds to switch back to the low precision timer from the high precision timer, whenever an externally-enforced stutter occurs such as clicking-and-holding the window title bar.  I wonder if the high precision / low precision reads needs to occur simultaneously, in a critical section together (preferably with the less expensive read occuring first, e.g. milliseconds precision read followed by microsecond precision read).  That might prevent false alarms for fallback triggers.  If you're verifying the high precision timer with the low precision timer, I'd suggest perhaps maybe a +/- 1ms window (2ms range) instead of +/- 0.5ms window (1ms range).   This might prevent the frequent precision-switching behaviour I'm seeing.

Good job though.  Even the worst-case graph of Chrome 33 is superior to to any of the Chrome 32 graphs I've ever seen.
chrome_scale10ms_lowprecision.png
66.5 KB View Download
chrome_scale2ms_lowprecision.png
82.3 KB View Download
chrome_scale2ms_ultra.png
67.8 KB View Download
chrome_scale10ms_ultra.png
66.1 KB View Download
The above were 4 comparision graphs specifically for Chrome 33.

Now these attached are comparision of Chrome 32 versus Chrome 33.  Observe how Chrome 33's timer performance.now() worst-case accuracy is superior to Chrome 32 best-case accuracy (even if it fluctuates).  So even though there's the new precision-switching behavior occuring in Chrome 33, it's encouraging to finally see microsecond-league precision in Chrome 33 JavaScript performance.now().
chrome_scale2ms_Chrome33_LowPrecisionCase.png
82.3 KB View Download
chrome_scale2ms_Chrome33_HighPrecisionCase.png
67.8 KB View Download
chrome_scale2ms_Chrome32_BestCase.png
92.2 KB View Download
Possibly, what it seems is that there's probably multiple levels of accuracy that are "interfering" with each other.  That is, perhaps the performance.now() is always microsecond accuracy but that the accuracy of the timing of calls to requestAnimationFrame() is varying between millisecond-precision and microsecond-precision, depending on the mode/state the browser is in.

It's not easy to make it switch gears, but I noticed refreshing the page often works, and sometimes clicking outside the window then clicking the graph. Here's an example of accuracy switching from millisecond precision to microsecond precision.  Even the millisecond precision (which seems to have microsecond-precision elements not found in Chrome 32). looks better than FireFox's and Chrome 32's.
chrome_scale10ms_AccuracySwitchingGears.png
64.3 KB View Download
The latest Canary (33.0.1735.0) appears to implement a performance.now() that is capped/limited to microsecond accuracy, even though it could be more accurate than that.  

Why is that?

From reading the W3C performance working group Teleconference notes, it is stated that 'microsecond' is the "minimum resolution" that performance.now should provide/return (note: it does not say microsecond is the maximum resolution).

I arrive at this conclusion by looping for an entire second in Canary, examining values returned by performance.now(), and keeping track of the minimum (non-zero) difference between two consecutive values.  The minimum I obtain is 0.0009999930625781417ms.  In particular, I call performance.now() 3,517,730 times in one second and find that only 982,403 of the returned values represent a different value.

Comment 73 Deleted

QueryPerformanceCounter() can tick more than a million times a second, so theoretically this doesn't have to be the minimum. I presume by RFC2119 normative standard, "SHOULD" is just a recommendation rather than a "MUST".  I imagine that different web browsers don't enforce milliseconds as a minimum possible timer resolution?

Since it's a floating point value, it seems silly to trunctate the precision, even though real-world precision is usually far less than this.  This is just a minor point to me, but it's noteworthy that the precision trunctation "isn't absolutely required".  

On my system, I'm able to read performance.now() several million times per second too, so microseconds may not be the final frontier for tomorrow's browsers.  To put this in perspective, 20 years ago, who would have though we've achieved microsecond timer accuracies in a browser-driven interpeted script language?  We've achieved necessary accuracies for refresh-rate-synchronized (VSYNC ON) motion at 240fps@240Hz. (I had a tester test www.testufo.com on a custom-modified true 1920x1080 240Hz monitor; and it worked with full refresh-rate-synchronized animations).
OK, found the reason in the Chromium source code -- it first converts QPF/QPC numbers to a microsecond (integer) result, and then converts that integer value to a JavaScript double.  Bottom line: computed fractional microseconds are discarded.

Also interesting to see the crazy way in which rollover_ms is manually kept track of, when there is an automatic way to do that.
Tons of interesting information on the subject: http://www.windowstimestamp.com/description
Fadi, have you been able to make any progress here?
I have started tackling one of the 2 issues blocking enabling the HiRes time on windows, performance on winXP. I have a try job that I am currently running on a win7 bot since our winXP try bot is down at the moment. I am following on that bug, once the bot is back up I will have new numbers for the winXP page_cyclers. Hopefully I will have a reproducible regression I can analyze and tackle.
Was it a design decision (or an accident) to intentionally exclude Windows QPC/QPF from being used when *no* RDTSC is even being used?  There are signature QPF values that indicate usage of PIT/ACPI.
I am still getting mysterious precision-switching behavior.


I am still getting mysterious precision-switching behavior in Canary 34.0.1772.0 with http://www.testufo.com/animation-time-graph#scale=1 I'm not sure what the cause is.

Even the low precision state is still fairly precise, compared to previous Chrome releases.  But it would be nice to know why the precision-switching behavior is happening.
chrome34-canary-1772.png
105 KB View Download
Regarding problems under winXP:  Look into Chrome's test for using the high-res timer (non-stop TSC and not AMD) returning true, and then calling and using QPC -- but that QPC is not using TSC.
Blockedon: chromium:330900
Cc: nsthorat@google.com
Fadi, I know you're just getting back, but any updates? The bisect bot is now up again.
Ping on this.
I made some analysis on the different performance issues resulting from switching to a higher resolution timer, I will publish them soon.

Concerning the non-supported platforms, the easiest way we found, is to attempt to dynamically bind the QPC call, if the bind fails, fallback to low-res timers. 
Cc: fmea...@chromium.org
Owner: ----
The analysis (Google Internal Doc):
https://docs.google.com/a/google.com/document/d/11BJTe1hNqfMyrYpHdKg3zvYjcB9jzoLx5MgvFyGHTL8/edit#

Comment 89 by hclam@chromium.org, Jun 23 2014

Cc: hclam@chromium.org

Comment 90 by hclam@chromium.org, Jun 23 2014

Cc: m...@chromium.org hubbe@chromium.org mfo...@chromium.org
Labels: Cr-Internals-Cast
+cast people who have strong interest in getting high res timer in Chrome.
In Chrome 35.0.1916.153m under Windows 6.1.7601, performance.now() only seems to return values like this:

7035.0000000034925
64502.00000000768
64652.00000000186
65252.00000000768

Never fewer than eight zeros. Call me a sceptic, but I doubt that this is really femtosecond precision, and doubt even more that I happen to call the method a few picoseconds after the nearest millisecond each time.
Blocking: chromium:397208
Any more progress on this?
Owner: fmea...@chromium.org
Status: Started
Working on a CL that makes QPC less expensive, also will try to re-enable QPC on windows by default this week.
Project Member

Comment 95 by bugdroid1@chromium.org, Aug 1 2014

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/45b918c9aa9aba9f3743312f182ecde3906078a0

commit 45b918c9aa9aba9f3743312f182ecde3906078a0
Author: fmeawad@chromium.org <fmeawad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Fri Aug 01 01:01:42 2014

Use HighResNow whenever possible on Windows.

Relanding simonjam@'s CL https://codereview.chromium.org/41953002/ to enable QPC.

This may result in perf changes, the perf changes may only be in the measurements and not actual regressions.

BUG= 158234 

Review URL: https://codereview.chromium.org/429053002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@286928 0039d316-1c4b-4281-b951-d872f2087c98


Project Member

Comment 97 by bugdroid1@chromium.org, Aug 6 2014

------------------------------------------------------------------
r287704 | fmeawad@chromium.org | 2014-08-06T06:21:18.585545Z

Changed paths:
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time.h?r1=287704&r2=287703&pathrev=287704
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time_win_unittest.cc?r1=287704&r2=287703&pathrev=287704
   M http://src.chromium.org/viewvc/chrome/trunk/src/base/time/time_win.cc?r1=287704&r2=287703&pathrev=287704

Make QPCValueToMicroseconds faster in case the value is less than 44 bits

If the QPC value is less than 44 bits, it is safe to multiply by a 20 bits
value (1000000) without risking overflow. This optimization reduces the
call time by half.

BUG= 158234 

Review URL: https://codereview.chromium.org/429743002
-----------------------------------------------------------------
Project Member

Comment 98 by bugdroid1@chromium.org, Aug 6 2014

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/3687b2f8321ad2ddfc0dfbf51547fbdcc53491ad

commit 3687b2f8321ad2ddfc0dfbf51547fbdcc53491ad
Author: fmeawad@chromium.org <fmeawad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Wed Aug 06 06:21:18 2014

Make QPCValueToMicroseconds faster in case the value is less than 44 bits

If the QPC value is less than 44 bits, it is safe to multiply by a 20 bits
value (1000000) without risking overflow. This optimization reduces the
call time by half.

BUG= 158234 

Review URL: https://codereview.chromium.org/429743002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287704 0039d316-1c4b-4281-b951-d872f2087c98


Fadi, is there more work to be done here?
There is a pending CL under review https://codereview.chromium.org/446203002/ that eliminates a measurement error. Waiting for it to land and stabilize before closing the issue.
Project Member

Comment 101 by bugdroid1@chromium.org, Aug 26 2014

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/05399593156ef3b8d96933258cd32fe716f63461

commit 05399593156ef3b8d96933258cd32fe716f63461
Author: fmeawad <fmeawad@chromium.org>
Date: Tue Aug 26 20:10:45 2014

We have noticed a clock shift when QPC was deployed. It shows as a regression on the perf bots
https://chromeperf.appspot.com/report?masters=ChromiumPerf&bots=chromium-rel-win8-dual&tests=startup.warm.dirty.blank_page%2Fwindow_display_time&rev=286928

It is not a real regression, the initial_time and initial_ticks are not properly initialized when switching to HighResolution (i.e. QPC).
This CL initializes the now_function to the HighResNowWrapper instead of setting it to RolloverProtectedNow then to the HighResNowWrapper.

By doing that, we avoid getting an incorrect initial_time and initial_ticks using the RolloverProtectedNow and avoid having to reinitialize.

BUG= 158234 

Review URL: https://codereview.chromium.org/446203002

Cr-Commit-Position: refs/heads/master@{#291974}

[modify] https://chromium.googlesource.com/chromium/src.git/+/05399593156ef3b8d96933258cd32fe716f63461/base/test/test_suite.cc
[modify] https://chromium.googlesource.com/chromium/src.git/+/05399593156ef3b8d96933258cd32fe716f63461/base/time/time.h
[modify] https://chromium.googlesource.com/chromium/src.git/+/05399593156ef3b8d96933258cd32fe716f63461/base/time/time_win.cc
[modify] https://chromium.googlesource.com/chromium/src.git/+/05399593156ef3b8d96933258cd32fe716f63461/chrome/browser/chrome_browser_main_win.cc
[modify] https://chromium.googlesource.com/chromium/src.git/+/05399593156ef3b8d96933258cd32fe716f63461/content/app/content_main_runner.cc

Project Member

Comment 102 by bugdroid1@chromium.org, Aug 28 2014

The following revision refers to this bug:
  https://chromium.googlesource.com/chromium/src.git/+/3a38fb5efd526a2278ab3b577c8c7881a3ad4d20

commit 3a38fb5efd526a2278ab3b577c8c7881a3ad4d20
Author: fmeawad <fmeawad@chromium.org>
Date: Thu Aug 28 00:48:16 2014

Revert of Initialize the now_funciton to the HighResNowWrapper in case High Res is supported (patchset #7 of https://codereview.chromium.org/446203002/)

Reason for revert:
It causes a Canary crash

https://code.google.com/p/chromium/issues/detail?id=408354

The added static initializer causes a crash in libpeerconnetion used by WebRTC

Fix to reland: remove static initializer.

Original issue's description:
> We have noticed a clock shift when QPC was deployed. It shows as a regression on the perf bots
> https://chromeperf.appspot.com/report?masters=ChromiumPerf&bots=chromium-rel-win8-dual&tests=startup.warm.dirty.blank_page%2Fwindow_display_time&rev=286928
>
> It is not a real regression, the initial_time and initial_ticks are not properly initialized when switching to HighResolution (i.e. QPC).
> This CL initializes the now_function to the HighResNowWrapper instead of setting it to RolloverProtectedNow then to the HighResNowWrapper.
>
> By doing that, we avoid getting an incorrect initial_time and initial_ticks using the RolloverProtectedNow and avoid having to reinitialize.
>
> BUG= 158234 
>
> Committed: https://chromium.googlesource.com/chromium/src/+/10c40c221c314e41add0a5b4df1ee7467681a430

TBR=jar@chromium.org,willchan@chromium.org,maruel@chromium.org,thakis@chromium.org,jam@chromium.org,cpu@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG= 158234 

Review URL: https://codereview.chromium.org/516693002

Cr-Commit-Position: refs/heads/master@{#292288}

[modify] https://chromium.googlesource.com/chromium/src.git/+/3a38fb5efd526a2278ab3b577c8c7881a3ad4d20/base/test/test_suite.cc
[modify] https://chromium.googlesource.com/chromium/src.git/+/3a38fb5efd526a2278ab3b577c8c7881a3ad4d20/base/time/time.h
[modify] https://chromium.googlesource.com/chromium/src.git/+/3a38fb5efd526a2278ab3b577c8c7881a3ad4d20/base/time/time_win.cc
[modify] https://chromium.googlesource.com/chromium/src.git/+/3a38fb5efd526a2278ab3b577c8c7881a3ad4d20/chrome/browser/chrome_browser_main_win.cc
[modify] https://chromium.googlesource.com/chromium/src.git/+/3a38fb5efd526a2278ab3b577c8c7881a3ad4d20/content/app/content_main_runner.cc

Blockedon: chromium:400627
Fixed?
I would call it fixed, High Res will be enabled on all channels in M38. Feel free to reopen in case of regression.
Status: Fixed
The cause of Chrome "frequently switching between millisecond precision and submillisecond precision" for inter-frame animation timings (found by blurbust above) is due to Chrome entering "high latency mode" (at the drop of a hat for no good reason) -- documented in new issue 465105.

Comment 108 Deleted

Labels: -Cr-Blink-Performance-APIs Cr-Blink-PermissionsAPI
Manually move Cr-Blink-Performance-APIs to Cr-Blink-PermissionsAPI
Just adding this note to document the fact that window.performance.now() resolution in Chome used to be 1 microsecond, but starting with 45.0.2450.0 (r337541), the resolution is intentionally being truncated/clamped to 5 microseconds:

  https://chromium.googlesource.com/chromium/blink/+/34c7884f58ae24b174179e1e9aec29c96e3c8d21
Cc: ksakamoto@chromium.org
That's a pretty nasty change, and quite devastating for those attempting to profile code.

ksakamoto: can a flag be added to preserve the old behavior (reusing --disable-web-security, etc)? We need microsecond-accurate timing.
This still appears to be a problem. I don't know when it started failing again. Windows 10 x64, Chrome Version 50.0.2661.102 m

Running this code:

var old = 0; 

for (var i=0; i<1000; i++) {
    var t = window.performance.now(); 
    var d = t - old; 
    old = t; 
    console.log(t + ' += ' +d); 
}

On Chrome returns results that are almost entirely consistently: 0, 1, or extremely close to those values (0.9950000000000045, 1.004999999999967, etc)

On Firefox, returns results that are almost entirely unique:

1626.6200000000001 += 0.21000000000003638 dynamic.header.js:7:5
1626.815 += 0.19499999999993634 dynamic.header.js:7:5
1627.075 += 0.2599999999999909 dynamic.header.js:7:5
1627.405 += 0.32999999999992724 dynamic.header.js:7:5
1627.69 += 0.28500000000008185 dynamic.header.js:7:5
1627.9850000000001 += 0.29500000000007276 dynamic.header.js:7:5
1628.24 += 0.25499999999988177 dynamic.header.js:7:5
1628.47 += 0.2300000000000182 dynamic.header.js:7:5
1628.67 += 0.20000000000004547 dynamic.header.js:7:5
1628.88 += 0.21000000000003638 dynamic.header.js:7:5
1629.095 += 0.21499999999991815 dynamic.header.js:7:5
1629.3 += 0.20499999999992724 dynamic.header.js:7:5

Comment 113 by ise...@gmail.com, May 29 2016

@ksakamoto: You don't reduce timer resolution to prevent timing attacks, you fix them at their source (by doing NOPs and other random stuff to normalize execution time). All reducing the resolution does is reduce the accuracy, meaning you can still run the test for longer to achieve the same accuracy.

I maintain a navigator.hardwareConcurrency polyfill that uses a timing attack. Your change doesn't stop it from working, it just makes it waste the user's CPU cycles for even longer. This change only serves to hurt timing attack victims *more*.

@benvanik: It shouldn't even be behind a flag, it should be the default behavior. We shouldn't be reducing the timer resolution in Chrome just because other parts of it aren't hardened against timing attacks. We need to address the issue at its core.
Showing comments 14 - 113 of 113 Older

Sign in to add a comment