From fc759442a83ef241cbfd93f636ac33f3533559aa Mon Sep 17 00:00:00 2001 From: danmiller973 Date: Thu, 11 Aug 2022 16:28:57 -0600 Subject: [PATCH 1/2] DA-102: Desktop app benchmarking tool --- .gitignore | 1 + .../Daqifi.Desktop.Bootloader.Test.csproj | 5 - .../Daqifi.Desktop.Bootloader.csproj | 6 - .../Daqifi.Desktop.Common.Test.csproj | 6 - .../Daqifi.Desktop.Common.csproj | 6 - .../Daqifi.Desktop.DataModel.Test.csproj | 6 - .../Daqifi.Desktop.DataModel.csproj | 8 - .../Daqifi.Desktop.IO.Test.csproj | 6 - Daqifi.Desktop.IO/Daqifi.Desktop.IO.csproj | 6 - .../Daqifi.Desktop.Test.csproj | 6 - Daqifi.Desktop/Daqifi.Desktop.csproj | 6 - Daqifi.Desktop/Daqifi.Desktop.csproj.user | 10 + Daqifi.Desktop/Loggers/SummaryLogger.cs | 427 ++++++++++++++++++ Daqifi.Desktop/MainWindow.xaml | 12 +- .../View/Flyouts/SummaryFlyout.xaml | 130 ++++++ .../View/Flyouts/SummaryFlyout.xaml.cs | 13 + Daqifi.Desktop/ViewModels/DaqifiViewModel.cs | 31 ++ 17 files changed, 623 insertions(+), 62 deletions(-) create mode 100644 Daqifi.Desktop/Loggers/SummaryLogger.cs create mode 100644 Daqifi.Desktop/View/Flyouts/SummaryFlyout.xaml create mode 100644 Daqifi.Desktop/View/Flyouts/SummaryFlyout.xaml.cs diff --git a/.gitignore b/.gitignore index f1b13ad6..712d3477 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ obj AnalysisReport.sarif debug.log upgrade-assistant.clef +.vs/ diff --git a/Daqifi.Desktop.Bootloader.Test/Daqifi.Desktop.Bootloader.Test.csproj b/Daqifi.Desktop.Bootloader.Test/Daqifi.Desktop.Bootloader.Test.csproj index 4509736d..0b483b0b 100644 --- a/Daqifi.Desktop.Bootloader.Test/Daqifi.Desktop.Bootloader.Test.csproj +++ b/Daqifi.Desktop.Bootloader.Test/Daqifi.Desktop.Bootloader.Test.csproj @@ -12,11 +12,6 @@ - - - - - diff --git a/Daqifi.Desktop.Bootloader/Daqifi.Desktop.Bootloader.csproj b/Daqifi.Desktop.Bootloader/Daqifi.Desktop.Bootloader.csproj index 55a44335..3d397e58 100644 --- a/Daqifi.Desktop.Bootloader/Daqifi.Desktop.Bootloader.csproj +++ b/Daqifi.Desktop.Bootloader/Daqifi.Desktop.Bootloader.csproj @@ -11,13 +11,7 @@ - - - - - - \ No newline at end of file diff --git a/Daqifi.Desktop.Common.Test/Daqifi.Desktop.Common.Test.csproj b/Daqifi.Desktop.Common.Test/Daqifi.Desktop.Common.Test.csproj index 171ee1c4..f6cb349c 100644 --- a/Daqifi.Desktop.Common.Test/Daqifi.Desktop.Common.Test.csproj +++ b/Daqifi.Desktop.Common.Test/Daqifi.Desktop.Common.Test.csproj @@ -4,12 +4,6 @@ false - - - - - - diff --git a/Daqifi.Desktop.Common/Daqifi.Desktop.Common.csproj b/Daqifi.Desktop.Common/Daqifi.Desktop.Common.csproj index 8c776320..1632d343 100644 --- a/Daqifi.Desktop.Common/Daqifi.Desktop.Common.csproj +++ b/Daqifi.Desktop.Common/Daqifi.Desktop.Common.csproj @@ -16,14 +16,8 @@ - - - - - - \ No newline at end of file diff --git a/Daqifi.Desktop.DataModel.Test/Daqifi.Desktop.DataModel.Test.csproj b/Daqifi.Desktop.DataModel.Test/Daqifi.Desktop.DataModel.Test.csproj index 171ee1c4..f6cb349c 100644 --- a/Daqifi.Desktop.DataModel.Test/Daqifi.Desktop.DataModel.Test.csproj +++ b/Daqifi.Desktop.DataModel.Test/Daqifi.Desktop.DataModel.Test.csproj @@ -4,12 +4,6 @@ false - - - - - - diff --git a/Daqifi.Desktop.DataModel/Daqifi.Desktop.DataModel.csproj b/Daqifi.Desktop.DataModel/Daqifi.Desktop.DataModel.csproj index 6493020f..08291609 100644 --- a/Daqifi.Desktop.DataModel/Daqifi.Desktop.DataModel.csproj +++ b/Daqifi.Desktop.DataModel/Daqifi.Desktop.DataModel.csproj @@ -9,12 +9,4 @@ - - - - - - - - \ No newline at end of file diff --git a/Daqifi.Desktop.IO.Test/Daqifi.Desktop.IO.Test.csproj b/Daqifi.Desktop.IO.Test/Daqifi.Desktop.IO.Test.csproj index 17ca6785..f4cc410d 100644 --- a/Daqifi.Desktop.IO.Test/Daqifi.Desktop.IO.Test.csproj +++ b/Daqifi.Desktop.IO.Test/Daqifi.Desktop.IO.Test.csproj @@ -11,14 +11,8 @@ - - - - - - diff --git a/Daqifi.Desktop.IO/Daqifi.Desktop.IO.csproj b/Daqifi.Desktop.IO/Daqifi.Desktop.IO.csproj index 78515640..0fb26593 100644 --- a/Daqifi.Desktop.IO/Daqifi.Desktop.IO.csproj +++ b/Daqifi.Desktop.IO/Daqifi.Desktop.IO.csproj @@ -13,13 +13,7 @@ - - - - - - \ No newline at end of file diff --git a/Daqifi.Desktop.Test/Daqifi.Desktop.Test.csproj b/Daqifi.Desktop.Test/Daqifi.Desktop.Test.csproj index fc49ad99..38492aa2 100644 --- a/Daqifi.Desktop.Test/Daqifi.Desktop.Test.csproj +++ b/Daqifi.Desktop.Test/Daqifi.Desktop.Test.csproj @@ -8,14 +8,8 @@ - - - - - - diff --git a/Daqifi.Desktop/Daqifi.Desktop.csproj b/Daqifi.Desktop/Daqifi.Desktop.csproj index 04d11b20..8d603dc7 100644 --- a/Daqifi.Desktop/Daqifi.Desktop.csproj +++ b/Daqifi.Desktop/Daqifi.Desktop.csproj @@ -142,11 +142,6 @@ false - - - - - @@ -162,7 +157,6 @@ - diff --git a/Daqifi.Desktop/Daqifi.Desktop.csproj.user b/Daqifi.Desktop/Daqifi.Desktop.csproj.user index 7937b018..8f2bbc2b 100644 --- a/Daqifi.Desktop/Daqifi.Desktop.csproj.user +++ b/Daqifi.Desktop/Daqifi.Desktop.csproj.user @@ -10,4 +10,14 @@ en-US false + + + Code + + + + + Designer + + \ No newline at end of file diff --git a/Daqifi.Desktop/Loggers/SummaryLogger.cs b/Daqifi.Desktop/Loggers/SummaryLogger.cs new file mode 100644 index 00000000..87f30a36 --- /dev/null +++ b/Daqifi.Desktop/Loggers/SummaryLogger.cs @@ -0,0 +1,427 @@ +using Daqifi.Desktop.Channel; +using Daqifi.Desktop.Commands; +using Daqifi.Desktop.Common.Loggers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Daqifi.Desktop.Logger +{ + /// + /// Provaides summary data for incoming samples + /// + public class SummaryLogger : ObservableObject, ILogger + { + + #region "Private Data" + + /// + /// Summary results object + /// + private class SummaryBuffer + { + public SummaryBuffer() + { + Devices = new HashSet(); + Channels = new HashSet(); + } + + /// + /// The number of samples seen + /// + public int SampleCount { get; set; } + + /// + /// The total elapsed time + /// + public long FirstSampleTicks { get; set; } + + /// + /// The total elapsed time + /// + public long LastSampleTicks { get; set; } + + /// + /// The average time between samples + /// + public double AverageDeltaTicks { get; set; } + + /// + /// The maximum time between samples + /// + public long MaxDeltaTicks { get; set; } + + /// + /// The minimum time between samples + /// + public long MinDeltaTicks { get; set; } + + /// + /// The devices seen + /// + public HashSet Devices { get; set; } + + /// + /// The channels seen + /// + public HashSet Channels { get; set; } + + /// + /// The maximum value of the incoming samples + /// + public double MaxValue { get; set; } + + /// + /// The minimum value of the incoming samples + /// + public double MinValue { get; set; } + + /// + /// The average value of the incoming samples + /// + public double AverageValue { get; set; } + + public void Reset() + { + SampleCount = 0; + FirstSampleTicks = 0; + LastSampleTicks = 0; + AverageDeltaTicks = 0; + MaxDeltaTicks = 0; + MinDeltaTicks = 0; + Devices.Clear(); + Channels.Clear(); + MaxValue = 0.0; + MinValue = 0.0; + AverageValue = 0.0; + } + } + + private int _loggingSession; + + private int _sampleSize; + + private bool _enabled; + + /// + /// The in-progress sample set + /// + private SummaryBuffer _buffer; + + /// + /// The last completed sample set + /// + private SummaryBuffer _current; + + /// + /// Application logger + /// + public AppLogger AppLogger = AppLogger.Instance; + #endregion + + #region "Properties" + /// + /// The log session to track + /// + public int LoggingSession + { + get => _loggingSession; + set { _loggingSession = value; NotifyPropertyChanged("LoggingSession"); } + } + + /// + /// Indicates whether the logger is accepting data + /// + public bool Enabled + { + get => _enabled; + set { _enabled = value; NotifyPropertyChanged("Enabled"); } + } + + /// + /// The number of samples to evaluate + /// + public int SampleSize + { + get => _sampleSize; + set { _sampleSize = value; NotifyPropertyChanged("SampleSize"); } + } + + /// + /// The total elapsed time + /// + public TimeSpan ElapsedTime + { + get + { + return TimeSpan.FromTicks(_current.LastSampleTicks - _current.FirstSampleTicks); + } + } + + /// + /// The time of the last sample + /// + public DateTime LastUpdate + { + get + { + return new DateTime(_current.LastSampleTicks); + } + } + + /// + /// The frequency sample rate + /// + public double SampleRate + { + get + { + return _current.AverageDeltaTicks >0 ? 1.0 / TimeSpan.FromTicks((long)_current.AverageDeltaTicks).TotalSeconds : 0.0; + } + } + + /// + /// The maximum time between samples + /// + public TimeSpan MaxDelta + { + get + { + return new TimeSpan(_current.MaxDeltaTicks); + } + } + + /// + /// The minimum time between samples + /// + public TimeSpan MinDelta + { + get + { + return new TimeSpan(_current.MinDeltaTicks); + } + } + + /// + /// The devices sthat reported data + /// + public string Devices + { + get + { + return _current.Devices.Any() ? _current.Devices.Aggregate((a, b) => String.Format("{0}, {1}", a, b)) : String.Empty; + } + } + + /// + /// The channels seen + /// + public string Channels + { + get + { + return _current.Channels.Any() ? _current.Channels.Aggregate((a, b) => String.Format("{0}, {1}", a, b)) : String.Empty; + } + } + + /// + /// The maximum value of the incoming samples + /// + public double MaxValue + { + get + { + return _current.MaxValue; + } + } + + /// + /// The minimum value of the incoming samples + /// + public double MinValue + { + get + { + return _current.MinValue; + } + } + + /// + /// The average value of the incoming samples + /// + public double AverageValue + { + get + { + return _current.AverageValue; + } + } + + #endregion + + #region "Command Properties" + + /// + /// Resets the summary logger + /// + public ICommand ResetCommand { get; } + + /// + /// Starts or stops the summary logger + /// + public ICommand ToggleEnabledCommand { get; } + + #endregion + + #region "Constructor" + + public SummaryLogger() + { + _buffer = new SummaryBuffer(); + _current = new SummaryBuffer(); + + _sampleSize = 1000; + + ResetCommand = new DelegateCommand(Reset); + ToggleEnabledCommand = new DelegateCommand(ToggleEnabled); + } + + #endregion + + public void Log(DataSample dataSample) + { + if (!_enabled) + { + return; + } + + lock(_buffer) + { + if (dataSample.LoggingSessionID != _loggingSession) + { + return; + } + + if (_buffer.SampleCount == 0) + { + _buffer.FirstSampleTicks = dataSample.TimestampTicks; + _buffer.MinValue = dataSample.Value; + _buffer.MaxValue = dataSample.Value; + } + else + { + _buffer.MinValue = Math.Min(dataSample.Value, _buffer.MinValue); + _buffer.MaxValue = Math.Max(dataSample.Value, _buffer.MaxValue); + } + _buffer.AverageValue += dataSample.Value / _sampleSize; + + if (_buffer.SampleCount > 0) + { + var elapsed = dataSample.TimestampTicks - _buffer.LastSampleTicks; + if (_buffer.SampleCount == 1) + { + _buffer.MinDeltaTicks = elapsed; + _buffer.MaxDeltaTicks = elapsed; + } + else + { + _buffer.MinDeltaTicks = Math.Min(_buffer.MinDeltaTicks, elapsed); + _buffer.MaxDeltaTicks = Math.Max(_buffer.MinDeltaTicks, elapsed); + } + _buffer.AverageDeltaTicks += elapsed / (double)(_sampleSize - 1); + } + _buffer.LastSampleTicks = dataSample.TimestampTicks; + + _buffer.Devices.Add(dataSample.DeviceName); + _buffer.Channels.Add(dataSample.ChannelName); + + ++_buffer.SampleCount; + if (_buffer.SampleCount == _sampleSize) + { + lock (_current) + { + SwapBuffer(); + } + } + } + } + + private void SwapBuffer() + { + lock(_buffer) + { + lock (_current) + { + (_current, _buffer) = (_buffer, _current); + _buffer.Reset(); + + NotifyResultsChanged(); + } + } + } + + private void NotifyResultsChanged() + { + NotifyPropertyChanged("ElapsedTime"); + NotifyPropertyChanged("LastUpdate"); + NotifyPropertyChanged("SampleRate"); + NotifyPropertyChanged("MaxDelta"); + NotifyPropertyChanged("MinDelta"); + NotifyPropertyChanged("Devices"); + NotifyPropertyChanged("Channels"); + NotifyPropertyChanged("MaxValue"); + NotifyPropertyChanged("MinValue"); + NotifyPropertyChanged("AverageValue"); + } + + private void ToggleEnabled(object o) + { + if (Enabled) + { + Stop(); + } + else + { + Start(); + } + } + + private void Start() + { + lock(_buffer) + { + _enabled = false; + _buffer.Reset(); + _enabled = true; + NotifyPropertyChanged("Enabled"); + } + } + + private void Stop() + { + lock (_buffer) + { + _enabled = false; + NotifyPropertyChanged("Enabled"); + } + } + + private void Reset(object o) + { + lock(_buffer) + { + lock (_current) + { + Enabled = false; + SampleSize = 1000; + _buffer.Reset(); + _current.Reset(); + NotifyResultsChanged(); + } + } + } + } +} diff --git a/Daqifi.Desktop/MainWindow.xaml b/Daqifi.Desktop/MainWindow.xaml index ebb244c4..98b3bcc9 100644 --- a/Daqifi.Desktop/MainWindow.xaml +++ b/Daqifi.Desktop/MainWindow.xaml @@ -8,6 +8,7 @@ xmlns:Service="clr-namespace:Daqifi.Desktop.DialogService" xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" Service:DialogService.IsRegisteredView="True" Title="DAQifi v1.0.9" Height="{Binding Height, Mode=TwoWay}" Width="{Binding Width, Mode=TwoWay}" WindowState="{Binding ViewWindowState, Mode=OneWayToSource}" BorderThickness="0" GlowBrush="Black"> @@ -82,7 +83,10 @@ - + + + + @@ -131,6 +135,12 @@ + +