Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT[DYN-2332] As a user I want Tuneup times color coded to visually highlight hot spots #50

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions TuneUp/ProfiledNodeViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class ProfiledNodeViewModel : NotificationObject
/// </summary>
public string Name
{
get
get
{
// For virtual row, do not attempt to grab node name
if (!name.Contains(ExecutionTimelString) && !name.StartsWith(GroupNodePrefix))
Expand All @@ -37,7 +37,7 @@ public string Name
}
internal set { name = value; }
}

/// <summary>
/// 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.
Expand Down Expand Up @@ -133,6 +133,20 @@ public ProfiledNodeState State
}
private ProfiledNodeState state;

/// <summary>
/// The current hotspot state based on execution time and configured hotspot values
/// </summary>
public ProfiledNodeHotspotState HotspotState
{
get => hotspotState;
set
{
hotspotState = value;
RaisePropertyChanged(nameof(HotspotState));
}
}
private ProfiledNodeHotspotState hotspotState;

/// <summary>
/// The GUID of the group to which this node belongs
/// </summary>
Expand Down
68 changes: 64 additions & 4 deletions TuneUp/TuneUpWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
</ResourceDictionary.MergedDictionaries>
<local:IsGroupToMarginMultiConverter x:Key="IsGroupToMarginMultiConverter" />
<local:IsGroupToVisibilityMultiConverter x:Key="IsGroupToVisibilityMultiConverter" />
<local:IsGroupToBrushConverter x:Key="IsGroupToBrushConverter" />
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<local:IsGroupToBrushMultiConverter x:Key="IsGroupToBrushMultiConverter" />
</ResourceDictionary>
</Window.Resources>
<Grid Name="MainGrid" >
Expand Down Expand Up @@ -133,7 +134,14 @@
<Style x:Key="DataGridTextBlockStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="10,0,10,0"/>
<Setter Property="Foreground" Value="{Binding IsGroup, Converter={StaticResource IsGroupToBrushConverter}}"/>
<Setter Property="Foreground">
<Setter.Value>
<MultiBinding Converter="{StaticResource IsGroupToBrushMultiConverter}">
<Binding Path="IsGroup"/>
<Binding Path="HotspotState"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Path=IsMouseOver}" Value="True">
<Setter Property="Foreground" Value="{StaticResource MemberButtonText}"/>
Expand All @@ -150,10 +158,29 @@
</Trigger>
</Style.Triggers>
</Style>
<!-- TextBox Style -->
<Style x:Key="NumberBoxStyle" TargetType="TextBox">
<Setter Property="Height" Value="20" />
<Setter Property="MinWidth" Value="25" />
<Setter Property="Margin" Value="2,0,0,0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Background" Value="{StaticResource PreferencesWindowBackgroundColor}" />
<Setter Property="BorderThickness" Value="0,0,0,2" />
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="Foreground" Value="{StaticResource PreferencesWindowFontColor}" />
<Setter Property="Visibility" Value="{Binding Path=ShowHotspotsEnabled, Converter={StaticResource BoolToVisibilityConverter}}" />
<EventSetter Event="PreviewTextInput" Handler="NumberValidationTextBox" />
</Style>
<!-- Label Style -->
<Style x:Key="SettingsLabelStyle" TargetType="Label">
<Setter Property="FontFamily" Value="{StaticResource ArtifaktElementRegular}"/>
<Setter Property="Foreground" Value="{StaticResource NodeNameForeground}"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Recompute All Button -->
<StackPanel
Expand Down Expand Up @@ -186,10 +213,43 @@
Name="TotalGraphExecutiontimeLabel"
Content="{Binding Path=TotalGraphExecutiontime, Mode=OneWay}"/>
</StackPanel>
<StackPanel Grid.Row="1">
<StackPanel Grid.Row="1"
HorizontalAlignment="Left"
Orientation="Horizontal">
<ToggleButton
Grid.Column="0"
Width="40"
Height="20"
Margin="2,0,0,0"
VerticalAlignment="Center"
IsEnabled="True"
Style="{StaticResource EllipseToggleButton1}"
Checked="HotspotToggleButton_Checked"
Unchecked="HotspotToggleButton_Checked"/>
<Label
Content="Show Node Hotspots"
Style="{StaticResource SettingsLabelStyle}"/>
<TextBox
x:Name="MinValueNumberBox"
Style="{StaticResource NumberBoxStyle}"
Text="{Binding Path=HotspotMinValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label
Style="{StaticResource SettingsLabelStyle}"
Content="Min value"
Visibility="{Binding Path=ShowHotspotsEnabled, Converter={StaticResource BoolToVisibilityConverter}}"/>
<TextBox
x:Name="MaxValueNumberBox"
Style="{StaticResource NumberBoxStyle}"
Text="{Binding Path=HotspotMaxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Label
Style="{StaticResource SettingsLabelStyle}"
Content="Max value"
Visibility="{Binding Path=ShowHotspotsEnabled, Converter={StaticResource BoolToVisibilityConverter}}"/>
</StackPanel>
<StackPanel Grid.Row="2">
<DataGrid
x:Name="NodeAnalysisTable"
Grid.Row="1"
Grid.Row="2"
ItemsSource="{Binding Path=ProfiledNodesCollection.View}"
Style="{StaticResource DataGridStyle1}"
AutoGenerateColumns="False"
Expand Down
46 changes: 41 additions & 5 deletions TuneUp/TuneUpWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using Dynamo.Extensions;
using Dynamo.Graph.Nodes;
Expand Down Expand Up @@ -86,7 +89,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
Expand Down Expand Up @@ -154,10 +157,35 @@ private void ExportTimes_Click(object sender, RoutedEventArgs e)
{
(NodeAnalysisTable.DataContext as TuneUpWindowViewModel).ExportToCsv();
}

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();
}
}

