I logged my first .NET Framework defect with Microsoft Connect last week. After hours of testing and reviewing code with colleagues I reluctantly came to the conclusion that the problem plaguing me was being caused by a defect in the .NET Framework.
Here’s the link to the bug report: https://connect.microsoft.com/VisualStudio/feedback/details/1402528
And the write-up (minus the lengthy code sample to demonstrate the problem)…
I believe that the calculation performed to produce the next value for an ElapsedTime performance counter is incorrect.
The calculation is performed when the System.Diagnostics.PerformanceCounter.NextValue() method is called from System.DLL.
After looking through the reference source at the following address I believe the problem is down to the System.Diagnostics.CounterSampleCalculator.GetElapsedTime method.
It appears to calculate the elapsed time by comparing the time that the new sample was taken with the raw value of the old sample meaning that the polling period between samples is included in the result. This difference is negligible for large values infrequently reset such as system up time but non-negligible for small time periods that are being constantly reset. I came to this conclusion from the following code snippet, taken from the GetElapsedTime method in the reference source:
eDifference = (float)((ulong)newSample.CounterTimeStamp - oldSample.UnsignedRawValue);
I have worked around this by working out what I believe the correct calculated value should be from the raw sample as stated in MSDN for the elapsed time counter type (note that the previous sample is not taken into account to remove the poll period from the equation):
(sample.CounterTimeStamp - (float)sample.RawValue) / sample.CounterFrequency