Moving StopWatch to `src\Common\src\Corelib` (dotnet/corefxdotnet/coreclr#42072)
authorVladimir Sadov <vsadov@microsoft.com>
Thu, 24 Oct 2019 12:23:17 +0000 (05:23 -0700)
committerJan Kotas <jkotas@microsoft.com>
Thu, 24 Oct 2019 15:28:09 +0000 (08:28 -0700)
Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
Commit migrated from https://github.com/dotnet/coreclr/commit/b6195fac6c93af4db8caf0cc66b57a90bb82676a

src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Windows.cs [new file with mode: 0644]
src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs [new file with mode: 0644]

diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Unix.cs
new file mode 100644 (file)
index 0000000..13beddd
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics
+{
+    public partial class Stopwatch
+    {
+        private static long QueryPerformanceFrequency()
+        {
+            return (long)Interop.Sys.GetTimestampResolution();
+        }
+
+        private static long QueryPerformanceCounter()
+        {
+            return (long)Interop.Sys.GetTimestamp();
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.Windows.cs
new file mode 100644 (file)
index 0000000..20f5656
--- /dev/null
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics
+{
+    public partial class Stopwatch
+    {
+        private static unsafe long QueryPerformanceFrequency()
+        {
+            long resolution;
+
+            Interop.BOOL result = Interop.Kernel32.QueryPerformanceFrequency(&resolution);
+            // The P/Invoke is documented to never fail on Windows XP or later
+            Debug.Assert(result != Interop.BOOL.FALSE);
+
+            return resolution;
+        }
+
+        private static unsafe long QueryPerformanceCounter()
+        {
+            long timestamp;
+
+            Interop.BOOL result = Interop.Kernel32.QueryPerformanceCounter(&timestamp);
+            // The P/Invoke is documented to never fail on Windows XP or later
+            Debug.Assert(result != Interop.BOOL.FALSE);
+
+            return timestamp;
+        }
+    }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Stopwatch.cs
new file mode 100644 (file)
index 0000000..3b7c0ba
--- /dev/null
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics
+{
+    // This class uses high-resolution performance counter if the installed
+    // hardware supports it. Otherwise, the class will fall back to DateTime
+    // and uses ticks as a measurement.
+
+    public partial class Stopwatch
+    {
+        private const long TicksPerMillisecond = 10000;
+        private const long TicksPerSecond = TicksPerMillisecond * 1000;
+
+        private long _elapsed;
+        private long _startTimeStamp;
+        private bool _isRunning;
+
+        // "Frequency" stores the frequency of the high-resolution performance counter,
+        // if one exists. Otherwise it will store TicksPerSecond.
+        // The frequency cannot change while the system is running,
+        // so we only need to initialize it once.
+        public static readonly long Frequency = QueryPerformanceFrequency();
+        public static readonly bool IsHighResolution = true;
+
+        // performance-counter frequency, in counts per ticks.
+        // This can speed up conversion from high frequency performance-counter
+        // to ticks.
+        private static readonly double s_tickFrequency = (double)TicksPerSecond / Frequency;
+
+        public Stopwatch()
+        {
+            Reset();
+        }
+
+        public void Start()
+        {
+            // Calling start on a running Stopwatch is a no-op.
+            if (!_isRunning)
+            {
+                _startTimeStamp = GetTimestamp();
+                _isRunning = true;
+            }
+        }
+
+        public static Stopwatch StartNew()
+        {
+            Stopwatch s = new Stopwatch();
+            s.Start();
+            return s;
+        }
+
+        public void Stop()
+        {
+            // Calling stop on a stopped Stopwatch is a no-op.
+            if (_isRunning)
+            {
+                long endTimeStamp = GetTimestamp();
+                long elapsedThisPeriod = endTimeStamp - _startTimeStamp;
+                _elapsed += elapsedThisPeriod;
+                _isRunning = false;
+
+                if (_elapsed < 0)
+                {
+                    // When measuring small time periods the Stopwatch.Elapsed*
+                    // properties can return negative values.  This is due to
+                    // bugs in the basic input/output system (BIOS) or the hardware
+                    // abstraction layer (HAL) on machines with variable-speed CPUs
+                    // (e.g. Intel SpeedStep).
+
+                    _elapsed = 0;
+                }
+            }
+        }
+
+        public void Reset()
+        {
+            _elapsed = 0;
+            _isRunning = false;
+            _startTimeStamp = 0;
+        }
+
+        // Convenience method for replacing {sw.Reset(); sw.Start();} with a single sw.Restart()
+        public void Restart()
+        {
+            _elapsed = 0;
+            _startTimeStamp = GetTimestamp();
+            _isRunning = true;
+        }
+
+        public bool IsRunning
+        {
+            get { return _isRunning; }
+        }
+
+        public TimeSpan Elapsed
+        {
+            get { return new TimeSpan(GetElapsedDateTimeTicks()); }
+        }
+
+        public long ElapsedMilliseconds
+        {
+            get { return GetElapsedDateTimeTicks() / TicksPerMillisecond; }
+        }
+
+        public long ElapsedTicks
+        {
+            get { return GetRawElapsedTicks(); }
+        }
+
+        public static long GetTimestamp()
+        {
+            Debug.Assert(IsHighResolution);
+            return QueryPerformanceCounter();
+        }
+
+        // Get the elapsed ticks.
+        private long GetRawElapsedTicks()
+        {
+            long timeElapsed = _elapsed;
+
+            if (_isRunning)
+            {
+                // If the Stopwatch is running, add elapsed time since
+                // the Stopwatch is started last time.
+                long currentTimeStamp = GetTimestamp();
+                long elapsedUntilNow = currentTimeStamp - _startTimeStamp;
+                timeElapsed += elapsedUntilNow;
+            }
+            return timeElapsed;
+        }
+
+        // Get the elapsed ticks.
+        private long GetElapsedDateTimeTicks()
+        {
+            Debug.Assert(IsHighResolution);
+            // convert high resolution perf counter to DateTime ticks
+            return unchecked((long)(GetRawElapsedTicks() * s_tickFrequency));
+        }
+    }
+}