diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index d08c6949616c10..9c363ff74cd570 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.Versioning; using System.Threading; @@ -92,7 +93,7 @@ private void OnEventSourceCommand(object? sender, EventCommandEventArgs e) Debug.Assert((s_counterGroupEnabledList == null && !_eventSource.IsEnabled()) || (_eventSource.IsEnabled() && s_counterGroupEnabledList!.Contains(this)) - || (_pollingIntervalInMilliseconds == 0 && !s_counterGroupEnabledList!.Contains(this)) + || (_pollingInterval == TimeSpan.Zero && !s_counterGroupEnabledList!.Contains(this)) || (!_eventSource.IsEnabled() && !s_counterGroupEnabledList!.Contains(this))); } } @@ -142,22 +143,24 @@ internal static CounterGroup GetCounterGroup(EventSource eventSource) #region Timer Processing - private DateTime _timeStampSinceCollectionStarted; - private int _pollingIntervalInMilliseconds; - private DateTime _nextPollingTimeStamp; + private long _timeStampSinceCollectionStarted; + private TimeSpan _pollingInterval; + private long _nextPollingTimeStamp; private void EnableTimer(float pollingIntervalInSeconds) { Debug.Assert(pollingIntervalInSeconds > 0); Debug.Assert(Monitor.IsEntered(s_counterGroupLock)); - if (_pollingIntervalInMilliseconds == 0 || pollingIntervalInSeconds * 1000 < _pollingIntervalInMilliseconds) + TimeSpan interval = TimeSpan.FromSeconds(pollingIntervalInSeconds); + if (_pollingInterval == TimeSpan.Zero || interval < _pollingInterval) { - _pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000); + _pollingInterval = interval; // Schedule IncrementingPollingCounter reset and synchronously reset other counters HandleCountersReset(); - _timeStampSinceCollectionStarted = DateTime.UtcNow; - _nextPollingTimeStamp = DateTime.UtcNow + new TimeSpan(0, 0, (int)pollingIntervalInSeconds); + long now = Stopwatch.GetTimestamp(); + _timeStampSinceCollectionStarted = now; + _nextPollingTimeStamp = now + _pollingInterval.Ticks * Stopwatch.Frequency / TimeSpan.TicksPerSecond; // Create the polling thread and init all the shared state if needed if (s_pollingThread == null) @@ -186,7 +189,7 @@ private void EnableTimer(float pollingIntervalInSeconds) private void DisableTimer() { Debug.Assert(Monitor.IsEntered(s_counterGroupLock)); - _pollingIntervalInMilliseconds = 0; + _pollingInterval = TimeSpan.Zero; s_counterGroupEnabledList?.Remove(this); if (s_needsResetIncrementingPollingCounters.Count > 0) @@ -225,15 +228,15 @@ private void OnTimer() { if (_eventSource.IsEnabled()) { - DateTime now; + long now; TimeSpan elapsed; - int pollingIntervalInMilliseconds; + TimeSpan pollingInterval; DiagnosticCounter[] counters; lock (s_counterGroupLock) { - now = DateTime.UtcNow; - elapsed = now - _timeStampSinceCollectionStarted; - pollingIntervalInMilliseconds = _pollingIntervalInMilliseconds; + now = Stopwatch.GetTimestamp(); + elapsed = Stopwatch.GetElapsedTime(_timeStampSinceCollectionStarted, now); + pollingInterval = _pollingInterval; counters = new DiagnosticCounter[_counters.Count]; _counters.CopyTo(counters); } @@ -253,16 +256,22 @@ private void OnTimer() // written to the old session or the new session. The behavior change is not being treated as a // significant problem to address for now, but we can come back and address it if it turns out to // be an actual issue. - counter.WritePayload((float)elapsed.TotalSeconds, pollingIntervalInMilliseconds); + counter.WritePayload((float)elapsed.TotalSeconds, (int)pollingInterval.TotalMilliseconds); } lock (s_counterGroupLock) { _timeStampSinceCollectionStarted = now; - TimeSpan delta = now - _nextPollingTimeStamp; - delta = _pollingIntervalInMilliseconds > delta.TotalMilliseconds ? TimeSpan.FromMilliseconds(_pollingIntervalInMilliseconds) : delta; - if (_pollingIntervalInMilliseconds > 0) - _nextPollingTimeStamp += TimeSpan.FromMilliseconds(_pollingIntervalInMilliseconds * Math.Ceiling(delta.TotalMilliseconds / _pollingIntervalInMilliseconds)); + TimeSpan delta = Stopwatch.GetElapsedTime(_nextPollingTimeStamp, now); + if (delta < _pollingInterval) + { + delta = _pollingInterval; + } + + if (_pollingInterval > TimeSpan.Zero) + { + _nextPollingTimeStamp += (long)Math.Ceiling(delta / _pollingInterval) * _pollingInterval.Ticks * Stopwatch.Frequency / TimeSpan.TicksPerSecond; + } } } } @@ -292,14 +301,14 @@ private static void PollForValues() sleepEvent = s_pollingThreadSleepEvent; foreach (CounterGroup counterGroup in s_counterGroupEnabledList!) { - DateTime now = DateTime.UtcNow; - if (counterGroup._nextPollingTimeStamp < now + new TimeSpan(0, 0, 0, 0, 1)) + long now = Stopwatch.GetTimestamp(); + TimeSpan timeUntilNextPoll = Stopwatch.GetElapsedTime(now, counterGroup._nextPollingTimeStamp); + if (timeUntilNextPoll < TimeSpan.FromMilliseconds(1)) { onTimers.Add(counterGroup); } - int millisecondsTillNextPoll = (int)((counterGroup._nextPollingTimeStamp - now).TotalMilliseconds); - millisecondsTillNextPoll = Math.Max(1, millisecondsTillNextPoll); + int millisecondsTillNextPoll = Math.Max(1, (int)timeUntilNextPoll.TotalMilliseconds); sleepDurationInMilliseconds = Math.Min(sleepDurationInMilliseconds, millisecondsTillNextPoll); }