public class IsGroupToMarginMultiConverter : IMultiValueConverter
{
private static readonly Guid DefaultGuid = Guid.Empty;
Expand All @@ -179,17 +207,25 @@ public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
}
}

public class IsGroupToBrushConverter : IValueConverter
public class IsGroupToBrushMultiConverter : IMultiValueConverter
{
private static readonly SolidColorBrush GroupBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#333333"));
private static readonly SolidColorBrush DefaultBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AAAAAA"));
private static readonly SolidColorBrush MinHotspotBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#B7D78C"));
private static readonly SolidColorBrush MaxHotspotBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#EB5555"));

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return value is bool isGroup && isGroup ? GroupBrush : DefaultBrush;
if (values.Length == 2 && values[0] is bool isGroup && values[1] is ProfiledNodeHotspotState hotspotState)
{
if (isGroup) return GroupBrush;
else if (hotspotState == ProfiledNodeHotspotState.Low) return MinHotspotBrush;
else if (hotspotState == ProfiledNodeHotspotState.High) return MaxHotspotBrush;
}
return DefaultBrush;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
Expand Down
99 changes: 96 additions & 3 deletions TuneUp/TuneUpWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Linq;
using System.Threading;
using System.Windows.Data;
using System.Windows.Media;
using Dynamo.Core;
using Dynamo.Engine.Profiling;
using Dynamo.Graph.Annotations;
Expand Down Expand Up @@ -43,6 +42,21 @@ public enum ProfiledNodeState
NotExecuted = 5,
}

/// <summary>
/// Enum of possible states of node depending on execution time and hotspot values
/// </summary>
public enum ProfiledNodeHotspotState
{
[Display(Name = "Mid")]
Mid = 0,

[Display(Name = "Low")]
Low = 1,

[Display(Name = "High")]
High = 2
}

/// <summary>
/// ViewModel for TuneUp.
/// Handles profiling setup, workspace events, execution events, etc.
Expand All @@ -63,6 +77,9 @@ public class TuneUpWindowViewModel : NotificationObject, IDisposable
private bool isTuneUpChecked = false;
private ListSortDirection sortDirection;
private string sortingOrder = "number";
private bool showHotspotsEnabled;
private int hotspotMinValue;
private int hotspotMaxValue;

/// <summary>
/// Name of the row to display current execution time
Expand Down Expand Up @@ -190,6 +207,54 @@ public bool IsTuneUpChecked
}
}

/// <summary>
/// Gets or sets a value indicating whether hotspot highlighting is enabled.
/// </summary>
public bool ShowHotspotsEnabled
{
get => showHotspotsEnabled;
set
{
showHotspotsEnabled = value;
SetNodeHotspotState();
RaisePropertyChanged(nameof(ShowHotspotsEnabled));
}
}

/// <summary>
/// Gets or sets the minimum value for hotspot highlighting.
/// </summary>
public int HotspotMinValue
{
get => hotspotMinValue;
set
{
if (hotspotMinValue != value)
{
hotspotMinValue = value;
RaisePropertyChanged(nameof(HotspotMinValue));
SetNodeHotspotState();
}
}
}

/// <summary>
/// Gets or sets the maximum value for hotspot highlighting.
/// </summary>
public int HotspotMaxValue
{
get => hotspotMaxValue;
set
{
if (hotspotMaxValue != value)
{
hotspotMaxValue = value;
RaisePropertyChanged(nameof(HotspotMaxValue));
SetNodeHotspotState();
}
}
}

/// <summary>
/// Collection of profiling data for nodes in the current workspace
/// </summary>
Expand All @@ -215,7 +280,7 @@ public string TotalGraphExecutiontime
return (PreviousExecutionTimeRow?.ExecutionMilliseconds + CurrentExecutionTimeRow?.ExecutionMilliseconds).ToString() + "ms";
}
}

#endregion

#region Constructor
Expand Down Expand Up @@ -485,6 +550,34 @@ private void CalculateGroupNodes()
}
}

/// <summary>
/// Updates the hotspot state of all nodes based on execution time and configured hotspot values.
/// </summary>
private void SetNodeHotspotState()
{
foreach (var node in nodeDictionary.Values)
{
if (node.State == ProfiledNodeState.NotExecuted || !ShowHotspotsEnabled)
{
node.HotspotState = ProfiledNodeHotspotState.Mid;
continue;
}

if (node.ExecutionMilliseconds <= HotspotMinValue)
{
node.HotspotState = ProfiledNodeHotspotState.Low;
}
else if (node.ExecutionMilliseconds >= HotspotMaxValue)
{
node.HotspotState = ProfiledNodeHotspotState.High;
}
else
{
node.HotspotState = ProfiledNodeHotspotState.Mid;
}
}
}

/// <summary>
/// Applies the sorting logic to the ProfiledNodesCollection.
/// </summary>
Expand Down Expand Up @@ -602,7 +695,7 @@ private void CurrentWorkspaceModel_GroupAdded(AnnotationModel group)
profiledNode.GroupExecutionOrderNumber = profiledGroup.GroupExecutionOrderNumber;

groupDictionary[group.GUID].Add(profiledNode);
}
}
}
// Executes for each group when a graph with groups is open while TuneUp is enabled
// Ensures that group nodes are sorted properly and do not appear at the bottom of the DataGrid
Expand Down