From fff0fdb7f5ca7bf6658000c9e8eb9d979f18c634 Mon Sep 17 00:00:00 2001 From: Ivo Petrov Date: Mon, 15 Jul 2024 14:13:54 +0100 Subject: [PATCH 1/2] draft - hotspots highlighted --- TuneUp/ProfiledNodeViewModel.cs | 72 ++++++++- TuneUp/TuneUpWindow.xaml | 254 ++++++++++++++++++++------------ TuneUp/TuneUpWindow.xaml.cs | 42 +++++- TuneUp/TuneUpWindowViewModel.cs | 52 ++++++- 4 files changed, 311 insertions(+), 109 deletions(-) diff --git a/TuneUp/ProfiledNodeViewModel.cs b/TuneUp/ProfiledNodeViewModel.cs index 8c52c92..b2bdf4c 100644 --- a/TuneUp/ProfiledNodeViewModel.cs +++ b/TuneUp/ProfiledNodeViewModel.cs @@ -2,12 +2,67 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; +using System.Windows.Media; using Dynamo.Core; using Dynamo.Graph.Nodes; namespace TuneUp { public class ProfiledNodeViewModel : NotificationObject { + internal SolidColorBrush hotspotMinValueBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B7D78C")); + internal SolidColorBrush hotspotMaxValueBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#EB5555")); + internal SolidColorBrush defaultRowBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AAAAAA")); + + private int hotspotMinValue; + private int hotspotMaxValue; + public int HotspotMinValue + { + get => hotspotMinValue; + set + { + if (hotspotMinValue != value) + { + hotspotMinValue = value; + RaisePropertyChanged(nameof(HotspotMinValue)); + RaisePropertyChanged(nameof(RowBackground)); + } + } + } + public int HotspotMaxValue + { + get => hotspotMaxValue; + set + { + if (hotspotMaxValue != value) + { + hotspotMaxValue = value; + RaisePropertyChanged(nameof(HotspotMaxValue)); + RaisePropertyChanged(nameof(RowBackground)); + } + } + } + public Brush RowBackground + { + get + { + if (ExecutionMilliseconds < HotspotMinValue && HotspotMinValue > 0 && State != ProfiledNodeState.NotExecuted) + { + return hotspotMinValueBrush; + } + if (ExecutionMilliseconds > HotspotMaxValue && HotspotMaxValue > 0 && State != ProfiledNodeState.NotExecuted) + { + return hotspotMaxValueBrush; + } + return defaultRowBrush; + } + } + public void UpdateHotspotValues(int minVal, int maxVal) + { + HotspotMinValue = minVal; + HotspotMaxValue = maxVal; + } + + #region Properties /// /// Prefix string of execution time. @@ -22,7 +77,7 @@ public class ProfiledNodeViewModel : NotificationObject /// public string Name { - get + get { // For virtual row, do not attempt to grab node name if (!name.Contains(ExecutionTimelString)) @@ -31,7 +86,7 @@ public string Name } internal set { name = value; } } - + /// /// The order number of this node in the most recent graph run. /// Returns null if the node was not executed during the most recent graph run. @@ -65,6 +120,8 @@ public TimeSpan ExecutionTime executionTime = value; RaisePropertyChanged(nameof(ExecutionTime)); RaisePropertyChanged(nameof(ExecutionMilliseconds)); + // IP ADDED + RaisePropertyChanged(nameof(RowBackground)); } } private TimeSpan executionTime; @@ -74,10 +131,13 @@ public TimeSpan ExecutionTime /// public int ExecutionMilliseconds { - get - { - return (int)Math.Round(ExecutionTime.TotalMilliseconds); - } + get => (int)Math.Round(ExecutionTime.TotalMilliseconds); + //set + //{ + // executionMilliseconds = value; + // RaisePropertyChanged(nameof(ExecutionMilliseconds)); + // RaisePropertyChanged(nameof(RowBackground)); + //} } /// diff --git a/TuneUp/TuneUpWindow.xaml b/TuneUp/TuneUpWindow.xaml index 3316f72..6535a7d 100644 --- a/TuneUp/TuneUpWindow.xaml +++ b/TuneUp/TuneUpWindow.xaml @@ -1,43 +1,58 @@ - + - + + + + + + + + + + + - + - + - + - + - + + + + + + - - - + + Orientation="Horizontal"> - - - - - + - + HorizontalAlignment="Left" + Orientation="Horizontal"> + + + + - + Foreground="#ffffff" + Text="{Binding Name}" /> - - - - + + - - - + + - - - + + - diff --git a/TuneUp/TuneUpWindow.xaml.cs b/TuneUp/TuneUpWindow.xaml.cs index 155c9b1..69969dd 100644 --- a/TuneUp/TuneUpWindow.xaml.cs +++ b/TuneUp/TuneUpWindow.xaml.cs @@ -1,12 +1,21 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Media; using Dynamo.Extensions; using Dynamo.Graph.Nodes; using Dynamo.Models; using Dynamo.Utilities; using Dynamo.Wpf.Extensions; +using System.Text.RegularExpressions; +using System.Windows.Input; +using System.Globalization; +using CoreNodeModels.Input; namespace TuneUp { @@ -73,7 +82,7 @@ private void NodeAnalysisTable_SelectionChanged(object sender, SelectionChangedE if (selectedNodes.Count() > 0) { // Select - var command = new DynamoModel.SelectModelCommand(selectedNodes.Select(nm => nm.GUID), ModifierKeys.None); + var command = new DynamoModel.SelectModelCommand(selectedNodes.Select(nm => nm.GUID), Dynamo.Utilities.ModifierKeys.None); commandExecutive.ExecuteCommand(command, uniqueId, "TuneUp"); // Focus on selected @@ -90,5 +99,34 @@ private void RecomputeGraph_Click(object sender, RoutedEventArgs e) { (NodeAnalysisTable.DataContext as TuneUpWindowViewModel).ResetProfiling(); } + + private void HotspotToggleButton_Checked(object sender, RoutedEventArgs e) + { + var viewModel = NodeAnalysisTable.DataContext as TuneUpWindowViewModel; + viewModel.ShowHotspotsEnabled = (sender as ToggleButton).IsChecked == true; + } + + private void NumberValidationTextBox(object sender, TextCompositionEventArgs e) + { + Regex regex = new Regex("[^0-9]+"); + e.Handled = regex.IsMatch(e.Text); + } + } + + #region Converters + + public class BoolToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return (bool)value ? Visibility.Visible : Visibility.Hidden; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotSupportedException(); + } } + + #endregion } diff --git a/TuneUp/TuneUpWindowViewModel.cs b/TuneUp/TuneUpWindowViewModel.cs index 347d053..d1a6813 100644 --- a/TuneUp/TuneUpWindowViewModel.cs +++ b/TuneUp/TuneUpWindowViewModel.cs @@ -39,6 +39,52 @@ public enum ProfiledNodeState /// public class TuneUpWindowViewModel : NotificationObject, IDisposable { + private bool showHotspotsEnabled; + private int hotspotMinValue; + private int hotspotMaxValue; + public bool ShowHotspotsEnabled + { + get => showHotspotsEnabled; + set + { + showHotspotsEnabled = value; + RaisePropertyChanged(nameof(ShowHotspotsEnabled)); + } + } + public int HotspotMinValue + { + get => hotspotMinValue; + set + { + if (hotspotMinValue != value) + { + hotspotMinValue = value; + RaisePropertyChanged(nameof(HotspotMinValue)); + UpdateNodeBackgrounds(); + } + } + } + public int HotspotMaxValue + { + get => hotspotMaxValue; + set + { + if (hotspotMaxValue != value) + { + hotspotMaxValue = value; + RaisePropertyChanged(nameof(HotspotMaxValue)); + UpdateNodeBackgrounds(); + } + } + } + private void UpdateNodeBackgrounds() + { + foreach (var node in nodeDictionary.Values) + { + node.UpdateHotspotValues(HotspotMinValue, HotspotMaxValue); + } + } + #region Internal Properties private ViewLoadedParams viewLoadedParams; @@ -97,7 +143,7 @@ private HomeWorkspaceModel CurrentWorkspace #endregion #region Public Properties - + /// /// Is the recomputeAll button enabled in the UI. Users should not be able to force a /// reset of the engine and re-execution of the graph if one is still ongoing. This causes...trouble. @@ -418,7 +464,7 @@ private void ManageWorkspaceEvents(HomeWorkspaceModel workspace, bool subscribe) node.NodeExecutionBegin += OnNodeExecutionBegin; node.NodeExecutionEnd += OnNodeExecutionEnd; } - ResetProfiledNodes(); + ResetProfiledNodes(); } // Unsubscribe to workspace events else @@ -433,7 +479,7 @@ private void ManageWorkspaceEvents(HomeWorkspaceModel workspace, bool subscribe) node.NodeExecutionBegin -= OnNodeExecutionBegin; node.NodeExecutionEnd -= OnNodeExecutionEnd; } - } + } executedNodesNum = 0; } From 0f137c8b5bc876bd90a0a3a2ee6b1a21ea97230b Mon Sep 17 00:00:00 2001 From: Ivo Petrov Date: Wed, 31 Jul 2024 07:38:52 +0100 Subject: [PATCH 2/2] conflicts resolved --- TuneUp/ProfiledNodeViewModel.cs | 213 +++++++++----- TuneUp/TuneUpWindow.xaml | 315 ++++++++++++-------- TuneUp/TuneUpWindow.xaml.cs | 135 ++++++++- TuneUp/TuneUpWindowViewModel.cs | 502 +++++++++++++++++++++++++++----- 4 files changed, 889 insertions(+), 276 deletions(-) diff --git a/TuneUp/ProfiledNodeViewModel.cs b/TuneUp/ProfiledNodeViewModel.cs index b2bdf4c..281643a 100644 --- a/TuneUp/ProfiledNodeViewModel.cs +++ b/TuneUp/ProfiledNodeViewModel.cs @@ -1,74 +1,25 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Windows.Media; using Dynamo.Core; +using Dynamo.Graph.Annotations; using Dynamo.Graph.Nodes; + namespace TuneUp { public class ProfiledNodeViewModel : NotificationObject { - internal SolidColorBrush hotspotMinValueBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B7D78C")); - internal SolidColorBrush hotspotMaxValueBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#EB5555")); - internal SolidColorBrush defaultRowBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AAAAAA")); - - private int hotspotMinValue; - private int hotspotMaxValue; - public int HotspotMinValue - { - get => hotspotMinValue; - set - { - if (hotspotMinValue != value) - { - hotspotMinValue = value; - RaisePropertyChanged(nameof(HotspotMinValue)); - RaisePropertyChanged(nameof(RowBackground)); - } - } - } - public int HotspotMaxValue - { - get => hotspotMaxValue; - set - { - if (hotspotMaxValue != value) - { - hotspotMaxValue = value; - RaisePropertyChanged(nameof(HotspotMaxValue)); - RaisePropertyChanged(nameof(RowBackground)); - } - } - } - public Brush RowBackground - { - get - { - if (ExecutionMilliseconds < HotspotMinValue && HotspotMinValue > 0 && State != ProfiledNodeState.NotExecuted) - { - return hotspotMinValueBrush; - } - if (ExecutionMilliseconds > HotspotMaxValue && HotspotMaxValue > 0 && State != ProfiledNodeState.NotExecuted) - { - return hotspotMaxValueBrush; - } - return defaultRowBrush; - } - } - public void UpdateHotspotValues(int minVal, int maxVal) - { - HotspotMinValue = minVal; - HotspotMaxValue = maxVal; - } - - #region Properties /// /// Prefix string of execution time. /// public static readonly string ExecutionTimelString = "Execution Time"; + public static readonly string GroupNodePrefix = "Group: "; + private string name = String.Empty; /// /// The name of this profiled node. This value can be either an actual @@ -80,7 +31,7 @@ public string Name get { // For virtual row, do not attempt to grab node name - if (!name.Contains(ExecutionTimelString)) + if (!name.Contains(ExecutionTimelString) && !name.StartsWith(GroupNodePrefix)) name = NodeModel?.Name; return name; } @@ -93,10 +44,7 @@ public string Name /// public int? ExecutionOrderNumber { - get - { - return executionOrderNumber; - } + get => executionOrderNumber; set { executionOrderNumber = value; @@ -105,39 +53,56 @@ public int? ExecutionOrderNumber } private int? executionOrderNumber; + /// + /// The order number of this group in the most recent graph run. + /// This number is assigned to each node within the group. + /// + public int? GroupExecutionOrderNumber + { + get => groupExecutionOrderNumber; + set + { + groupExecutionOrderNumber = value; + RaisePropertyChanged(nameof(GroupExecutionOrderNumber)); + } + } + private int? groupExecutionOrderNumber; /// /// The most recent execution time of this node /// public TimeSpan ExecutionTime { - get - { - return executionTime; - } + get => executionTime; set { executionTime = value; RaisePropertyChanged(nameof(ExecutionTime)); RaisePropertyChanged(nameof(ExecutionMilliseconds)); - // IP ADDED - RaisePropertyChanged(nameof(RowBackground)); } } private TimeSpan executionTime; + /// + /// The total execution time of all node in the group. + /// + public TimeSpan GroupExecutionTime + { + get => groupExecutionTime; + set + { + groupExecutionTime = value; + RaisePropertyChanged(nameof(GroupExecutionTime)); + } + } + private TimeSpan groupExecutionTime; + /// /// The most recent execution time of this node in milliseconds /// public int ExecutionMilliseconds { get => (int)Math.Round(ExecutionTime.TotalMilliseconds); - //set - //{ - // executionMilliseconds = value; - // RaisePropertyChanged(nameof(ExecutionMilliseconds)); - // RaisePropertyChanged(nameof(RowBackground)); - //} } /// @@ -145,10 +110,7 @@ public int ExecutionMilliseconds /// public bool WasExecutedOnLastRun { - get - { - return wasExecutedOnLastRun; - } + get => wasExecutedOnLastRun; set { wasExecutedOnLastRun = value; @@ -162,10 +124,7 @@ public bool WasExecutedOnLastRun /// public ProfiledNodeState State { - get - { - return state; - } + get => state; set { state = value; @@ -174,6 +133,81 @@ public ProfiledNodeState State } private ProfiledNodeState state; + /// + /// The current hotspot state based on execution time and configured hotspot values + /// + public ProfiledNodeHotspotState HotspotState + { + get => hotspotState; + set + { + hotspotState = value; + RaisePropertyChanged(nameof(HotspotState)); + } + } + private ProfiledNodeHotspotState hotspotState; + + /// + /// The GUID of the group to which this node belongs + /// + public Guid GroupGUID + { + get => groupGIUD; + set + { + groupGIUD = value; + RaisePropertyChanged(nameof(GroupGUID)); + } + } + private Guid groupGIUD; + + /// + /// The name of the group to which this node belongs + /// This property is also applied to individual nodes and is used when sorting by name + /// + public string GroupName + { + get => groupName; + set + { + groupName = value; + RaisePropertyChanged(nameof(GroupName)); + } + } + private string groupName; + + /// + /// Indicates if this node is a group + /// + public bool IsGroup + { + get => isGroup; + set + { + isGroup = value; + RaisePropertyChanged(nameof(IsGroup)); + } + } + private bool isGroup; + + /// + /// The background brush for this node + /// If this node represents a group, it inherits the background color from the associated AnnotationModel + /// + public SolidColorBrush BackgroundBrush + { + get => backgroundBrush; + set + { + if (value != null) + { + backgroundBrush = value; + RaisePropertyChanged(nameof(BackgroundBrush)); + } + } + } + private SolidColorBrush backgroundBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#333333")); + /// /// Return the display name of state enum. /// Making this identical property because of datagrid binding @@ -190,6 +224,11 @@ public string StateDescription } } + /// + /// The Stopwatch to measure execution time of this node + /// + internal Stopwatch Stopwatch { get; set; } + internal NodeModel NodeModel { get; set; } #endregion @@ -202,6 +241,7 @@ public ProfiledNodeViewModel(NodeModel node) { NodeModel = node; State = ProfiledNodeState.NotExecuted; + Stopwatch = new Stopwatch(); } /// @@ -217,5 +257,20 @@ public ProfiledNodeViewModel(string name, TimeSpan exTimeSum, ProfiledNodeState this.ExecutionTime = exTimeSum; State = state; } + + /// + /// An alternative constructor to represent an annotation model as a group node. + /// + /// the annotation model + public ProfiledNodeViewModel(AnnotationModel group) + { + NodeModel = null; + Name = $"{GroupNodePrefix}{group.AnnotationText}"; + GroupName = group.AnnotationText; + GroupGUID = group.GUID; + BackgroundBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(group.Background)); + IsGroup = true; + State = ProfiledNodeState.NotExecuted; + } } } diff --git a/TuneUp/TuneUpWindow.xaml b/TuneUp/TuneUpWindow.xaml index 6535a7d..d0608e1 100644 --- a/TuneUp/TuneUpWindow.xaml +++ b/TuneUp/TuneUpWindow.xaml @@ -1,70 +1,115 @@ - - + + + + - - + - + - + - + - + - + + + @@ -116,30 +182,38 @@ - + + Grid.Row="0" + HorizontalAlignment="Left" + Orientation="Horizontal"> - - - - + Text="{Binding Path=HotspotMaxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>