JD2022-TU1/main/extern/ProfileEventViewer4/Summary.cs

525 lines
No EOL
20 KiB
C#

using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.IO;
// Keep in sync with ProfileEvent.cs
using Time = System.Double;
using TD.SandDock;
namespace ProfileEventViewer
{
public partial class Summary : UserDockableWindow
{
private ProfileEventTrace m_Parent = null;
private int m_ItemClickCount = 1;
private UInt32 m_LastItemID = UInt32.MaxValue;
private Timer m_SelectionTimer = new Timer();
private bool m_SelectionChanged = true;
private List<ListViewInfo> m_ListViewInfo = new List<ListViewInfo>();
private List<ListViewInfo> m_FilteredListViewInfo = new List<ListViewInfo>();
private SortInfo m_SortInfo = new SortInfo() { Ascending = true, Column = 0 };
private ListViewCache m_ListViewCache = new ListViewCache();
private Filters Filters { get; set; }
public List<ListViewInfo> ListViewInfos
{
get { return m_ListViewInfo; }
}
public Summary(ProfileEventTrace parent)
{
InitializeComponent();
m_Parent = parent;
Text = m_Parent.Text.Replace(" Trace", " Summary");
Filters = new Filters();
m_SelectionTimer.Interval = 50;
m_SelectionTimer.Tick += new EventHandler(m_SelectionTimer_Tick);
toolStripStatusTotalTime.Text = string.Empty;
toolStripStatusSelectedTime.Text = string.Empty;
foreach (ProfileEventData.ProfileContext context in parent.Data.Contexts.Values)
{
if (!context.ContainsProfileEvents())
continue;
ToolStripMenuItem item = new ToolStripMenuItem(context.Name);
item.Checked = true;
item.CheckOnClick = true;
item.Visible = !context.IsHidden;
item.Tag = context;
item.Click += menuItemContext_Click;
contextMenuStripList.Items.Add(item);
}
parent.ContextSelectionChanged += ContextSelectionChanged;
parent.SelectionTimesChanged += SelectionTimesChanged;
parent.ContextsFilterChanged += ContextsFilterChanged;
}
void ContextSelectionChanged(ProfileEventTrace sender, HashSet<string> filteredContexts)
{
// Update the menu's checkboxes.
int baseIndex = contextMenuStripList.Items.IndexOf(toolStripSeparatorContextNames) + 1;
for (int i = baseIndex; i < contextMenuStripList.Items.Count; ++i)
{
ToolStripMenuItem item = (ToolStripMenuItem)contextMenuStripList.Items[i];
item.Checked = !filteredContexts.Contains(item.Text);
}
}
void SelectionTimesChanged(ProfileEventTrace sender)
{
m_SelectionChanged = true;
if (DockSituation != DockSituation.None)
{
UpdateWithTrace(m_SelectionChanged);
m_SelectionChanged = false;
}
}
void ContextsFilterChanged(ProfileEventTrace sender)
{
// Update the menu's visibility.
int baseIndex = contextMenuStripList.Items.IndexOf(toolStripSeparatorContextNames) + 1;
for (int i = baseIndex; i < contextMenuStripList.Items.Count; ++i)
{
ToolStripMenuItem item = (ToolStripMenuItem)contextMenuStripList.Items[i];
ProfileEventData.ProfileContext context = item.Tag as ProfileEventData.ProfileContext;
if (context != null)
item.Visible = !context.IsHidden;
}
}
void m_SummaryList_ColumnClick(object sender, ColumnClickEventArgs e)
{
if (e.Column == m_SortInfo.Column)
{
m_SortInfo.Ascending = !m_SortInfo.Ascending;
}
else if (e.Column == 0) // ProfileName
{
m_SortInfo.Ascending = true;
}
else // All other columns are numbers; I prefer to see the biggest ones first.
{
m_SortInfo.Ascending = false;
}
m_SortInfo.Column = e.Column;
SortUsingCurrentSettings();
m_SummaryList.Invalidate();
}
private void SortUsingCurrentSettings()
{
m_ListViewCache.Clear();
m_SummaryList.VirtualListSize = 0;
m_SummaryList.SelectedIndices.Clear(); // Clear selection, as it is not well supported to sort it...
int signChanger = m_SortInfo.Ascending ? 1 : -1;
if (m_SortInfo.Column == 0) // ProfileName
m_FilteredListViewInfo.Sort((x, y) => signChanger * CaseInsensitiveComparer.Default.Compare(x.ProfileName, y.ProfileName));
else if (m_SortInfo.Column == 1) // TotalTime
m_FilteredListViewInfo.Sort((x, y) => signChanger * Math.Sign(x.TotalTime - y.TotalTime));
else if (m_SortInfo.Column == 2) // ClockTime
m_FilteredListViewInfo.Sort((x, y) => signChanger * Math.Sign(x.ClockTime - y.ClockTime));
else if (m_SortInfo.Column == 3) // CallCount
m_FilteredListViewInfo.Sort((x, y) => signChanger * x.CallCount.CompareTo(y.CallCount));
else if (m_SortInfo.Column == 4) // MeanTime
m_FilteredListViewInfo.Sort((x, y) => signChanger * Math.Sign(x.MeanTime - y.MeanTime));
else if (m_SortInfo.Column == 5) // MinTime
m_FilteredListViewInfo.Sort((x, y) => signChanger * Math.Sign(x.MinTime - y.MinTime));
else if (m_SortInfo.Column == 6) // MaxTime
m_FilteredListViewInfo.Sort((x, y) => signChanger * Math.Sign(x.MaxTime - y.MaxTime));
m_SummaryList.VirtualListSize = m_FilteredListViewInfo.Count;
UpdateSelectionSummary();
}
private void textBoxFilter_TextChanged(object sender, EventArgs e)
{
Filters.SetFilter(textBoxFilter.Text.Trim());
UpdateListViewItem();
}
private void UpdateListViewItem()
{
m_FilteredListViewInfo.Clear();
m_ListViewCache.Clear();
if (!Filters.IsValid)
{
m_FilteredListViewInfo.AddRange(m_ListViewInfo);
}
else
{
m_FilteredListViewInfo.AddRange(m_ListViewInfo.Where(info => Filters.IsAllowed(info.ProfileName)));
}
SortUsingCurrentSettings();
if (m_FilteredListViewInfo.Count == 0)
toolStripStatusTotalTime.Text = string.Empty;
else
{
Time totalTime = m_FilteredListViewInfo.Sum(info => info.TotalTime);
Time minExtent = m_FilteredListViewInfo.Min(info => info.MinTimeExtent);
Time maxExtent = m_FilteredListViewInfo.Max(info => info.MaxTimeExtent);
ClockTime mergedClockTime = new ClockTime();
m_FilteredListViewInfo.ForEach(info => mergedClockTime.Merge(info.GetClockTimeObject()));
mergedClockTime.CoalesceResults();
toolStripStatusTotalTime.Text = string.Format("{0} / {1} / {2} / {3}", m_Parent.TimeToString(totalTime), m_Parent.TimeToString(mergedClockTime.GetTime()), m_Parent.TimeToString(maxExtent - minExtent), m_FilteredListViewInfo.Count);
}
m_SummaryList.Invalidate();
}
public void UpdateWithTrace(bool selectionChanged)
{
if (!selectionChanged)
return;
// Supports detail mode only.
m_SummaryList.View = View.Details;
m_ListViewCache.Clear();
m_ListViewInfo.Clear();
foreach (UInt32 id in m_Parent.SelectionTimes.Keys)
{
ProfileEventTrace.SelectionInfo info = (ProfileEventTrace.SelectionInfo)m_Parent.SelectionTimes[id];
Time time = info.m_TotalTime;
if (time > (Time)0)
{
ListViewInfo listViewInfo = new ListViewInfo()
{
ProfileName = m_Parent.Data.GetProfileName(id),
ProfileId = id,
CallCount = info.m_Calls,
TotalTime = info.m_TotalTime,
MinTime = info.m_MinTime,
MaxTime = info.m_MaxTime,
ClockTime = info.m_ClockTime.GetTime(),
MinTimeExtent = info.m_MinTimeExtent,
MaxTimeExtent = info.m_MaxTimeExtent
};
listViewInfo.SetClockTimeObject(info.m_ClockTime);
m_ListViewInfo.Add(listViewInfo);
}
}
UpdateListViewItem();
}
private void Summary_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}
private void m_SummaryList_DoubleClick(object sender, EventArgs e)
{
if (menuItemDblClkCenterView.Checked)
CenterViewOnSelection();
else
ZoomViewOnSelection();
}
private bool HandleEventCycle()
{
if (m_SummaryList.SelectedIndices.Count == 0)
return false;
UInt32 itemId = m_FilteredListViewInfo[m_SummaryList.SelectedIndices[0]].ProfileId;
if (itemId == m_LastItemID)
++m_ItemClickCount;
else
m_ItemClickCount = 1;
m_LastItemID = itemId;
return true;
}
private void ZoomViewOnSelection()
{
HandleEventCycle();
m_Parent.Open(); // Ensure visible.
m_Parent.ZoomViewOnItem(m_LastItemID, m_ItemClickCount);
}
private void CenterViewOnSelection()
{
HandleEventCycle();
m_Parent.Open(); // Ensure visible.
m_Parent.CenterViewOnItem(m_LastItemID, m_ItemClickCount);
}
private void menuItemCenterOnItem_Click(object sender, EventArgs e)
{
CenterViewOnSelection();
}
private void menuItemZoomOnItem_Click(object sender, EventArgs e)
{
ZoomViewOnSelection();
}
private void buttonExportCSV_Click(object sender, EventArgs e)
{
SaveFileDialog fileDlg = new SaveFileDialog();
fileDlg.OverwritePrompt = true;
fileDlg.Filter = "Comma Separated file (*.csv) | *.csv";
if (fileDlg.ShowDialog() == DialogResult.OK)
{
SaveCSV(fileDlg.FileName);
}
}
private void SaveCSV(string fileName)
{
StreamWriter sw = System.IO.File.CreateText(fileName);
foreach (System.Reflection.PropertyInfo property in typeof(ListViewInfo).GetProperties())
sw.Write(string.Format("{0};", property.Name));
sw.WriteLine();
foreach (ListViewInfo info in m_FilteredListViewInfo)
{
foreach (System.Reflection.PropertyInfo property in typeof(ListViewInfo).GetProperties())
sw.Write(string.Format("{0};", property.GetValue(info, null).ToString()));
sw.WriteLine();
}
sw.Close();
MessageBox.Show(string.Format("File {0} created.", fileName));
}
private void SelectAll()
{
// Weird way of selecting, but a helluva lot faster than doing it by hand!
// ... As a note, SendKeys may trigger a first chance exception of type NullReferenceException
// So when using this feature while debugging, you should not trap NullReferenceExceptions, otherwise the feature won't work
m_SummaryList.Focus();
m_SummaryList.BeginUpdate();
ListViewItem topItem = m_SummaryList.TopItem;
SendKeys.Send("{END}"); // Send END key
SendKeys.Send(" "); // Send "space" key (selects the last element)
SendKeys.SendWait("+{HOME}"); // Send Shift + HOME keys (to select all)
m_SummaryList.TopItem = topItem; // Try to keep the same scroll position (doesn't always exactly work, but it's better than having it scrolled up all the way to the top)
m_SummaryList.EndUpdate();
}
private void Summary_DockSituationChanged(object sender, EventArgs e)
{
statusStrip.SizingGrip = (DockSituation == DockSituation.Floating);
if (m_Parent != null)
{
if (DockSituation != DockSituation.None)
{
UpdateWithTrace(m_SelectionChanged);
m_SelectionChanged = false;
}
}
}
private void m_SummaryList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
m_SelectionTimer.Start();
}
private void m_SummaryList_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
{
m_SelectionTimer.Start();
}
private void m_SelectionTimer_Tick(object sender, EventArgs e)
{
UpdateSelectionSummary();
}
private void UpdateSelectionSummary()
{
m_SelectionTimer.Stop();
if (m_Parent == null)
return;
if (m_SummaryList.SelectedIndices.Count == 0)
{
toolStripStatusSelectedTime.Text = string.Empty;
return;
}
// Calculate the total time for selected events
Time totalTime = 0;
Time minExtent = Time.MaxValue;
Time maxExtent = Time.MinValue;
ClockTime mergedClockTime = new ClockTime();
foreach (int index in m_SummaryList.SelectedIndices)
{
ListViewInfo info = m_FilteredListViewInfo[index];
totalTime += info.TotalTime;
minExtent = Math.Min(minExtent, info.MinTimeExtent);
maxExtent = Math.Max(maxExtent, info.MaxTimeExtent);
mergedClockTime.Merge(info.GetClockTimeObject());
}
mergedClockTime.CoalesceResults();
toolStripStatusSelectedTime.Text = string.Format("{0} / {1} / {2} / {3}", m_Parent.TimeToString(totalTime), m_Parent.TimeToString(mergedClockTime.GetTime()), m_Parent.TimeToString(maxExtent - minExtent), m_SummaryList.SelectedIndices.Count);
}
private void menuItemSelectAll_Click(object sender, EventArgs e)
{
SelectAll();
}
private void m_SummaryList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
if (m_ListViewCache.IsIndexInCache(e.ItemIndex))
{
e.Item = m_ListViewCache.GetListViewItem(e.ItemIndex);
return;
}
ListViewInfo info = m_FilteredListViewInfo[e.ItemIndex];
ListViewItem item = new ListViewItem(info.ProfileName);
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.TotalTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.ClockTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.CallCount.ToString()));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.MeanTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.MinTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.MaxTime)));
e.Item = item;
}
private void m_SummaryList_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
{
if (m_ListViewCache.IsRangeInCache(e.StartIndex, e.EndIndex))
return; // Requested cache is a subset of the current one
List<ListViewItem> listViewCache = new List<ListViewItem>(e.EndIndex - e.StartIndex + 1);
for (int i = e.StartIndex; i <= e.EndIndex; ++i)
{
ListViewInfo info = m_FilteredListViewInfo[i];
ListViewItem item = new ListViewItem(info.ProfileName);
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.TotalTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.ClockTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.CallCount.ToString()));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.MeanTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.MinTime)));
item.SubItems.Add(new ListViewItem.ListViewSubItem(item, m_Parent.TimeToString(info.MaxTime)));
listViewCache.Add(item);
}
m_ListViewCache.Populate(listViewCache, e.StartIndex);
}
private void menuItemAll_Click(object sender, EventArgs e)
{
List<string> contextNames = new List<string>();
int baseIndex = contextMenuStripList.Items.IndexOf(toolStripSeparatorContextNames) + 1;
for (int i = baseIndex; i < contextMenuStripList.Items.Count; ++i)
{
ToolStripMenuItem item = (ToolStripMenuItem)contextMenuStripList.Items[i];
contextNames.Add(item.Text);
item.Checked = true;
}
m_Parent.UnfilterContexts(contextNames);
}
private void menuItemNone_Click(object sender, EventArgs e)
{
List<string> contextNames = new List<string>();
int baseIndex = contextMenuStripList.Items.IndexOf(toolStripSeparatorContextNames) + 1;
for (int i = baseIndex; i < contextMenuStripList.Items.Count; ++i)
{
ToolStripMenuItem item = (ToolStripMenuItem)contextMenuStripList.Items[i];
contextNames.Add(item.Text);
item.Checked = false;
}
m_Parent.FilterContexts(contextNames);
}
private void menuItemContext_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = (ToolStripMenuItem)sender;
if (item.Checked)
m_Parent.UnfilterContext(item.Text);
else
m_Parent.FilterContext(item.Text);
}
private void contextMenuStripList_Opening(object sender, CancelEventArgs e)
{
if (m_SummaryList.SelectedIndices.Count == 0)
{
menuItemCenterOnItem.Visible = false;
menuItemZoomOnItem.Visible = false;
}
else
{
string profileName = m_FilteredListViewInfo[m_SummaryList.SelectedIndices[0]].ProfileName;
menuItemCenterOnItem.Visible = true;
menuItemCenterOnItem.Text = "&Center on next " + profileName;
menuItemZoomOnItem.Visible = true;
menuItemZoomOnItem.Text = "&Zoom on next " + profileName;
}
}
private void menuItemDblClkCenterView_Click(object sender, EventArgs e)
{
menuItemDblClkCenterView.Checked = true;
menuItemDblClkZoomView.Checked = false;
}
private void menuItemDblClkZoomView_Click(object sender, EventArgs e)
{
menuItemDblClkCenterView.Checked = false;
menuItemDblClkZoomView.Checked = true;
}
}
}