-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
steady_clock::now() says:
Lines 612 to 614 in a83d8c0
| _NODISCARD static time_point now() noexcept { // get current time | |
| const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot | |
| const long long _Ctr = _Query_perf_counter(); |
Lines 92 to 96 in a83d8c0
| _CRTIMP2_PURE long long __cdecl _Query_perf_frequency() { // get frequency of performance counter | |
| LARGE_INTEGER li; | |
| QueryPerformanceFrequency(&li); // always succeeds | |
| return li.QuadPart; | |
| } |
As the comment indicates, QueryPerformanceFrequency documentation says: "The frequency of the performance counter is fixed at system boot and is consistent across all processors. Therefore, the frequency need only be queried upon application initialization, and the result can be cached."
This code originally used magic statics, but TFS checkin 1586419 on March 16, 2016 removed that. My checkin notes claimed (emphasis added):
Remove intentional but unnecessary use of magic statics in
steady_clock::now()calling_Query_perf_frequency(). Calling QPC is very fast (when I originally profilednow(), IIRC I could call it 6-7 times before the tick changed). Calling QPF will be comparably fast, so we may as well just do that instead of paying the magic statics cost. I've left the "system boot" comment, since it's helpful to know.
I had no evidence for this performance assumption and it was incorrect. In DevCom-505019, where this issue was originally reported, Damian Zwoliński noted that while QPC is indeed efficient on most platforms (aside: IIRC, on certain VMs it is expensive), QPF is not efficient.
We're avoiding magic statics for a reason (its use of Thread Local Storage is problematic for some users), but we should investigate whether it's possible to restore caching without TLS and without breaking ABI. For example, we could have a static long long initialized to 0 (no magic) and use interlocked operations to cache QPF, since 0 is never a valid value for it.