From 63e394d884ca30394d324b7dbbe6ca25a393fb2a Mon Sep 17 00:00:00 2001 From: Niko Ehrenfeuchter <nikolaus.ehrenfeuchter@unibas.ch> Date: Sun, 11 Mar 2018 23:11:34 +0100 Subject: [PATCH] Extend Monitoring.Cpu with field initializers and timeout on violation. --- ATxCommon/Monitoring/Cpu.cs | 78 +++++++++++++++++++++++++++++++++++-- ATxService/AutoTx.cs | 22 ++++++++++- 2 files changed, 94 insertions(+), 6 deletions(-) diff --git a/ATxCommon/Monitoring/Cpu.cs b/ATxCommon/Monitoring/Cpu.cs index c0272ee..be98f76 100644 --- a/ATxCommon/Monitoring/Cpu.cs +++ b/ATxCommon/Monitoring/Cpu.cs @@ -1,8 +1,10 @@ using System; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Timers; using NLog; +using Timer = System.Timers.Timer; namespace ATxCommon.Monitoring { @@ -13,26 +15,78 @@ namespace ATxCommon.Monitoring private readonly Timer _monitoringTimer; private readonly PerformanceCounter _cpuCounter; private readonly float[] _loadReadings = {0F, 0F, 0F, 0F}; + private float _load; + private int _interval; + private int _limit; + private int _behaving; + private int _probation; + private bool _enabled; + public float Load() => _load; + public int Interval { + get => _interval; + set { + _interval = value; + _monitoringTimer.Interval = value; + Log.Debug("CPU monitoring interval: {0}", _interval); + } + } + + public int Limit { + get => _limit; + set { + _limit = value; + Log.Debug("CPU monitoring limit: {0}", _limit); + } + } + + public int Probation { + get => _probation; + set { + _probation = value; + Log.Debug("CPU monitoring probation cycles when violating limit: {0}", _probation); + } + } + + public bool Enabled { + get => _enabled; + set => EnableTimer(value); + } + + public Cpu() { + _interval = 250; + _limit = 25; + _probation = 40; Log.Debug("Initializing CPU monitoring..."); + try { _cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); - _monitoringTimer = new Timer(250); + Log.Debug("CPU monitoring initializing PerformanceCounter (takes 1s)..."); + _cpuCounter.NextValue(); + Thread.Sleep(1000); + Log.Debug("CPU monitoring current load: {0}", _cpuCounter.NextValue()); + // _monitoringTimer = new Timer(_interval); + _monitoringTimer = new Timer(_interval); _monitoringTimer.Elapsed += UpdateCpuLoad; - _monitoringTimer.Enabled = true; } - catch (Exception ex) { - Log.Error("Initializing CPU monitoring completed ({1}): {0}", ex.Message, ex.GetType()); + catch (Exception) { + Log.Error("Initializing CPU monitoring failed!"); throw; } Log.Debug("Initializing CPU monitoring completed."); } + private void EnableTimer(bool enabled) { + Log.Debug("{0} CPU monitoring.", enabled ? "Enabling" : "Disabling"); + _monitoringTimer.Enabled = enabled; + _enabled = enabled; + } + private void UpdateCpuLoad(object sender, ElapsedEventArgs e) { _monitoringTimer.Enabled = false; try { @@ -42,6 +96,22 @@ namespace ATxCommon.Monitoring _loadReadings[3] = _cpuCounter.NextValue(); _load = _loadReadings.Average(); Log.Trace("load values: {0}, average: {1}", string.Join(", ", _loadReadings), _load); + if (_loadReadings[3] > _limit) { + Log.Debug("CPU load ({0}) violating limit ({1})!", _loadReadings[3], _limit); + _behaving = 0; + // TODO: fire callback for violating load limit + } else { + _behaving++; + if (_behaving == _probation) { + Log.Debug("CPU load below limit for {0} cycles, yay!", _probation); + // TODO: fire callback for load behaving well + } else if (_behaving > _probation) { + Log.Debug("CPU load behaving well since {0} cycles.", _behaving); + } else if (_behaving < 0) { + Log.Warn("Integer wrap around happened, resetting probation counter!"); + _behaving = 0; + } + } } catch (Exception ex) { Log.Error("UpdateCpuLoad failed: {0}", ex.Message); diff --git a/ATxService/AutoTx.cs b/ATxService/AutoTx.cs index 61d3cc4..69d1d62 100644 --- a/ATxService/AutoTx.cs +++ b/ATxService/AutoTx.cs @@ -380,14 +380,32 @@ namespace ATxService _mainTimer.Elapsed += OnTimedEvent; _mainTimer.Enabled = true; - - _cpu = new Cpu(); } catch (Exception ex) { Log.Error("Error in OnStart(): {0}", ex.Message); throw; } + try { + _cpu = new Cpu { + Interval = 250, + Limit = 25, + Probation = 16, + Enabled = true + }; + } + catch (UnauthorizedAccessException ex) { + Log.Error("Not enough permissions to monitor the CPU load.\nMake sure the " + + "service account is a member of the [Performance Monitor Users] " + + "system group.\nError message was: {0}", ex.Message); + throw; + } + catch (Exception ex) { + Log.Error("Unexpected error initializing CPU monitoring: {0}", ex.Message); + throw; + } + + // read the build timestamp from the resources: var buildTimestamp = Properties.Resources.BuildDate.Trim(); var buildCommitName = Properties.Resources.BuildCommit.Trim(); -- GitLab