private static void MonitorLowPriority() { ShortTime lastTime = ShortTime.Now; while (true) { try { Thread.Sleep(10); ShortTime currentTime = ShortTime.Now; long sleepDelta = (long)lastTime.ElapsedTicks(currentTime); long additionalDelay = sleepDelta - 100 * TimeSpan.TicksPerMillisecond; double additionalDelayMS = additionalDelay / (double)TimeSpan.TicksPerMillisecond; if (additionalDelayMS > 1000) { LogLarge.Publish(additionalDelayMS.ToString() + " ms (Normal Priority)"); } else if (additionalDelayMS > 500) { LogMedium.Publish(additionalDelayMS.ToString() + " ms (Normal Priority)"); } Interlocked.Increment(ref s_lowProcessCount); lastTime = currentTime; } catch (Exception ex) { Log.Publish(MessageLevel.Warning, MessageFlags.BugReport, "Unexpected Exception Caught", null, null, ex); Thread.Sleep(1000); } } }
private static void MonitorHighPriority() { //This one will primarily detect when the process is paused. //This occurs when garbage collection occurs. ShortTime lastTime = ShortTime.Now; while (true) { try { Thread.Sleep(10); ShortTime currentTime = ShortTime.Now; long sleepDelta = (long)lastTime.ElapsedTicks(currentTime); long additionalDelay = sleepDelta - 10 * TimeSpan.TicksPerMillisecond; double additionalDelayMS = additionalDelay / (double)TimeSpan.TicksPerMillisecond; if (additionalDelayMS > 1000) { LogLarge.Publish(additionalDelayMS.ToString() + " ms (High Priority)"); } else if (additionalDelayMS > 300) { LogMedium.Publish(additionalDelayMS.ToString() + " ms (High Priority)"); } else if (additionalDelayMS > 100) { LogSmall.Publish(additionalDelayMS.ToString() + " ms (High Priority)"); } Interlocked.Increment(ref s_highProcessCount); AdjustRealtime(); lastTime = currentTime; } catch (Exception ex) { Log.Publish(MessageLevel.Warning, MessageFlags.BugReport, "Unexpected Exception Caught", null, null, ex); Thread.Sleep(1000); } } }
private static void AdjustRealtime() { //This method is supposed to be called every 10 milliseconds on a high priority thread. //However don't update the time unless 100ms has elapsed. //Since DateTime can be programmatically changed, I'm using CPU Registers. long physicalTimeSinceLastSet = (long)s_currentTimeSetTime.ElapsedTicks(); if (physicalTimeSinceLastSet < 100 * TimeSpan.TicksPerMillisecond) { return; } long clockSinceLastSet = DateTime.UtcNow.Ticks - s_currentTime; if (Math.Abs(physicalTimeSinceLastSet - clockSinceLastSet) > TimeSpan.TicksPerSecond) { Log.Publish(MessageLevel.Warning, MessageFlags.SystemHealth, "System time has been adjusted by more than 1 second. Resetting Loading Figures.", $"Expected Clock Change: {physicalTimeSinceLastSet / TimeSpan.TicksPerMillisecond} ms, Clock change: {clockSinceLastSet / TimeSpan.TicksPerMillisecond}"); Reset(); return; } if (clockSinceLastSet < 0) { Log.Publish(MessageLevel.Info, MessageFlags.SystemHealth, "System Clock did not advance.", $"Expected Clock Change: {physicalTimeSinceLastSet / TimeSpan.TicksPerMillisecond} ms, Clock change: {clockSinceLastSet / TimeSpan.TicksPerMillisecond}"); } int highDelay = Interlocked.Exchange(ref s_highProcessCount, 0); int normalDelay = Interlocked.Exchange(ref s_normalProcessCount, 0); int lowDelay = Interlocked.Exchange(ref s_lowProcessCount, 0); if (highDelay >= 5 && lowDelay <= 1) { try { OnHighLoad?.Invoke(); } catch (Exception) { } } long maxAdjustment = 0; if (lowDelay >= 7) { maxAdjustment = 500 * TimeSpan.TicksPerMillisecond; } else if (lowDelay >= 5) { maxAdjustment = 400 * TimeSpan.TicksPerMillisecond; } else if (normalDelay >= 7) { maxAdjustment = 300 * TimeSpan.TicksPerMillisecond; } else if (normalDelay >= 5) { maxAdjustment = 200 * TimeSpan.TicksPerMillisecond; } else if (highDelay >= 4) { maxAdjustment = 100 * TimeSpan.TicksPerMillisecond; } else { maxAdjustment = 50 * TimeSpan.TicksPerMillisecond; } if (maxAdjustment < clockSinceLastSet) { LogLoadingClock.Publish($"Behind by {clockSinceLastSet / TimeSpan.TicksPerMillisecond}ms adjusting by {maxAdjustment / TimeSpan.TicksPerMillisecond}ms"); } long adjustment = Math.Min(clockSinceLastSet, maxAdjustment); if (adjustment >= 0) { Interlocked.Exchange(ref s_currentTime, s_currentTime + adjustment); } s_currentTimeSetTime = ShortTime.Now; }