Last Comment Bug 784859 - Make the Windows TimeStamp implementation faster
: Make the Windows TimeStamp implementation faster
Status: RESOLVED FIXED
:
Product: Core
Classification: Components
Component: XPCOM (show other bugs)
: Trunk
: x86 Mac OS X
-- normal with 1 vote (vote)
: mozilla18
Assigned To: :Ehsan Akhgari (needinfo please, extremely long backlog)
:
: Nathan Froyd [:froydnj]
Mentors:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-08-22 16:36 PDT by :Ehsan Akhgari (needinfo please, extremely long backlog)
Modified: 2012-11-20 05:33 PST (History)
15 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC (2.39 KB, patch)
2012-08-22 16:37 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter (3.12 KB, patch)
2012-08-22 16:43 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 3: Refactor TickCount64 to make its signature similar to GetTickCount64 (2.29 KB, patch)
2012-08-22 16:43 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 4: Use the native GetTickCount64 function where available (4.89 KB, patch)
2012-08-22 16:44 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks (2.59 KB, patch)
2012-08-22 16:44 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 6: Remove the need for locking in all calls to TimeStamp::Now (7.37 KB, patch)
2012-08-22 16:45 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC (2.39 KB, patch)
2012-08-23 17:08 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review-
Details | Diff | Splinter Review
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter (4.95 KB, patch)
2012-08-23 17:09 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review-
Details | Diff | Splinter Review
Part 3: Refactor TickCount64 to make its signature similar to GetTickCount64 (2.32 KB, patch)
2012-08-23 17:09 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review+
Details | Diff | Splinter Review
Part 4: Use the native GetTickCount64 function where available (4.81 KB, patch)
2012-08-23 17:10 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review+
Details | Diff | Splinter Review
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks (2.70 KB, patch)
2012-08-23 17:10 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
no flags Details | Diff | Splinter Review
Part 6: Remove the need for locking in all calls to TimeStamp::Now (7.46 KB, patch)
2012-08-23 17:11 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review+
Details | Diff | Splinter Review
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC (2.46 KB, patch)
2012-09-07 14:17 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review+
Details | Diff | Splinter Review
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter (5.15 KB, patch)
2012-09-07 14:19 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review+
Details | Diff | Splinter Review
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks (2.77 KB, patch)
2012-09-07 14:22 PDT, :Ehsan Akhgari (needinfo please, extremely long backlog)
netzen: review+
Details | Diff | Splinter Review

Description User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:36:34 PDT
I and Jeff spent some time today to improve our Windows TimeStamp implementation.  Here is the major changes that we have implemented:

* Use QueryPerformanceCounter directly if the machine has a stable TSC
* Use GetTickCount64 if the platform supports it, and have a fallback for Windows XP which simulates it by calling GetTickCount.
* Avoid locking in almost all calls to TimeStamp::Now for machines without a stable TSC by doing atomic operations.

I'll attach the patches here, and I'll ask Honza for review since he wrote the original code.
Comment 1 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:37:20 PDT
Created attachment 654420 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC
Comment 2 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:43:32 PDT
Created attachment 654421 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter
Comment 3 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:43:51 PDT
Created attachment 654422 [details] [diff] [review]
Part 3: Refactor TickCount64 to make its signature similar to GetTickCount64
Comment 4 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:44:12 PDT
Created attachment 654423 [details] [diff] [review]
Part 4: Use the native GetTickCount64 function where available
Comment 5 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:44:39 PDT
Created attachment 654424 [details] [diff] [review]
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks
Comment 6 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-22 16:45:03 PDT
Created attachment 654425 [details] [diff] [review]
Part 6: Remove the need for locking in all calls to TimeStamp::Now
Comment 7 User image Jeff Muizelaar [:jrmuizel] 2012-08-23 08:03:07 PDT
Comment on attachment 654421 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter

Review of attachment 654421 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +517,5 @@
> +  do {
> +    readValue = InterlockedAdd64(destination, 0);
> +    if (readValue > newValue)
> +      return readValue;
> +  } while (readValue != InterlockedCompareExchange64(destination, newValue, readValue));

This will need something like:

+inline LONGLONG _cdecl 
+MozInterlockedCompareExchange64(LONGLONG volatile *Destination,
+                                LONGLONG Exchange,
+                                LONGLONG Comparand)
+{
+  __asm {
+    lea esi,[Comparand]
+    lea edi,[Exchange]
+    mov eax,[esi]
+    mov edx,[esi+4]
+    mov ebx,[edi]
+    mov ecx,[edi+4]
+    mov esi,[Destination]
+    lock cmpxchg8b [esi]
+  }
+}
+
+inline LONGLONG _cdecl 
+MozInterlockedGet64(LONGLONG volatile *Source)
+{
+  __asm {
+    xor eax,eax
+    xor edx,edx
+    xor ebx,ebx
+    xor ecx,ecx
+    mov esi,[Source]
+    lock cmpxchg8b [esi]
+  }
+}
+

to work on XP which doesn't have InterlockedCompareExchange64.

InterlockedAdd64 is only supported on Itanium
Comment 8 User image Jeff Muizelaar [:jrmuizel] 2012-08-23 08:09:32 PDT
(In reply to Jeff Muizelaar [:jrmuizel] from comment #7)
> Comment on attachment 654421 [details] [diff] [review]
> Part 2: Avoid locking to store the computed result in the global variable in
> CalibratedPerformanceCounter
> 
> Review of attachment 654421 [details] [diff] [review]:
> -----------------------------------------------------------------
> +
> 
> to work on XP which doesn't have InterlockedCompareExchange64.
> 
> InterlockedAdd64 is only supported on Itanium

We might also be able to use __InterlockedCompareExchange64
Comment 9 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-23 17:08:37 PDT
Created attachment 654857 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC

This version of the patches actually compiles!  And it's improved much.
Comment 10 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-23 17:09:30 PDT
Created attachment 654858 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter
Comment 11 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-23 17:09:51 PDT
Created attachment 654859 [details] [diff] [review]
Part 3: Refactor TickCount64 to make its signature similar to GetTickCount64
Comment 12 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-23 17:10:12 PDT
Created attachment 654860 [details] [diff] [review]
Part 4: Use the native GetTickCount64 function where available
Comment 13 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-23 17:10:39 PDT
Created attachment 654861 [details] [diff] [review]
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks
Comment 14 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-08-23 17:11:00 PDT
Created attachment 654862 [details] [diff] [review]
Part 6: Remove the need for locking in all calls to TimeStamp::Now
Comment 15 User image Trev 2012-08-23 18:58:10 PDT
Would this also fix bug 603872?
Comment 16 User image Jeff Muizelaar [:jrmuizel] 2012-08-23 19:15:58 PDT
(In reply to Trev from comment #15)
> Would this also fix bug 603872?

No. Date() does not use TimeStamp::Now()
Comment 17 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-09-06 08:03:13 PDT
Comment on attachment 654857 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC

Brian, could you please take a stab at reviewing these patches?  The code in question is fairly localized, and relatively easy to understand.  :-)
Comment 18 User image Brian R. Bondy [:bbondy] 2012-09-07 05:35:47 PDT
Comment on attachment 654857 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC

Review of attachment 654857 [details] [diff] [review]:
-----------------------------------------------------------------

As far as I understand QueryPerformanceCounter is a safe API that uses the time stamp counter register only when it's safe. 
Otherwise it provides a safe and fast alternative.  I don't understand why it would be gated on the same conditions as the TSC.
Using the TSC register directly would be faster than using QueryPerformanceCounter if it was safe.

See here: http://msdn.microsoft.com/en-us/library/ee417693%28VS.85%29.aspx

I suspect I'm missing some known information though.
Comment 19 User image Jeff Muizelaar [:jrmuizel] 2012-09-07 07:31:54 PDT
(In reply to Brian R. Bondy [:bbondy] from comment #18)
> Comment on attachment 654857 [details] [diff] [review]
> Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC
> 
> Review of attachment 654857 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> As far as I understand QueryPerformanceCounter is a safe API that uses the
> time stamp counter register only when it's safe. 
> Otherwise it provides a safe and fast alternative.  I don't understand why
> it would be gated on the same conditions as the TSC.
> Using the TSC register directly would be faster than using
> QueryPerformanceCounter if it was safe.
> 
> See here: http://msdn.microsoft.com/en-us/library/ee417693%28VS.85%29.aspx
> 
> I suspect I'm missing some known information though.

The problem is that QueryPerformanceCounter isn't always safe. So we need to know when it's actually safe to use.
Comment 20 User image Brian R. Bondy [:bbondy] 2012-09-07 07:59:13 PDT
> The problem is that QueryPerformanceCounter isn't always safe. 
> So we need to know when it's actually safe to use.

In comment 18 I'm really asking for a resource that can explain exactly why it's not safe.  I suspect there is some documentation we're going off of, I just don't know where to find it.

The first patch seems to assume that QueryPerformanceCounter and TSC is the same thing, when it's not. 
And if we know TSC is safe, why use QueryPerformanceCounter at all?

The only remarks about QueryPerformanceCounter on its MSDN page about a problem with it is:
> On a multiprocessor computer, it should not matter which processor is called. 
> However, you can get different results on different processors due to bugs in the 
> basic input/output system (BIOS) or the hardware abstraction layer (HAL)

Which may not be an actual be a show stopper for using it.

The other page I mentioned above in Comment 18 states problems with TSC and recommends to use QueryPerformanceCounter instead.
Comment 21 User image Brian R. Bondy [:bbondy] 2012-09-07 08:13:27 PDT
The reason I'm asking for the reason QueryPerformanceCounter (QPC) is broken by the way, is because I'm being asked to review a patch that may not be using the correct heuristic for checking if QPC works or not.
Comment 22 User image Brian R. Bondy [:bbondy] 2012-09-07 08:59:35 PDT
Comment on attachment 654857 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC

Review of attachment 654857 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +38,5 @@
> +
> +  __cpuid(regs, 0x80000007);
> +  // if bit 8 is set than TSC will run at a constant rate
> +  // in all ACPI P-state, C-states and T-states
> +  return regs[4] & (1 << 8);

regs[4] is out of bounds!
Comment 23 User image Brian R. Bondy [:bbondy] 2012-09-07 09:34:39 PDT
Comment on attachment 654858 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter

Review of attachment 654858 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +39,5 @@
> +
> +  __cpuid(cpuInfo.regs, 0);
> +  // Only allow Intel CPUs for now
> +  if (memcmp(cpuInfo.cpuString, "GenuineIntel", sizeof(cpuInfo.cpuString)))
> +    return false;

This needs to be a case insensitive compare, my CPU returns genuineintel for these 8 bytes.
Comment 24 User image Brian R. Bondy [:bbondy] 2012-09-07 09:35:05 PDT
*12 bytes
Comment 25 User image Brian R. Bondy [:bbondy] 2012-09-07 09:40:46 PDT
Comment on attachment 654859 [details] [diff] [review]
Part 3: Refactor TickCount64 to make its signature similar to GetTickCount64

Review of attachment 654859 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +397,5 @@
>  // @param gtc
>  // Result of GetTickCount().  Passing it as an arg lets us call it out
>  // of the common mutex.
>  static inline ULONGLONG
> +TickCount64()

While we're here, maybe we should just use GetTickCount64 when it's available? (Vista and later)
Comment 26 User image Brian R. Bondy [:bbondy] 2012-09-07 09:42:38 PDT
Comment on attachment 654860 [details] [diff] [review]
Part 4: Use the native GetTickCount64 function where available

Review of attachment 654860 [details] [diff] [review]:
-----------------------------------------------------------------

Awesome! Ignore last comment.
Comment 27 User image Brian R. Bondy [:bbondy] 2012-09-07 12:24:37 PDT
Comment on attachment 654861 [details] [diff] [review]
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks

Review of attachment 654861 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +413,5 @@
> +        newValue = (oldTop + (1ULL<<32)) | newBottom;
> +    } else {
> +        newValue = oldTop | newBottom;
> +    }
> +  } while (old != _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*> (sLastGTCResult),

Use &sLastGTCResult here not sLastGTCResult, otherwise it looks good. r=me with that.
Comment 28 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-09-07 14:17:34 PDT
Created attachment 659358 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC

(In reply to Brian R. Bondy [:bbondy] from comment #22)
> Comment on attachment 654857 [details] [diff] [review]
> Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC
> 
> Review of attachment 654857 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: xpcom/ds/TimeStamp_windows.cpp
> @@ +38,5 @@
> > +
> > +  __cpuid(regs, 0x80000007);
> > +  // if bit 8 is set than TSC will run at a constant rate
> > +  // in all ACPI P-state, C-states and T-states
> > +  return regs[4] & (1 << 8);
> 
> regs[4] is out of bounds!

Oops :D
Comment 29 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-09-07 14:19:06 PDT
Created attachment 659359 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter

(In reply to Brian R. Bondy [:bbondy] from comment #23)
> Comment on attachment 654858 [details] [diff] [review]
> Part 2: Avoid locking to store the computed result in the global variable in
> CalibratedPerformanceCounter
> 
> Review of attachment 654858 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: xpcom/ds/TimeStamp_windows.cpp
> @@ +39,5 @@
> > +
> > +  __cpuid(cpuInfo.regs, 0);
> > +  // Only allow Intel CPUs for now
> > +  if (memcmp(cpuInfo.cpuString, "GenuineIntel", sizeof(cpuInfo.cpuString)))
> > +    return false;
> 
> This needs to be a case insensitive compare, my CPU returns genuineintel for
> these 8 bytes.

Fixed.  Also, I had the ordering of registers wrong, and I fixed that as well.
Comment 30 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-09-07 14:22:29 PDT
Created attachment 659360 [details] [diff] [review]
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks
Comment 31 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-09-07 14:24:07 PDT
https://tbpl.mozilla.org/?tree=Try&rev=2912dc1aaac3
Comment 32 User image Brian R. Bondy [:bbondy] 2012-09-07 15:50:19 PDT
Comment on attachment 659359 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter

Review of attachment 659359 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +41,5 @@
> +  // Only allow Intel CPUs for now
> +  // The order of the registers is reg[1], reg[3], reg[2].  We just adjust the
> +  // string so that we can compare in one go.
> +  if (_strnicmp(cpuInfo.cpuString, "GenuntelineI", sizeof(cpuInfo.cpuString)))
> +    return false;

Lookeat!s Gr

:)
Comment 34 User image Jeff Muizelaar [:jrmuizel] 2012-09-08 13:01:16 PDT
It would've been nice to get actual performance numbers for this before checking it in.
Comment 36 User image :Ms2ger (⌚ UTC+1/+2) 2012-09-17 04:01:14 PDT
Comment on attachment 659358 [details] [diff] [review]
Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC

Review of attachment 659358 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +33,5 @@
> +
> +  // detect if the Advanced Power Management feature is supported
> +  __cpuid(regs, 0x80000000);
> +  if (regs[0] < 0x80000007)
> +          return false;

This sure is indented strangely.
Comment 37 User image :Ehsan Akhgari (needinfo please, extremely long backlog) 2012-09-17 12:12:16 PDT
Comment on attachment 659359 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter

(In reply to :Ms2ger from comment #36)
> Comment on attachment 659358 [details] [diff] [review]
> Part 1: Use QueryPerformanceCounter directly if the machine has a stable TSC
> 
> Review of attachment 659358 [details] [diff] [review]:
> -----------------------------------------------------------------
> 
> ::: xpcom/ds/TimeStamp_windows.cpp
> @@ +33,5 @@
> > +
> > +  // detect if the Advanced Power Management feature is supported
> > +  __cpuid(regs, 0x80000000);
> > +  if (regs[0] < 0x80000007)
> > +          return false;
> 
> This sure is indented strangely.


>   // detect if the Advanced Power Management feature is supported
>   __cpuid(regs, 0x80000000);
>   if (regs[0] < 0x80000007)
>-          return false;
>+    return false;


:-)
Comment 38 User image Honza Bambas (:mayhemer) 2012-11-20 05:32:47 PST
Comment on attachment 659359 [details] [diff] [review]
Part 2: Avoid locking to store the computed result in the global variable in CalibratedPerformanceCounter

Review of attachment 659359 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +598,2 @@
>  
> +  return AtomicStoreIfGreaterThan(&sLastResult, result);

For original QPC integration and calibration I had a code that was only using Interlock* functions.  It was horribly slow, since Interlock is slow the same way as critical section entering.

Now you have critical section AND interlock, it is imo slower now.

I know lock is later removed at all, but in cost of adding just more Interlocking*...
Comment 39 User image Honza Bambas (:mayhemer) 2012-11-20 05:33:24 PST
Comment on attachment 659360 [details] [diff] [review]
Part 5: Change the implementation of GetTickCount64Fallback so that it never locks

Review of attachment 659360 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +434,2 @@
>  
> +  return newValue;

I had a similar (maybe better ;)) code that was using Interlocks* but that was much much slower then when I had just a single lock.  So I abandoned this approach.

So, IMO this is regressing performance and may also bring some gtc/qpc distance issues that are critical to checking QPC jitter...
Comment 40 User image Honza Bambas (:mayhemer) 2012-11-20 05:33:41 PST
Comment on attachment 654862 [details] [diff] [review]
Part 6: Remove the need for locking in all calls to TimeStamp::Now

Review of attachment 654862 [details] [diff] [review]:
-----------------------------------------------------------------

::: xpcom/ds/TimeStamp_windows.cpp
@@ +199,5 @@
> +    bool fallBackToGTC;
> +    bool forceRecalibrate;
> +  } flags;
> +  uint32_t dwordValue;
> +} sCalibrationFlags;

Why then there aren't just two uint32_t global vars rather?

@@ +507,1 @@
>        RecordFlaw();

RecordFlaw does sCalibrationFlags.flags.fallBackToGTC = true.  That can be turned to 32 bit write that may be freely concurent since we only switch to |true|.

Hence I think you don't need lock here.

@@ +519,2 @@
>  
> +    sCalibrationFlags.flags.forceRecalibrate = false;

Why are you actually locking here?

@@ +574,1 @@
>    LONGLONG diff = qpc - ms2mt(gtc) - sSkew;

Read access to 64bit sSkew is atomic?

Note You need to log in before you can comment on or make changes to this bug.