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

2501 lines
96 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using TD.SandDock;
using Time = System.Double;
namespace ProfileEventViewer
{
public partial class ProfileEventTrace : UserTabbedDocument
{
#region Internal classes, structures and enums
struct View
{
public Time TimeStart { get; private set;}
public Time TimeEnd { get; private set; }
public Time ZoomFactor { get { return 1.0 / (TimeEnd - TimeStart); } }
public delegate void ViewChangedHandler(View view);
public event ViewChangedHandler ViewChanged;
const Time MIN_DIFF = 5;
const Time MAX_DIFF = 100000000000;
private void SetZoom(Time startTime, Time endTime)
{
SetZoom(startTime, endTime, TimeStart, 0);
}
// In charge of changing the zoom and not putting bad values in it!
private void SetZoom(Time startTime, Time endTime, Time zoomLocation, Time startRatio)
{
if (endTime - startTime < MIN_DIFF) // Maximal zoom
{
TimeStart = zoomLocation - startRatio * MIN_DIFF;
TimeEnd = zoomLocation + (1 - startRatio) * MIN_DIFF;
}
else if (endTime - startTime > MAX_DIFF) // Minimal zoom
{
TimeStart = zoomLocation - startRatio * MAX_DIFF;
TimeEnd = zoomLocation + (1 - startRatio) * MAX_DIFF;
}
else
{
TimeStart = startTime;
TimeEnd = endTime;
}
if (ViewChanged != null)
ViewChanged(this);
}
private void ChangeZoom(Time startDelta, Time endDelta)
{
SetZoom(TimeStart + startDelta, TimeEnd + endDelta);
}
private void ChangeZoom(Time startDelta, Time endDelta, Time zoomLocation, Time startRatio)
{
SetZoom(TimeStart + startDelta, TimeEnd + endDelta, zoomLocation, startRatio);
}
public void ZoomOnTime(Time timeLocation, Time timeDx)
{
// where removing dx * timeStepPerPixel * 2 units from the selection
// split it around the focus so that the focus location on screen remains
// constant
Time timeToRemove = timeDx * 2;
Time ratio = (TimeEnd - timeLocation) / (TimeEnd - TimeStart);
ChangeZoom(timeToRemove * (1 - ratio), -timeToRemove * ratio, timeLocation, (1 - ratio));
}
public void Zoom(Time timeDx)
{
Time centerLocation = TimeStart + (TimeEnd - TimeStart) / 2;
ZoomOnTime(centerLocation, timeDx);
}
public void ZoomToAbsolute(Time start, Time end)
{
SetZoom(start, end, start, 0);
}
public void CenterOnLocation(Time location)
{
Time dt = location - (TimeStart + TimeEnd) / 2;
Pan(dt);
}
public void Pan(Time delta)
{
ChangeZoom(delta, delta);
}
public bool IsRangeVisible(Time rangeStart, Time rangeEnd)
{
System.Diagnostics.Debug.Assert(rangeStart <= rangeEnd);
return !(rangeStart > TimeEnd || rangeEnd < TimeStart || rangeStart == rangeEnd);
}
}
public class SelectionInfo
{
public Time m_MinTimeExtent = Time.MaxValue;
public Time m_MaxTimeExtent = Time.MinValue;
public ClockTime m_ClockTime = new ClockTime();
public Time m_TotalTime;
public Time m_MinTime = Time.MaxValue;
public Time m_MaxTime = Time.MinValue;
public UInt32 m_Calls;
};
struct DrawEventContext
{
public int m_Y;
public Graphics Graphics;
};
struct FindEventContext
{
public Time Time;
public int TargetDepth;
}
enum MouseMode
{
None,
Pan,
ZoomOnLocation,
MarkRange,
SelectContexts
};
#endregion
#region Static stuff
private const int EventHeight = 20;
private const int TitleHeight = 30;
private const int MaxDataEventWidth = 300;
private static readonly Color DataEventColor = Color.Yellow;
private static readonly Color FilteredDataEventColor = Color.FromArgb(100, Color.Yellow);
private static readonly Color FilteredOutColor = Color.FromArgb(100, 100, 100, 100);
private static readonly Pen engineFrameDelimiterPen = new Pen(Color.FromArgb(25, 200, 0, 0), 1);
private static readonly Pen graphicFrameDelimiterPen = new Pen(Color.FromArgb(25, 0, 0, 200), 1);
private static readonly Pen rectPen = new Pen(Color.Black, 1);
private static readonly Pen rectFilteredOutPen = new Pen(FilteredOutColor);
private static readonly Pen adjustedRectPen = new Pen(Color.Black, 1);
private static readonly Pen adjustedRectFilteredOutPen = new Pen(FilteredOutColor);
private static readonly Pen selectedRectPen = new Pen(Color.Black, 2);
private static readonly Pen selectedRectFilteredOutPen = new Pen(FilteredOutColor, 2);
private static readonly Pen adjustedSelectedRectPen = new Pen(Color.Black, 2);
private static readonly Pen adjustedSelectedRectFilteredOutPen = new Pen(FilteredOutColor, 2);
private static readonly Pen[,,] eventPens;
private static readonly SolidBrush rectBrush = new SolidBrush(Color.DarkGray);
private static readonly Brush contextBackgroundBrushLight = new SolidBrush(Color.LightGray);
private static readonly Brush contextBackgroundBrushDark = new SolidBrush(Color.Gray);
private static readonly Brush contextButtonBrush = new SolidBrush(Color.WhiteSmoke);
private static readonly Font contextTitleFont = new Font("Arial Black", 16);
private static readonly Font barFont = new Font("Arial Narrow", 10);
private static readonly Font dataEventFont = new Font("Arial Narrow", 9);
private static readonly Brush fontBrush = new SolidBrush(Color.Black);
private static readonly Brush fontFilteredOutBrush = new SolidBrush(Color.FromArgb(80, 80, 80, 80));
private static readonly Brush rangeBrush = new SolidBrush(Color.FromArgb(64, 64, 64, 64));
private static readonly Pen tspen = new Pen(Color.Black);
private static readonly Pen tspen2 = new Pen(Color.Black);
private static readonly SolidBrush sleepBrush = new SolidBrush(Color.FromArgb(40, Color.DarkRed));
private static readonly Pen sleepPen = new Pen(Color.FromArgb(96, Color.DarkRed));
private static readonly SolidBrush sleepFontBrush = new SolidBrush(Color.FromArgb(190, Color.DarkRed));
private static readonly SolidBrush filteredOutSleepBrush = new SolidBrush(Color.FromArgb(20, sleepBrush.Color));
private static readonly Pen filteredOutSleepPen = new Pen(Color.FromArgb(48, sleepPen.Color));
private static readonly SolidBrush filteredOutSleepFontBrush = new SolidBrush(Color.FromArgb(95, sleepFontBrush.Color));
private static readonly SolidBrush awakeBrush = new SolidBrush(Color.Ivory);
private static readonly Pen awakePen = new Pen(Color.Black);
private static readonly SolidBrush filteredOutAwakeBrush = new SolidBrush(Color.FromArgb(100, awakeBrush.Color));
private static readonly Pen filteredOutAwakePen = new Pen(Color.FromArgb(100, awakePen.Color));
private static readonly Pen timeLinePrimaryPen = new Pen(Color.FromArgb(32, Color.Black));
private static readonly Pen timeLineSecondaryPen = new Pen(Color.FromArgb(16, Color.Black));
private static readonly Brush timeLineBrush = new SolidBrush(Color.FromArgb(128, Color.Black));
private static readonly Font timeLineFont = new Font("Arial Black", 8);
private static readonly Pen highlightPen = new Pen(Color.Black, 2);
private static readonly Brush engineFrameBrush = new SolidBrush(Color.FromArgb(100, 200, 0, 0));
private static readonly Brush graphicFrameBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 200));
private static readonly Brush whiteFontBrush = new SolidBrush(Color.White);
static ProfileEventTrace()
{
adjustedRectPen.DashStyle = DashStyle.Dash;
adjustedRectFilteredOutPen.DashStyle = DashStyle.Dash;
adjustedSelectedRectPen.DashStyle = DashStyle.Dash;
adjustedSelectedRectFilteredOutPen.DashStyle = DashStyle.Dash;
eventPens = new Pen[2 /*IsAdjusted*/, 2/*IsSelected*/, 2/*IsHidden*/];
eventPens[0, 0, 0] = rectPen;
eventPens[0, 0, 1] = rectFilteredOutPen;
eventPens[0, 1, 0] = selectedRectPen;
eventPens[0, 1, 1] = selectedRectFilteredOutPen;
eventPens[1, 0, 0] = adjustedRectPen;
eventPens[1, 0, 1] = adjustedRectFilteredOutPen;
eventPens[1, 1, 0] = adjustedSelectedRectPen;
eventPens[1, 1, 1] = adjustedSelectedRectFilteredOutPen;
}
#endregion
#region Events
public delegate void FilterChangedHandler(ProfileEventTrace sender);
public event FilterChangedHandler EventsFilterChanged;
public event FilterChangedHandler ContextsFilterChanged;
public delegate void RangeSelectionChangedHandler(ProfileEventTrace sender, bool markingEnded, bool contentChanged);
public event RangeSelectionChangedHandler RangeSelectionChanged;
public delegate void ContextSelectionChangedHandler(ProfileEventTrace sender, HashSet<string> filteredContexts);
public event ContextSelectionChangedHandler ContextSelectionChanged;
public delegate void SelectionTimesChangedHandler(ProfileEventTrace sender);
public event SelectionTimesChangedHandler SelectionTimesChanged;
#endregion
#region Private Members
private ProfileEventDoc m_Doc;
private ProfileEventData m_Data;
private Summary m_Summary;
private TaskGraph m_TaskGraph;
private Filters m_Filters = new Filters();
private Regex m_ContextsVisibilityFilter = new Regex(".*", RegexOptions.Compiled);
private View m_View;
private int m_YOffset;
private Time m_RangeStart;
private Time m_RangeEnd;
private Time m_FocusTime;
private int m_SelectContextStartYOffset;
private int m_SelectContextEndYOffset;
private Time m_TimeStepPerPixel;
private Hashtable m_SelectionTimes = new Hashtable();
private bool m_ShowThreadInfo = false;
private bool m_ShowThreadInfoContexts = false;
private bool m_ShowTimeLine = false;
private bool m_ShowSecondaryTimeLineMarkers = false;
private bool m_ShowParentShadow = false;
private bool m_ShowTinyEvents = true;
private int m_LastX;
private int m_LastY;
private MouseMode m_MouseMode = MouseMode.None;
private ProfileEventData.ProfileContext.Event m_SelectedProfileEvent = null;
private ProfileEventData.ProfileContext.Data m_SelectedDataEvent = null;
private ProfileEventData.ProfileContext.Event m_ToolTipEvent = null;
private ProfileEventData.ProfileContext.Data m_ToolTipDataEvent = null;
private ProfileEventData.ProfileContext.SleepEvent m_SleepToolTip = null;
private HashSet<string> m_FilteredContexts = new HashSet<string>();
// Create a compatible Graphics
private Bitmap m_OffScreenBitmap = null;
private Graphics m_OffScreenGraphics = null;
private bool m_needRedraw = true;
#endregion
public ProfileEventTrace(ProfileEventDoc doc)
{
InitializeComponent();
m_Doc = doc;
m_Data = doc.Data;
Text = doc.Name + " - Trace";
doc.SelectedProfileEventChanged += new EventDelegate(OnSelectedProfileEventChanged);
doc.SelectedDataEventChanged += new EventDelegate(OnSelectedDataEventChanged);
ShowTimeLine = false;
ShowSecondaryTimeLineMarkers = true;
// set the time start to the extent
TimeExtent extent = m_Data.TimeExtent;
m_View.ViewChanged += new View.ViewChangedHandler(m_View_ViewChanged);
m_View.ZoomToAbsolute(extent.Min, extent.Max);
Redraw();
this.MouseWheel += new MouseEventHandler(ProfileEventsViewer_MouseWheel);
m_Summary = new Summary(this);
m_TaskGraph = null;
engineFrameDelimiterPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
graphicFrameDelimiterPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
eventToolTip.UseFading = false;
}
public ProfileEventDoc Doc
{
get { return m_Doc; }
}
public ProfileEventData Data
{
get { return m_Data; }
}
public Summary Summary
{
get { return m_Summary; }
}
public TaskGraph TaskGraph
{
get { return m_TaskGraph; }
set { m_TaskGraph = value; }
}
public bool ShowThreadInfo
{
get { return m_ShowThreadInfo; }
set
{
m_ShowThreadInfo = value;
Redraw();
}
}
public bool ShowThreadInfoContexts
{
get { return m_ShowThreadInfoContexts; }
set
{
m_ShowThreadInfoContexts = value;
Redraw();
}
}
public bool ShowTimeLine
{
get { return m_ShowTimeLine; }
set
{
m_ShowTimeLine = value;
Redraw();
}
}
public bool ShowSecondaryTimeLineMarkers
{
get { return m_ShowSecondaryTimeLineMarkers; }
set
{
m_ShowSecondaryTimeLineMarkers = value;
Redraw();
}
}
public bool HasSelection { get { return m_RangeEnd - m_RangeStart > 0; } }
public bool HasProfileEventSelection { get { return m_SelectedProfileEvent != null; } }
public bool HasDataEventSelection { get { return m_SelectedDataEvent != null; } }
public Hashtable SelectionTimes
{
get { return m_SelectionTimes; }
}
private Time ConvertXToTime(int x)
{
Time timeStepPerPixel = TimeStepPerPixel();
return (Time)((x * timeStepPerPixel) + m_View.TimeStart);
}
private Int64 ConvertTimeToXForDrawing(Time time)
{
Time timeStepPerPixel = TimeStepPerPixel();
// Allow 10 pixels outside the bounds of the screen
Time clampedTime = Math.Min(Math.Max(time, m_View.TimeStart - 10 * timeStepPerPixel), m_View.TimeEnd + 10 * timeStepPerPixel);
return (Int64)((clampedTime - m_View.TimeStart) / timeStepPerPixel);
}
private Int64 ConvertTimeToX(Time time)
{
Time timeStepPerPixel = TimeStepPerPixel();
return (Int64)((time - m_View.TimeStart) / timeStepPerPixel);
}
private bool IsContextShown(ProfileEventData.ProfileContext context)
{
return !context.IsHidden &&
(context.ContainsProfileEvents() || (context.ContainsAnyEvents() && ShowThreadInfoContexts));
}
public ProfileEventData.ProfileContext.Event FindEvent(ProfileEventData.ProfileContext.Event profileEvent, UInt32 profileID, ref int count, ref int depth)
{
// recursive function
if (profileEvent == null)
return null;
if (profileEvent.Inside(m_RangeStart, m_RangeEnd))
{
if (profileEvent.ProfileID == profileID)
--count;
if (count == 0)
{
depth = 1;
return profileEvent;
}
if (profileEvent.Child != null)
{
ProfileEventData.ProfileContext.Event child = profileEvent.Child;
while (child != null)
{
ProfileEventData.ProfileContext.Event candidate = FindEvent(child, profileID, ref count, ref depth);
if (candidate != null)
{
++depth;
return candidate;
}
child = child.Sibling;
}
}
}
return null;
}
private bool TryGetProfileIDFromEventName(string itemName, out UInt32 profileID)
{
profileID = 0;
foreach (UInt32 id in m_Data.Profiles.Keys)
{
ProfileEventData.ProfileDesc desc = (ProfileEventData.ProfileDesc)m_Data.Profiles[id];
if (desc.Name == itemName)
{
profileID = id;
return true;
}
}
return false;
}
private bool TryGetEventFromIdAndCount(UInt32 itemId, int clickCount, out ProfileEventData.ProfileContext.Event targetEvent, out int yOffset, out int depth)
{
targetEvent = null;
yOffset = m_YOffset;
depth = 0;
//UInt32 profileID = 0;
//if (!TryGetProfileIDFromEventName(itemName, out profileID))
// return false;
UInt32 profileID = itemId;
// from the profile ID, find occurrences of the event
int count = clickCount;
do
{
int contextmaxy = 0;
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
int contextStart;
bool isContextFiltered = m_FilteredContexts.Contains(context.Name);
if (!IsContextShown(context) || isContextFiltered)
continue;
contextmaxy += TitleHeight;
contextStart = contextmaxy;
contextmaxy += (context.VisibleLevelCount * EventHeight);
foreach (ProfileEventData.ProfileContext.Event profileEvent in context.Heads)
{
targetEvent = FindEvent(profileEvent, profileID, ref count, ref depth);
if (targetEvent != null)
{
yOffset = contextStart + TitleHeight + (depth - 1) * EventHeight;
return true;
}
}
}
} while (count < clickCount);
return false;
}
private void ShowEventToolTip(ProfileEventData.ProfileContext.Event target, int yOffset)
{
string itemName = ((ProfileEventData.ProfileDesc)m_Data.Profiles[target.ProfileID]).Name;
string toolTipString;
if (target.Task != null)
{
eventToolTip.ToolTipTitle = String.Format("{0} - Task: {1}", itemName, target.Task.Desc.Name);
toolTipString = String.Format("Event time {0}\nTotal task time: {1}", TimeToString(target.Length), TimeToString(target.Task.TotalTime));
if (target.Task.PreTasks.Count > 0)
{
toolTipString += "\n\nPre Tasks:\n";
foreach (ProfileEventData.TaskInstance instance in target.Task.PreTasks)
{
toolTipString += String.Format("{0}\n", instance.Desc.Name);
}
}
if (target.Task.PostTasks.Count > 0)
{
toolTipString += "\nPost Tasks:\n";
foreach (ProfileEventData.TaskInstance instance in target.Task.PostTasks)
{
toolTipString += String.Format("{0}\n", instance.Desc.Name);
}
toolTipString += "\n";
}
}
else
{
eventToolTip.ToolTipTitle = itemName;
toolTipString = TimeToString(target.Length);
}
m_ToolTipEvent = target;
m_ToolTipDataEvent = null;
m_SleepToolTip = null;
eventToolTip.InitialDelay = 0;
eventToolTip.AutoPopDelay = 100000;
eventToolTip.ShowAlways = true;
eventToolTip.Active = true;
eventToolTip.BackColor = m_Data.GetProfileColor(target.ProfileID);
eventToolTip.SetToolTip(this, toolTipString);
eventToolTip.Show(toolTipString, this, (int)ConvertTimeToX((m_View.TimeStart + m_View.TimeEnd) / 2), m_YOffset + yOffset - EventHeight / 2);
}
private void CenterViewVerticallyOnOffset(int yOffset)
{
m_YOffset = ClientSize.Height / 2 - yOffset;
}
public void CenterViewOnItem(UInt32 itemId, int clickCount)
{
ProfileEventData.ProfileContext.Event target;
int yOffset, depth;
if (!TryGetEventFromIdAndCount(itemId, clickCount, out target, out yOffset, out depth))
return;
Time time = target.Time + target.Length / 2;
m_View.CenterOnLocation(time);
if (target.Context.VisibleLevelCount < depth)
target.Context.VisibleLevelCount = depth;
CenterViewVerticallyOnOffset(yOffset);
ShowEventToolTip(target, yOffset);
Redraw();
}
private void ZoomOnEvent(ProfileEventData.ProfileContext.Event target)
{
if (target == null)
return;
m_View.ZoomToAbsolute(target.Time - target.Length / 20, target.EndTime + target.Length / 20);
m_View.CenterOnLocation(target.Time + (Time)(target.EndTime - target.Time) / 2); // Center on location if zoom is too small
}
public void ZoomViewOnItem(UInt32 itemId, int clickCount)
{
ProfileEventData.ProfileContext.Event target;
int yOffset, depth;
if (!TryGetEventFromIdAndCount(itemId, clickCount, out target, out yOffset, out depth))
return;
ZoomOnEvent(target);
if (target.Context.VisibleLevelCount < depth )
target.Context.VisibleLevelCount = depth ;
CenterViewVerticallyOnOffset(yOffset);
ShowEventToolTip(target, yOffset);
Redraw();
}
private void ProfileEventTrace_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
ProfileEventData.ProfileContext.Data clickedDataEvent = null;
ProfileEventData.ProfileContext.Event clickedProfileEvent = GetEventFromMousePosition(m_LastX, m_LastY);
if (clickedProfileEvent == null)
{
clickedDataEvent = GetDataEventFromMousePosition(m_LastX, m_LastY);
if (clickedDataEvent == null)
{
bool ctrlIsDown = (Control.ModifierKeys & Keys.Control) == Keys.Control;
// Handle context plus/minus buttons
int yOffset = m_YOffset;
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
if (!IsContextShown(context))
continue;
Rectangle rectButtonMinus = new Rectangle(2, yOffset + 2, 11, 11);
Rectangle rectButtonPlus = new Rectangle(2, yOffset + 17, 11, 11);
if (rectButtonMinus.Contains(m_LastX, m_LastY))
{
if (!ctrlIsDown)
--context.VisibleLevelCount;
else
context.VisibleLevelCount = 0;
Redraw();
return;
}
if (rectButtonPlus.Contains(m_LastX, m_LastY))
{
if (!ctrlIsDown)
++context.VisibleLevelCount;
else
context.VisibleLevelCount = context.MaxLevel + 1;
Redraw();
return;
}
yOffset += TitleHeight + (context.VisibleLevelCount * EventHeight);
}
}
}
m_Doc.SelectedProfileEvent = clickedProfileEvent;
m_Doc.SelectedDataEvent = clickedDataEvent;
}
private void ProfileEventTrace_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
ProfileEventData.ProfileContext.Event targetEvent = GetEventFromMousePosition(m_LastX, m_LastY);
if (targetEvent != null)
{
bool ctrlIsDown = (Control.ModifierKeys & Keys.Control) == Keys.Control;
if (!ctrlIsDown)
{
// Double click: change profile event filter
string profileName = m_Data.GetProfileName(targetEvent.ProfileID);
string newFilterName = string.Format(@"""{0}""", profileName);
if (m_Filters.OriginalFilter != newFilterName)
SetEventsFilterString(newFilterName);
else
SetEventsFilterString(string.Empty);
}
else
{
// Ctrl + Double click: change selection range to targeted event's range
// Ctrl + Shift + Double click: extend selection range to include targeted event's range
bool shiftIsDown = (Control.ModifierKeys & Keys.Shift) == Keys.Shift;
bool extendSelection = shiftIsDown;
m_Doc.SelectedProfileEvent = targetEvent;
AdjustRangeToSelectedEvent(extendSelection);
}
}
}
void ProfileEventsViewer_MouseWheel(object sender, MouseEventArgs e)
{
Time timeStepPerPixel = TimeStepPerPixel();
Time timeDx = (timeStepPerPixel);
// Cap the delta, so that we don't zoom in too much
const int MAX_DELTA = 240;
const int MIN_DELTA = -360; // It's longer to unzoom than to zoom...
int delta = Math.Max(Math.Min(e.Delta, MAX_DELTA), MIN_DELTA);
Time location = ConvertXToTime(e.X);
if (Control.ModifierKeys == Keys.Shift)
{
m_View.ZoomOnTime(location, timeDx * (delta / 10));
}
else
{
m_View.ZoomOnTime(location, timeDx * delta);
}
Redraw();
}
private void ProfileEventsViewer_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
m_LastX = e.X;
m_LastY = e.Y;
bool shiftIsDown = (Control.ModifierKeys & Keys.Shift) == Keys.Shift;
bool ctrlIsDown = (Control.ModifierKeys & Keys.Control) == Keys.Control;
if (e.Button == MouseButtons.Left)
{
if (shiftIsDown)
{
m_MouseMode = MouseMode.Pan;
Cursor = Cursors.NoMove2D;
Capture = true;
}
else if (ctrlIsDown)
{
m_FocusTime = ConvertXToTime(e.X);
m_MouseMode = MouseMode.ZoomOnLocation;
Cursor = Cursors.NoMoveHoriz;
Capture = true;
}
}
if (e.Button == MouseButtons.Middle)
{
m_MouseMode = MouseMode.Pan;
Cursor = Cursors.NoMove2D;
Capture = true;
}
if (e.Button == MouseButtons.Right)
{
Capture = true;
if (!ctrlIsDown)
{
m_MouseMode = MouseMode.MarkRange;
Cursor = Cursors.NoMoveHoriz;
if (!shiftIsDown || m_RangeStart == m_RangeEnd) // Create new selection
{
m_RangeStart = ConvertXToTime(e.X);
m_RangeEnd = m_RangeStart;
m_FocusTime = m_RangeStart;
}
else // Extend selection
{
Time clickTime = ConvertXToTime(e.X);
if (clickTime < m_RangeStart)
{
m_FocusTime = m_RangeEnd;
m_RangeStart = clickTime;
}
else
{
m_FocusTime = m_RangeStart;
m_RangeEnd = clickTime;
}
}
FireSelectionChanged(false, true);
}
else
{
// Select contexts.
m_MouseMode = MouseMode.SelectContexts;
Cursor = Cursors.NoMoveVert;
m_SelectContextStartYOffset = e.Y - m_YOffset;
m_SelectContextEndYOffset = m_SelectContextStartYOffset;
}
Redraw();
}
}
private void OnSelectedProfileEventChanged(ProfileEventDoc doc)
{
if (m_SelectedProfileEvent != doc.SelectedProfileEvent)
{
m_SelectedProfileEvent = m_Doc.SelectedProfileEvent;
Redraw();
}
}
private void OnSelectedDataEventChanged(ProfileEventDoc doc)
{
if (m_SelectedDataEvent != doc.SelectedDataEvent)
{
m_SelectedDataEvent = m_Doc.SelectedDataEvent;
Redraw();
}
}
private void ProfileEventsViewer_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
MouseMode oldMouseMode = m_MouseMode;
m_MouseMode = MouseMode.None;
Cursor = Cursors.Default;
Capture = false;
if (oldMouseMode == MouseMode.MarkRange)
{
FireSelectionChanged(true, true);
}
else if (oldMouseMode == MouseMode.SelectContexts)
{
SelectContextsInYRange(m_SelectContextStartYOffset, m_SelectContextEndYOffset, true);
m_SelectContextStartYOffset = m_SelectContextEndYOffset;
Redraw();
}
}
private void ProfileEventsViewer_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
int dx = e.X - m_LastX;
int dy = e.Y - m_LastY;
m_LastX = e.X;
m_LastY = e.Y;
// return if nothing to do
if (dx == 0 && dy == 0)
return;
// Handle tooltips
if (m_MouseMode == MouseMode.None)
{
ProfileEventData.ProfileContext.Event profileEvent = GetEventFromMousePosition(m_LastX, m_LastY);
// draw a tooltip
if (profileEvent != null)
{
if (m_ToolTipEvent != profileEvent)
{
string toolTipString;
if (profileEvent.Task != null)
{
eventToolTip.ToolTipTitle = String.Format("{0} - Task: {1}", m_Data.GetProfileName(profileEvent.ProfileID), profileEvent.Task.Desc.Name);
toolTipString = String.Format("Event time {0}\nTotal task time: {1}", TimeToString(profileEvent.Length), TimeToString(profileEvent.Task.TotalTime));
if (profileEvent.Task.PreTasks.Count > 0)
{
toolTipString += "\n\nPre Tasks:\n";
foreach (ProfileEventData.TaskInstance instance in profileEvent.Task.PreTasks)
{
toolTipString += String.Format("{0}\n", instance.Desc.Name);
}
}
if (profileEvent.Task.PostTasks.Count > 0)
{
toolTipString += "\nPost Tasks:\n";
foreach (ProfileEventData.TaskInstance instance in profileEvent.Task.PostTasks)
{
toolTipString += String.Format("{0}\n", instance.Desc.Name);
}
toolTipString += "\n";
}
}
else
{
eventToolTip.ToolTipTitle = m_Data.GetProfileName(profileEvent.ProfileID);
toolTipString = TimeToString(profileEvent.Length);
}
m_ToolTipEvent = profileEvent;
m_ToolTipDataEvent = null;
m_SleepToolTip = null;
eventToolTip.InitialDelay = 0;
eventToolTip.AutoPopDelay = 100000;
eventToolTip.ShowAlways = true;
eventToolTip.Active = true;
eventToolTip.BackColor = m_Data.GetProfileColor(profileEvent.ProfileID);
eventToolTip.SetToolTip(this, toolTipString);
}
}
else
{
ProfileEventData.ProfileContext.Data dataEvent = GetDataEventFromMousePosition(m_LastX, m_LastY);
if (dataEvent != null)
{
if (m_ToolTipDataEvent != dataEvent)
{
eventToolTip.ToolTipTitle = "";
m_ToolTipEvent = null;
m_ToolTipDataEvent = dataEvent;
m_SleepToolTip = null;
eventToolTip.InitialDelay = 0;
eventToolTip.AutoPopDelay = 100000;
eventToolTip.ShowAlways = true;
eventToolTip.Active = true;
eventToolTip.BackColor = Color.Yellow;
eventToolTip.SetToolTip(this, dataEvent.m_String);
}
}
else
{
ProfileEventData.ProfileContext.SleepEvent sleepEvent = GetSleepEventFromMousePosition(m_LastX, m_LastY);
if (sleepEvent != null && ShowThreadInfo)
{
if(sleepEvent != m_SleepToolTip)
{
// find the ThreadSwitchEvents related to this sleep event..
String ContextTo = "Unknown (Lock?)";
String ContextFrom = "Unknown (Unlock?)";
for (int i = 0; i < m_Data.ThreadSwitchs.Count; i++)
{
if (sleepEvent.m_Start == m_Data.ThreadSwitchs[i].m_Time)
{
// find the Context to which this thread switched to...
foreach (ProfileEventData.ProfileContext loopcontext in m_Data.Contexts.Values)
if (loopcontext.OsThreadID == m_Data.ThreadSwitchs[i].m_newThreadID && loopcontext.OsThreadID != 0)
ContextTo = loopcontext.Name;
}
if (sleepEvent.m_End == m_Data.ThreadSwitchs[i].m_Time)
{
// find the Context to which this thread switched from...
foreach (ProfileEventData.ProfileContext loopcontext2 in m_Data.Contexts.Values)
if (loopcontext2.OsThreadID == m_Data.ThreadSwitchs[i].m_oldThreadID && loopcontext2.OsThreadID != 0)
ContextFrom = loopcontext2.Name;
}
}
eventToolTip.ToolTipTitle = String.Format("This thread is IDLE: ");
m_ToolTipEvent = null;
m_ToolTipDataEvent = null;
m_SleepToolTip = sleepEvent;
eventToolTip.InitialDelay = 0;
eventToolTip.AutoPopDelay = 100000;
eventToolTip.ShowAlways = true;
eventToolTip.Active = true;
eventToolTip.BackColor = Color.Yellow;
String ToolTipText = String.Format("The thread switched to : {0}\nAnd then switched back from : {1}.", ContextTo, ContextFrom);
eventToolTip.SetToolTip(this, ToolTipText);
}
}
else
{
m_ToolTipEvent = null;
m_ToolTipDataEvent = null;
m_SleepToolTip = null;
eventToolTip.Active = false;
}
}
}
return;
}
else
{
m_ToolTipEvent = null;
m_ToolTipDataEvent = null;
m_SleepToolTip = null;
eventToolTip.Active = false;
}
// get window width
Time timeStepPerPixel = TimeStepPerPixel();
Time timeDx = (timeStepPerPixel * dx);
switch (m_MouseMode)
{
case MouseMode.Pan:
m_View.Pan(-timeDx);
m_YOffset += dy;
WrapAround(e.X, e.Y, dx, dy);
break;
case MouseMode.ZoomOnLocation:
m_View.ZoomOnTime(m_FocusTime, timeDx);
WrapAround(e.X, e.Y, dx, dy);
break;
case MouseMode.MarkRange:
Time currentSelectedTime = ConvertXToTime(e.X);
if (currentSelectedTime < m_FocusTime)
{
m_RangeEnd = m_FocusTime;
m_RangeStart = currentSelectedTime;
}
else
{
m_RangeStart = m_FocusTime;
m_RangeEnd = currentSelectedTime;
}
FireSelectionChanged(false, true);
break;
case MouseMode.SelectContexts:
m_SelectContextEndYOffset = e.Y - m_YOffset;
SelectContextsInYRange(m_SelectContextStartYOffset, m_SelectContextEndYOffset, false);
break;
}
Redraw();
}
private void SelectContextsInYRange(int startYRange, int endYRange, bool applyFilterChanges)
{
// If the range is empty, clear the selection
if (startYRange == endYRange)
{
m_FilteredContexts.Clear();
}
else
{
int start = Math.Min(startYRange, endYRange);
int end = Math.Max(startYRange, endYRange);
int currentYOffset = 0;
// Find overlapping contexts.
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
if (!IsContextShown(context))
continue;
int contextStart = currentYOffset;
int contextEnd = contextStart + TitleHeight + (context.VisibleLevelCount * EventHeight);
bool overlaps = ((contextStart <= start && start <= contextEnd) ||
(contextStart <= end && end <= contextEnd) ||
(contextStart > start && contextEnd < end));
if (overlaps)
m_FilteredContexts.Remove(context.Name);
else
m_FilteredContexts.Add(context.Name);
currentYOffset = contextEnd;
}
}
if (applyFilterChanges)
{
if (ContextSelectionChanged != null)
ContextSelectionChanged(this, m_FilteredContexts);
ComputeSelectionTimes();
Redraw();
}
}
private void WrapAround(int x, int y, int dx, int dy)
{
int newX = x, newY = y;
if (x > ClientSize.Width)
newX = x % ClientSize.Width;
else if (x < 0)
newX = ClientSize.Width + x % ClientSize.Width;
if (y > ClientSize.Height)
newY = y % ClientSize.Height;
else if (y < 0)
newY = ClientSize.Height + y % ClientSize.Height;
m_LastX = newX;
m_LastY = newY;
if (newX != x || newY != y)
{
Point p = new Point(newX, newY);
Point newMousePos = PointToScreen(p);
Cursor.Position = newMousePos;
}
}
public string TimeToString(Time length)
{
UInt32 frequency = m_Data.GetFrequency();
Time frequencyInUS = ((Time)frequency) / 1000000;
Time lengthInUS = length / frequencyInUS;
if (lengthInUS <= 0)
{
return String.Format("{0} cycles", length);
}
else if (lengthInUS < 500)
{
return String.Format("{0:F3} us", lengthInUS);
}
else if (lengthInUS < 1000000)
{
return String.Format("{0:F2} ms", (lengthInUS / 1000));
}
else
{
return String.Format("{0:F2} s", (lengthInUS / 1000000));
}
}
struct EventScreenInfo
{
public Int64 m_ScreenX;
public Int64 m_ScreenLength;
public Int64 m_ScreenXE;
public Int64 m_ScreenY;
};
private bool ComputeEventScreenInfo(ProfileEventData.ProfileContext.Event profileEvent, ref DrawEventContext drawContext, ref EventScreenInfo info)
{
ProfileEventData.ProfileContext targetContext = profileEvent.Context;
if (targetContext.IsHidden)
return false;
Int64 screenXE = (Int64)ConvertTimeToX(profileEvent.Time + profileEvent.Length);
Int64 screenX = (Int64)ConvertTimeToX(profileEvent.Time);
screenX = Math.Max(-20, screenX);
screenXE = Math.Min(ClientSize.Width + 20, screenXE);
if (screenXE == screenX)
screenXE++;
Int64 screenLength = screenXE - screenX;
info.m_ScreenLength = screenLength;
info.m_ScreenX = screenX;
info.m_ScreenXE = screenXE;
// find the Y
int contextmaxy = (Int32)m_YOffset;
// find which context it's in
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
int contextStart;
if (!IsContextShown(context))
continue;
contextmaxy += TitleHeight;
contextStart = contextmaxy;
contextmaxy += (context.VisibleLevelCount * EventHeight);
if (context == targetContext)
{
info.m_ScreenY = contextStart;
break;
}
}
return true;
}
private void DrawEvent(ProfileEventData.ProfileContext.Event profileEvent, bool isContextFiltered, ref DrawEventContext drawContext, int maxStack)
{
if (maxStack == 0)
return;
if (profileEvent.Inside(m_View.TimeStart, m_View.TimeEnd))
{
// compute screen X size
Int64 screenX = ConvertTimeToX(profileEvent.Time);
Int64 screenXE = ConvertTimeToX(profileEvent.EndTime);
string profileEventName = m_Data.GetProfileName(profileEvent.ProfileID);
bool filteredOut = isContextFiltered;
if (!filteredOut && m_Filters.IsValid)
filteredOut = !m_Filters.IsAllowed(profileEventName);
// compute correct color
Color profileColor = m_Data.GetProfileColor(profileEvent.ProfileID);
if (filteredOut)
profileColor = Color.FromArgb(25, profileColor);
// draw a rectangle
rectBrush.Color = profileColor;
screenX = Math.Max(-20, screenX);
screenXE = Math.Min(ClientSize.Width + 20, screenXE);
if (screenXE == screenX)
screenXE++;
Int64 screenLength = screenXE - screenX;
if (screenLength > 1)
drawContext.Graphics.FillRectangle(rectBrush, screenX, drawContext.m_Y, screenLength, EventHeight);
else if (!m_ShowTinyEvents)
return;
int adjustedIndex = (profileEvent.IsAdjusted ? 1 : 0);
int selectedIndex = (m_SelectedProfileEvent == profileEvent ? 1 : 0);
int filteredIndex = (filteredOut ? 1 : 0);
Pen drawPen = eventPens[adjustedIndex, selectedIndex, filteredIndex];
drawContext.Graphics.DrawRectangle(drawPen, screenX, drawContext.m_Y, screenLength, EventHeight);
// set the clip region and display the profile name (if there's any chance it could fit)
if (screenLength > 20)
{
Region oldClipRegion = drawContext.Graphics.Clip;
drawContext.Graphics.SetClip(new Rectangle((int)screenX + 1, drawContext.m_Y, (int)screenLength - 1, EventHeight));
string profileName = String.Format("{0}{1}, {2}", (screenX < 0) ? "<< " : "", profileEventName, TimeToString(profileEvent.Length));
drawContext.Graphics.DrawString(profileName, barFont, filteredOut ? fontFilteredOutBrush : fontBrush, Math.Max(screenX, 0), drawContext.m_Y);
drawContext.Graphics.Clip = oldClipRegion;
}
// must draw the childs (if we were not too small)
if (profileEvent.Child != null && screenLength > 1 && maxStack > 1)
{
if (m_ShowParentShadow)
drawContext.Graphics.FillRectangle(rangeBrush, screenX, drawContext.m_Y + EventHeight, screenLength, EventHeight);
drawContext.m_Y += EventHeight;
ProfileEventData.ProfileContext.Event child = profileEvent.Child;
while (child != null)
{
DrawEvent(child, isContextFiltered, ref drawContext, maxStack - 1);
child = child.Sibling;
}
drawContext.m_Y -= EventHeight;
}
}
}
private int GetDataEventScreenWidth(ProfileEventData.ProfileContext.Data dataEvent)
{
Time maxTimeLength = dataEvent.GetMaxTimeLength();
int maxWidth = MaxDataEventWidth;
int screenLength = 1;
if (maxTimeLength > 0)
{
Int64 maxScreenWidth = (Int64)(maxTimeLength / TimeStepPerPixel());
if (maxScreenWidth < maxWidth)
maxWidth = (int)maxScreenWidth;
}
if (maxWidth <= 0)
screenLength = 1;
else if (maxWidth > 20)
screenLength = (int)m_OffScreenGraphics.MeasureString(dataEvent.m_String, dataEventFont, maxWidth).Width;
else
screenLength = maxWidth;
return screenLength;
}
private void DrawDataEvent(ProfileEventData.ProfileContext.Data dataEvent, bool isContextFiltered, ref DrawEventContext drawContext)
{
if (dataEvent.Inside(m_View.TimeStart, m_View.TimeEnd))
{
int eventY = drawContext.m_Y - EventHeight;
int gapHeight = 5;
int eventHeight = EventHeight - gapHeight;
// compute screen X size
Int64 screenX = ConvertTimeToX(dataEvent.m_Time);
Int64 screenLength = GetDataEventScreenWidth(dataEvent);
Int64 screenXE = screenX + screenLength;
// draw a data event poly
// 1___________2
// | __________|
// 5|/4 3
//
bool filteredOut = isContextFiltered;
if (!filteredOut && m_Filters.IsValid)
filteredOut = !m_Filters.IsAllowed(dataEvent.m_String);
rectBrush.Color = (filteredOut ? FilteredDataEventColor : DataEventColor);
screenX = Math.Max(-20, screenX);
screenXE = Math.Min(ClientSize.Width + 20, screenXE);
screenLength = screenXE - screenX;
Point[] eventPoly = {
new Point((int)screenX, eventY),
new Point((int)screenX+(int)screenLength, eventY),
new Point((int)screenX+(int)screenLength, eventY+eventHeight),
new Point((int)screenX+gapHeight, eventY+eventHeight),
new Point((int)screenX, eventY+eventHeight+gapHeight),
};
if (screenLength > 1)
drawContext.Graphics.FillPolygon(rectBrush, eventPoly);
int adjustedIndex = 0; // Data events are never adjusted
int selectedIndex = (m_SelectedDataEvent == dataEvent ? 1 : 0);
int filteredIndex = (filteredOut ? 1 : 0);
Pen drawPen = eventPens[adjustedIndex, selectedIndex, filteredIndex];
drawContext.Graphics.DrawPolygon(drawPen, eventPoly);
// set the clip region and display the profile name (if there's any chance it could fit)
if (screenLength > 20)
{
Region oldClipRegion = drawContext.Graphics.Clip;
drawContext.Graphics.SetClip(new Rectangle((int)screenX + 1, eventY, (int)screenLength - 1, EventHeight));
drawContext.Graphics.DrawString(dataEvent.m_String, dataEventFont, filteredOut ? fontFilteredOutBrush : fontBrush, Math.Max(screenX, 0), eventY);
drawContext.Graphics.Clip = oldClipRegion;
}
}
}
void HightLightEvent(ProfileEventData.ProfileContext.Event forEvent, Color color, ref DrawEventContext drawContext)
{
if (forEvent == null)
return;
// Locate the event screen coordinates
EventScreenInfo info = new EventScreenInfo();
if (ComputeEventScreenInfo(forEvent, ref drawContext, ref info))
{
// Draw rectangle
highlightPen.Color = color;
drawContext.Graphics.DrawRectangle(highlightPen, info.m_ScreenX, info.m_ScreenY, info.m_ScreenLength, EventHeight);
}
}
void HightLightTaskInstance(ProfileEventData.TaskInstance taskInstance, Color color, ref DrawEventContext drawContext)
{
foreach (ProfileEventData.ProfileContext.Event profileEvent in taskInstance.Events)
{
HightLightEvent(profileEvent, color, ref drawContext);
}
}
void DrawLinkedTasks(ProfileEventData.TaskInstance taskInstance, ref DrawEventContext drawContext, bool preTasks)
{
List<ProfileEventData.TaskInstance> instanceList = taskInstance.PostTasks;
Color color = Color.Green;
if (preTasks)
{
instanceList = taskInstance.PreTasks;
color = Color.Red;
}
foreach (ProfileEventData.TaskInstance task in instanceList)
{
if (task.Events.Count > 0)
HightLightTaskInstance(task, color, ref drawContext);
else
// probably a node task follow the node to the next task
DrawLinkedTasks(task, ref drawContext, preTasks);
}
}
void DrawTaskLinks(ProfileEventData.ProfileContext.Event forEvent, ref DrawEventContext drawContext)
{
ProfileEventData.TaskInstance instance = forEvent.Task;
if (instance != null)
{
// highlight the selected event
HightLightTaskInstance(instance, Color.Blue, ref drawContext);
DrawLinkedTasks(instance, ref drawContext, true);
DrawLinkedTasks(instance, ref drawContext, false);
}
}
private void DrawThreadSwitch(ref DrawEventContext drawContext)
{
const Int32 trisizeX = 5;
const Int32 trisizeY = 10;
const float MaxThreadSwitchInView = 500.0F;
if (ShowThreadInfo)
{
// Draw Thread Switch
Int32 X = 0;
Int32 oldX = -1;
List<Int32>ThreadSwitchX = new List<Int32>();
foreach (ThreadSwitch ts in m_Data.ThreadSwitchs)
{
X = (Int32)ConvertTimeToX((Time)ts.m_Time);
if (X < ClientSize.Width && X > 0)
ThreadSwitchX.Add(X);
}
if(ThreadSwitchX.Count < MaxThreadSwitchInView && ThreadSwitchX.Count > 0)
{
double alpha = ((1.0 - (ThreadSwitchX.Count / MaxThreadSwitchInView)) * 128.0);
alpha /= (1 + ((128.0 - alpha) / 5));
tspen.Color = Color.FromArgb((int)alpha, Color.Black);
// tspen.DashPattern = new float[] { 1.0F, 2.0F };
tspen2.Color = Color.FromArgb((int)alpha, Color.Black);
Point p1 = new Point(0, drawContext.m_Y - 15);
Point p2 = new Point(0, ClientSize.Height - 1);
foreach (int x in ThreadSwitchX)
{
p1.X = x;
// tspen.DashOffset = p1.X % 3;
if (oldX != p1.X)
{
p2.X = p1.X;
oldX = p1.X;
drawContext.Graphics.DrawLine(tspen, p1, p2);
drawContext.Graphics.DrawLine(tspen2, p1.X - trisizeX, p1.Y - trisizeY, p1.X, p1.Y);
drawContext.Graphics.DrawLine(tspen2, p1.X + trisizeX, p1.Y - trisizeY, p1.X, p1.Y);
drawContext.Graphics.DrawLine(tspen2, p1.X - trisizeX, p1.Y - trisizeY, p1.X + trisizeX, p1.Y - trisizeY);
}
}
}
// End thread switch draw...
}
}
void DrawSleepEvent(ProfileEventData.ProfileContext.SleepEvent sleep, bool isContextFiltered, ref DrawEventContext drawContext, int numContextLevel)
{
if (ShowThreadInfo)
{
Int32 Height = numContextLevel * EventHeight;
Int32 screenY = drawContext.m_Y + (EventHeight * 1 / 2);
Int32 textScreenY;
if (Height > EventHeight)
{
Height -= EventHeight;
textScreenY = screenY + (Height - EventHeight) / 2;
}
else
{
screenY = drawContext.m_Y;
textScreenY = screenY;
}
Int32 screenX = (Int32)ConvertTimeToX(sleep.m_Start);
Int32 screenXE = (Int32)ConvertTimeToX(sleep.m_End);
screenX = Math.Max(-20, screenX);
screenXE = Math.Min(ClientSize.Width + 20, screenXE);
Int32 screenLength = screenXE - screenX;
if (screenX > ClientSize.Width || screenXE < 0)
return;
Rectangle rect = new Rectangle(screenX, screenY, screenXE - screenX, Height);
// draw a rectangle
if (screenLength > 1)
drawContext.Graphics.FillRectangle(isContextFiltered ? filteredOutSleepBrush : sleepBrush, rect);
drawContext.Graphics.DrawRectangle(isContextFiltered ? filteredOutSleepPen : sleepPen, rect);
// set the clip region and display the profile name (if there's any chance it could fit)
if (screenLength > 20)
{
Region oldClipRegion = drawContext.Graphics.Clip;
drawContext.Graphics.SetClip(new Rectangle((int)screenX + 1, textScreenY, (int)screenXE - screenX - 1, Height));
string sleepInfo = String.Format("{0}{1}, {2}", (screenX < 0) ? "<< " : "", "Idle", TimeToString(sleep.m_End - sleep.m_Start));
drawContext.Graphics.DrawString(sleepInfo, barFont, isContextFiltered ? filteredOutSleepFontBrush : sleepFontBrush, Math.Max(screenX, 0), textScreenY);
drawContext.Graphics.Clip = oldClipRegion;
}
}
}
void DrawAwakeEvent(ProfileEventData.ProfileContext.SleepEvent awake, bool isContextFiltered, ref DrawEventContext drawContext, int numContextLevel)
{
if (numContextLevel == 0)
return;
//if (ShowThreadInfo)
{
Int32 Height = EventHeight;
Int32 screenY = drawContext.m_Y;
Int32 screenX = (Int32)ConvertTimeToX(awake.m_Start);
Int32 screenXE = (Int32)ConvertTimeToX(awake.m_End);
screenX = Math.Max(-20, screenX);
screenXE = Math.Min(ClientSize.Width + 20, screenXE);
if (screenX > ClientSize.Width || screenXE < 0)
return;
Int32 screenLength = screenXE - screenX;
Rectangle rect = new Rectangle(screenX, screenY, screenLength, Height);
// draw a rectangle
if (screenLength > 1)
drawContext.Graphics.FillRectangle(isContextFiltered ? filteredOutAwakeBrush : awakeBrush, rect);
drawContext.Graphics.DrawRectangle(isContextFiltered ? filteredOutAwakePen : awakePen, rect);
// set the clip region and display the profile name (if there's any chance it could fit)
if (screenLength > 20)
{
Region oldClipRegion = drawContext.Graphics.Clip;
drawContext.Graphics.SetClip(new Rectangle((int)screenX + 1, screenY, (int)screenXE - screenX - 1, Height));
string awakeInfo = String.Format("{0}{1}, {2}", (screenX < 0) ? "<< " : "", "Working", TimeToString(awake.m_End - awake.m_Start));
drawContext.Graphics.DrawString(awakeInfo, barFont, isContextFiltered ? fontFilteredOutBrush : fontBrush, Math.Max(screenX, 0), screenY);
drawContext.Graphics.Clip = oldClipRegion;
}
}
}
Time FindNextTimeMarker(Time startTime, Time timeStep)
{
return FindNextTimeMarker(startTime, timeStep, true);
}
Time FindNextTimeMarker(Time startTime, Time timeStep, bool ahead)
{
return Math.Floor((startTime / timeStep) + (ahead ? 1 : 0)) * timeStep;
}
IEnumerable<Time> GetTimeMarkers(double deltaExp, Time multiplier)
{
Time timeStepPerPixel = TimeStepPerPixel();
Time markerTimeStep = (Time)Math.Pow(10.0, Math.Floor(Math.Log10((double)timeStepPerPixel)) + deltaExp) * multiplier;
// Return at least one marker before the screen
yield return FindNextTimeMarker(ConvertXToTime(0), markerTimeStep, false);
Time nextTime = FindNextTimeMarker(ConvertXToTime(0), markerTimeStep);
while (ConvertTimeToX(nextTime) < ClientSize.Width)
{
yield return nextTime;
nextTime = FindNextTimeMarker(nextTime, markerTimeStep);
};
// Return at least one marker after the screen
yield return nextTime;
}
IEnumerable<Time> GetPrimaryTimeMarkers()
{
return GetTimeMarkers(2, 5);
}
IEnumerable<Time> GetSecondaryTimeMarkers()
{
return GetTimeMarkers(2, 1);
}
void DrawTimeLine(ref DrawEventContext drawContext)
{
List<Time> primaryMarkers = GetPrimaryTimeMarkers().ToList();
foreach (Time primaryMarker in primaryMarkers)
{
int screenX = (int)ConvertTimeToX(primaryMarker);
drawContext.Graphics.DrawLine(timeLinePrimaryPen, screenX, 0, screenX, ClientSize.Height);
}
if (ShowSecondaryTimeLineMarkers)
{
foreach (Time primaryMarker in GetSecondaryTimeMarkers())
{
int screenX = (int)ConvertTimeToX(primaryMarker);
drawContext.Graphics.DrawLine(timeLineSecondaryPen, screenX, 0, screenX, ClientSize.Height);
}
}
string scaleLabelStr = "Distance between primary markers";
string scaleStr = TimeToString(primaryMarkers[1] - primaryMarkers[0]);
float scaleLabelWidth = drawContext.Graphics.MeasureString(scaleLabelStr, timeLineFont).Width;
float scaleWidth = drawContext.Graphics.MeasureString(scaleStr, timeLineFont).Width;
drawContext.Graphics.DrawString(scaleLabelStr, timeLineFont, timeLineBrush, ClientSize.Width - scaleLabelWidth, ClientSize.Height - 2 * EventHeight);
drawContext.Graphics.DrawString(scaleStr, timeLineFont, timeLineBrush, ClientSize.Width - scaleWidth, ClientSize.Height - EventHeight);
}
void UpdateOffscreenSurface()
{
if (m_OffScreenBitmap != null)
m_OffScreenBitmap.Dispose();
if (m_OffScreenGraphics != null)
m_OffScreenGraphics.Dispose();
if (ClientSize.Width != 0 && ClientSize.Height != 0)
{
m_OffScreenBitmap = new Bitmap(ClientSize.Width, ClientSize.Height);
m_OffScreenGraphics = Graphics.FromImage(m_OffScreenBitmap);
m_needRedraw = true;
}
}
protected override void OnLostFocus(EventArgs e)
{
m_ToolTipEvent = null;
m_ToolTipDataEvent = null;
m_SleepToolTip = null;
eventToolTip.Active = false;
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do not paint background once we've loaded data
if (m_Data == null)
{
base.OnPaintBackground(pevent);
}
}
private ProfileEventData.ProfileContext.Event GetEventFromMousePositionInContext(FindEventContext findContext, ProfileEventData.ProfileContext.Event profileEvent)
{
if (findContext.Time >= profileEvent.Time &&
findContext.Time <= profileEvent.EndTime)
{
// could be in this one, if the depth is good
if (findContext.TargetDepth == profileEvent.Level)
{
return profileEvent;
}
// depth isn't correct, search the childs
if (profileEvent.Child != null)
{
ProfileEventData.ProfileContext.Event child = profileEvent.Child;
while (child != null)
{
profileEvent = GetEventFromMousePositionInContext(findContext, child);
if (profileEvent != null)
return profileEvent;
child = child.Sibling;
}
}
}
return null;
}
private ProfileEventData.ProfileContext.Event GetEventFromMousePosition(int x, int y)
{
if (x < 0 || x > ClientSize.Width || m_Data == null)
return null;
int contextmaxy = (Int32)m_YOffset;
FindEventContext findContext = new FindEventContext();
// We add half a pixel to get the time in the middle of a pixel, so a 2 pixels tasks can be pointed onto more easily
findContext.Time = (((Time)x + 0.5) * TimeStepPerPixel()) + m_View.TimeStart;
// find which context it's in
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
int contextStart;
if (!IsContextShown(context))
continue;
contextmaxy += TitleHeight;
contextStart = contextmaxy;
contextmaxy += (context.VisibleLevelCount * EventHeight);
if (y >= contextStart && y < contextmaxy)
{
findContext.TargetDepth = (y - contextStart) / (EventHeight);
foreach (ProfileEventData.ProfileContext.Event profileEvent in context.Heads)
{
ProfileEventData.ProfileContext.Event foundEvent = GetEventFromMousePositionInContext(findContext, profileEvent);
if (foundEvent != null)
return foundEvent;
}
}
contextStart = contextmaxy;
}
return null;
}
private ProfileEventData.ProfileContext.Data GetDataEventFromMousePosition(int x, int y)
{
if (x < 0 || x > ClientSize.Width || m_Data == null)
return null;
Time mouseTime = (((Time)x) * TimeStepPerPixel()) + m_View.TimeStart;
int contextmaxy = (Int32)m_YOffset;
// find which context it's in
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
int contextStart;
if (!IsContextShown(context))
continue;
contextmaxy += TitleHeight;
contextStart = contextmaxy;
contextmaxy += (context.VisibleLevelCount * EventHeight);
if (y >= (contextStart - EventHeight) && y < contextStart)
{
foreach (ProfileEventData.ProfileContext.Data dataEvent in context.DataEvents)
{
if (mouseTime >= dataEvent.m_Time && mouseTime <= dataEvent.HypotheticalEndTime)
{
// Time fits... let's check against what was rendered
Int64 dataEventX = (Int64)((dataEvent.m_Time - m_View.TimeStart) / TimeStepPerPixel());
int screenLength = GetDataEventScreenWidth(dataEvent);
if (x <= (dataEventX + screenLength))
return dataEvent;
}
}
}
contextStart = contextmaxy;
}
return null;
}
private ProfileEventData.ProfileContext.SleepEvent GetSleepEventFromMousePosition(int x, int y)
{
if (x < 0 || x > ClientSize.Width || m_Data == null)
return null;
int contextmaxy = (Int32)m_YOffset;
// find which context it's in
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
int contextStart;
if (!IsContextShown(context))
continue;
contextmaxy += TitleHeight;
contextStart = contextmaxy;
contextmaxy += (context.VisibleLevelCount * EventHeight);
if (y >= contextStart && y < contextmaxy)
{
foreach (ProfileEventData.ProfileContext.SleepEvent sleepEvent in context.SleepEvents)
{
if (x > ConvertTimeToX(sleepEvent.m_Start) && x <= ConvertTimeToX(sleepEvent.m_End))
return sleepEvent;
}
}
contextStart = contextmaxy;
}
return null;
}
private void ComputeContextSelectionTimes(ProfileEventData.ProfileContext.Event profileEvent)
{
if (profileEvent.Inside(m_RangeStart, m_RangeEnd))
{
// Only consider the included time
Time start = profileEvent.Time;
Time end = profileEvent.Time + profileEvent.Length;
if (start < m_RangeStart)
start = m_RangeStart;
if (end > m_RangeEnd)
end = m_RangeEnd;
// Add
// profileEvent.m_ProfileID += end-start;
SelectionInfo oldVal = (SelectionInfo)m_SelectionTimes[profileEvent.ProfileID];
oldVal.m_MinTimeExtent = Math.Min(oldVal.m_MinTimeExtent, start);
oldVal.m_MaxTimeExtent = Math.Max(oldVal.m_MaxTimeExtent, end);
oldVal.m_MinTime = Math.Min(oldVal.m_MinTime, (end - start));
oldVal.m_MaxTime = Math.Max(oldVal.m_MaxTime, (end - start));
oldVal.m_TotalTime += (end - start);
oldVal.m_Calls++;
if (IsAnyContextFilteredOrHidden())
oldVal.m_ClockTime.Merge(start, end);
//m_SelectionTimes[profileEvent.ProfileID] = oldVal;
// Childs
if (profileEvent.Child != null)
{
ProfileEventData.ProfileContext.Event child = profileEvent.Child;
while (child != null)
{
ComputeContextSelectionTimes(child);
child = child.Sibling;
}
}
}
}
public void ComputeSelectionTimes()
{
// Clear the times
m_SelectionTimes.Clear();
// Do nothing if no data or no selection
if (m_Data != null && m_RangeStart != m_RangeEnd)
{
// Pre-enter all the profile ids
foreach (UInt32 id in m_Data.Profiles.Keys)
{
ProfileEventData.ProfileDesc profile = (ProfileEventData.ProfileDesc) m_Data.Profiles[id];
ClockTime clockTime = (!IsAnyContextFilteredOrHidden()) ? profile.ClockTime.GetClockTimeWithinRange(m_RangeStart, m_RangeEnd) : new ClockTime();
m_SelectionTimes.Add(id, new SelectionInfo() { m_ClockTime = clockTime });
}
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
if (context.IsHidden || m_FilteredContexts.Contains(context.Name))
continue;
foreach (ProfileEventData.ProfileContext.Event profileEvent in context.Heads)
{
ComputeContextSelectionTimes(profileEvent);
}
}
// Extra step when some contexts are filtered or hidden
if (IsAnyContextFilteredOrHidden())
foreach (SelectionInfo info in m_SelectionTimes.Values)
info.m_ClockTime.CoalesceResults();
}
if (SelectionTimesChanged != null)
SelectionTimesChanged(this);
}
void FireSelectionChanged(bool markingEnded, bool contentChanged)
{
if (markingEnded && contentChanged)
ComputeSelectionTimes();
if (RangeSelectionChanged != null)
RangeSelectionChanged(this, markingEnded, contentChanged);
}
public void Redraw()
{
m_needRedraw = true;
Invalidate();
}
private void ProfileEventsViewer_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
if (m_Data == null || ClientSize.Width == 0 || ClientSize.Height == 0)
return;
if (m_OffScreenBitmap == null)
UpdateOffscreenSurface();
if (m_needRedraw)
{
Int64 width = ClientSize.Width;
Time timeStepPerPixel = TimeStepPerPixel();
DrawEventContext drawContext = new DrawEventContext();
drawContext.Graphics = m_OffScreenGraphics;
drawContext.Graphics.Clear(SystemColors.Control);
drawContext.m_Y = (Int32)m_YOffset;
// draw the thing
int contextIndex = 0;
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
if (!IsContextShown(context))
continue;
bool isContextFiltered = m_FilteredContexts.Contains(context.Name);
Brush titleBrush = ((contextIndex & 1) == 0) ? contextBackgroundBrushLight : contextBackgroundBrushDark;
Brush textBrush = (isContextFiltered ? fontFilteredOutBrush : fontBrush);
// Print context name
drawContext.Graphics.FillRectangle(titleBrush, 0, drawContext.m_Y, width, (context.VisibleLevelCount * EventHeight) + TitleHeight);
drawContext.Graphics.DrawString(context.Name, contextTitleFont, textBrush, 15, drawContext.m_Y);
Rectangle rectButtonMinus = new Rectangle(2, drawContext.m_Y + 2, 11, 11);
Rectangle rectButtonPlus = new Rectangle(2, drawContext.m_Y + 17, 11, 11);
drawContext.Graphics.FillRectangle(contextButtonBrush, rectButtonMinus);
drawContext.Graphics.FillRectangle(contextButtonBrush, rectButtonPlus);
bool isMinusButtonFiltered = isContextFiltered || (context.VisibleLevelCount == 0);
bool isPlusButtonFiltered = isContextFiltered || (context.VisibleLevelCount == context.MaxLevel + 1);
drawContext.Graphics.DrawRectangle(isMinusButtonFiltered ? rectFilteredOutPen : rectPen, rectButtonMinus);
drawContext.Graphics.DrawRectangle(isPlusButtonFiltered ? rectFilteredOutPen : rectPen, rectButtonPlus);
StringFormat buttonFormat = new StringFormat();
buttonFormat.Alignment = StringAlignment.Center;
buttonFormat.LineAlignment = StringAlignment.Center;
drawContext.Graphics.DrawString("-", barFont, isMinusButtonFiltered ? fontFilteredOutBrush : fontBrush, 8, drawContext.m_Y + 7, buttonFormat);
drawContext.Graphics.DrawString("+", barFont, isPlusButtonFiltered ? fontFilteredOutBrush : fontBrush, 8, drawContext.m_Y + 22, buttonFormat);
drawContext.m_Y += TitleHeight;
drawContext.m_Y += (context.VisibleLevelCount * EventHeight);
contextIndex++;
}
drawContext.m_Y = (Int32)m_YOffset;
contextIndex = 0;
DrawThreadSwitch(ref drawContext);
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
if (!IsContextShown(context))
continue;
bool isContextFiltered = m_FilteredContexts.Contains(context.Name);
drawContext.m_Y += TitleHeight;
int contextHeight = (context.VisibleLevelCount * EventHeight);
if (drawContext.m_Y > ClientSize.Height)
break;
else if (drawContext.m_Y + contextHeight <= 0)
{
drawContext.m_Y += contextHeight;
continue;
}
foreach (ProfileEventData.ProfileContext.Event profileEvent in context.Heads)
{
DrawEvent(profileEvent, isContextFiltered, ref drawContext, context.VisibleLevelCount);
}
foreach (ProfileEventData.ProfileContext.Data dataEvent in context.DataEvents)
{
DrawDataEvent(dataEvent, isContextFiltered, ref drawContext);
}
foreach (ProfileEventData.ProfileContext.SleepEvent sleepEvent in context.SleepEvents)
{
DrawSleepEvent(sleepEvent, isContextFiltered, ref drawContext, context.VisibleLevelCount);
}
if (context.Heads.Count == 0)
{
foreach (ProfileEventData.ProfileContext.SleepEvent awakeEvent in context.AwakeEvents)
{
DrawAwakeEvent(awakeEvent, isContextFiltered, ref drawContext, context.VisibleLevelCount);
}
}
drawContext.m_Y += contextHeight;
contextIndex++;
}
DrawFrameDelimiters(ref drawContext);
Int64 rangeX, rangeXE, rangeWidth;
foreach (ProfileEventData.Frame frame in m_Data.Frames)
{
Time min = frame.Extent.Min;
Time max = frame.Extent.Max;
if (!m_View.IsRangeVisible(min, max))
continue;
rangeX = ConvertTimeToXForDrawing(min);
rangeXE = ConvertTimeToXForDrawing(max);
rangeWidth = rangeXE - rangeX;
Brush brush;
const int height = 17;
RectangleF rect = new RectangleF(rangeX, ClientSize.Height - height, rangeWidth, height);
if (frame.Type == ProfileEventData.Frame.FrameType.Engine)
{
brush = engineFrameBrush;
}
else
{
brush = graphicFrameBrush;
rect.Offset(0, - height);
}
// display the selection range extent
drawContext.Graphics.FillRectangle(brush, rect);
// display range length
StringFormat format = new StringFormat();
format.Trimming = StringTrimming.EllipsisCharacter;
drawContext.Graphics.DrawString(TimeToString(max - min), dataEventFont, whiteFontBrush, rect, format);
}
if (m_SelectedProfileEvent != null)
{
DrawTaskLinks(m_SelectedProfileEvent, ref drawContext);
}
if (m_View.IsRangeVisible(m_RangeStart, m_RangeEnd))
{
// draw the selection range
rangeX = ConvertTimeToXForDrawing(m_RangeStart);
rangeXE = ConvertTimeToXForDrawing(m_RangeEnd);
if (rangeXE == rangeX)
rangeXE++;
rangeWidth = rangeXE - rangeX;
// display the selection range extent
drawContext.Graphics.FillRectangle(rangeBrush, rangeX, 0, rangeWidth, ClientSize.Height);
drawContext.Graphics.DrawString(TimeToString(m_RangeEnd - m_RangeStart), barFont, fontBrush, Math.Max(rangeX, 0), ClientSize.Height - EventHeight);
}
else if (m_RangeStart != m_RangeEnd)
{
// display range length and direction of selection
if (m_RangeEnd < m_View.TimeStart)
{
drawContext.Graphics.DrawString(string.Format("\u25c4 {0}", TimeToString(m_RangeEnd - m_RangeStart)), barFont, fontBrush, 0, ClientSize.Height - EventHeight);
}
else // if (m_RangeStart > m_View.TimeEnd)
{
string selectionLengthStr = string.Format("{0} \u25ba", TimeToString(m_RangeEnd - m_RangeStart));
int strLength = (int)m_OffScreenGraphics.MeasureString(selectionLengthStr, barFont).Width;
drawContext.Graphics.DrawString(selectionLengthStr, barFont, fontBrush, ClientSize.Width - strLength, ClientSize.Height - EventHeight);
}
}
// Draw context selection
if (m_SelectContextStartYOffset != m_SelectContextEndYOffset)
{
int start = Math.Min(m_SelectContextStartYOffset, m_SelectContextEndYOffset) + m_YOffset;
int end = Math.Max(m_SelectContextStartYOffset, m_SelectContextEndYOffset) + m_YOffset;
drawContext.Graphics.FillRectangle(rangeBrush, 0, start, ClientSize.Width, end - start);
}
if (ShowTimeLine)
DrawTimeLine(ref drawContext);
m_needRedraw = false;
}
e.Graphics.DrawImage(m_OffScreenBitmap, 0, 0);
}
private void DrawFrameDelimiters(ref DrawEventContext drawContext)
{
foreach (FrameDelimiter delimiter in m_Data.FrameDelimiters)
{
if (delimiter.Time < m_View.TimeStart)
continue;
if (delimiter.Time > m_View.TimeEnd)
break;
// compute screen X position
Int64 screenX = ConvertTimeToX(delimiter.Time);
if (delimiter.Type == FrameDelimiter.DelimiterType.Engine)
drawContext.Graphics.DrawLine(engineFrameDelimiterPen, screenX, 0, screenX, drawContext.Graphics.VisibleClipBounds.Height);
else if (delimiter.Type == FrameDelimiter.DelimiterType.Graphic)
drawContext.Graphics.DrawLine(graphicFrameDelimiterPen, screenX, 0, screenX, drawContext.Graphics.VisibleClipBounds.Height);
}
}
private void ProfileEventsViewer_MouseEnter(object sender, System.EventArgs e)
{
if (!Capture)
{
m_MouseMode = MouseMode.None;
m_LastX = 0;
m_LastY = 0;
}
}
private void ProfileEventsViewer_Resize(object sender, System.EventArgs e)
{
if (m_Data == null || ClientSize.Width == 0 || ClientSize.Height == 0)
return;
// Cache the time step
m_TimeStepPerPixel = (m_View.TimeEnd - m_View.TimeStart) / ClientSize.Width;
UpdateOffscreenSurface();
Update();
Redraw();
}
public void ZoomExtentAll()
{
m_View.ZoomToAbsolute(m_Data.TimeExtent.Min, m_Data.TimeExtent.Max);
Redraw();
}
public void ZoomExtentSelected()
{
m_View.ZoomToAbsolute(m_RangeStart, m_RangeEnd);
Redraw();
}
public void CopySelectedEventNameToClipboard()
{
if (m_SelectedProfileEvent != null)
{
Clipboard.SetText(m_Data.GetProfileName(m_SelectedProfileEvent.ProfileID));
}
else if (m_SelectedDataEvent != null)
{
Clipboard.SetText(m_SelectedDataEvent.m_String);
}
}
public void SelectAll()
{
m_RangeStart = m_View.TimeStart;
m_RangeEnd = m_View.TimeEnd;
FireSelectionChanged(true, true);
Redraw();
}
public void DeselectAll()
{
m_RangeStart = m_RangeEnd = 0;
FireSelectionChanged(true, true);
Redraw();
}
public void TrimSelection()
{
m_RangeStart = m_SelectionTimes.Values.Cast<SelectionInfo>().Select(info => info.m_MinTimeExtent).Min();
m_RangeEnd = m_SelectionTimes.Values.Cast<SelectionInfo>().Select(info => info.m_MaxTimeExtent).Max();
FireSelectionChanged(true, false);
// No need to recompute selection times, as they shouldn't have changed! :D
Redraw();
}
public void AdjustRangeToSelectedEvent(bool extendSelection)
{
if (m_SelectedProfileEvent == null)
return;
AdjustRangeToEvent(m_SelectedProfileEvent, extendSelection);
}
public void AdjustRangeToEvent(ProfileEventData.ProfileContext.Event targetEvent, bool extendSelection)
{
bool timeChanged = !extendSelection;
if (!extendSelection || m_RangeStart == m_RangeEnd)
{
m_RangeStart = targetEvent.Time;
m_RangeEnd = targetEvent.EndTime;
}
else
{
if (m_RangeStart > targetEvent.Time)
{
m_RangeStart = targetEvent.Time;
timeChanged = true;
}
if (m_RangeEnd < targetEvent.EndTime)
{
m_RangeEnd = targetEvent.EndTime;
timeChanged = true;
}
}
FireSelectionChanged(true, timeChanged);
Redraw();
}
public void SelectEngineFrames()
{
List<FrameDelimiter> engineDelimiters = m_Data.FrameDelimiters.Where(d => d.Type == FrameDelimiter.DelimiterType.Engine).ToList();
if (engineDelimiters.Count == 0)
{
MessageBox.Show("There are no engine frame delimiters.", "Select Engine Frames", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (m_RangeStart == m_RangeEnd)
{
MessageBox.Show("There is no selection. Start by approximately selecting the frames you want.", "Select Engine Frames", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (m_RangeStart < engineDelimiters[0].Time)
m_RangeStart = m_Data.TimeExtent.Min;
if (m_RangeEnd < engineDelimiters[0].Time)
m_RangeEnd = engineDelimiters[0].Time;
int i = 0;
for (; i < engineDelimiters.Count - 1; ++i)
{
if (m_RangeStart > engineDelimiters[i].Time && m_RangeStart < engineDelimiters[i + 1].Time)
{
m_RangeStart = engineDelimiters[i].Time;
break;
}
}
for (; i < engineDelimiters.Count - 1; ++i)
{
if (m_RangeEnd > engineDelimiters[i].Time && m_RangeEnd < engineDelimiters[i + 1].Time)
{
m_RangeEnd = engineDelimiters[i + 1].Time;
break;
}
}
if (m_RangeStart > engineDelimiters.Last().Time)
m_RangeStart = engineDelimiters.Last().Time;
if (m_RangeEnd > engineDelimiters.Last().Time)
m_RangeEnd = m_Data.TimeExtent.Max;
FireSelectionChanged(true, true);
Redraw();
}
public void SelectGraphicFrames()
{
List<FrameDelimiter> graphicDelimiters = m_Data.FrameDelimiters.Where(d => d.Type == FrameDelimiter.DelimiterType.Graphic).ToList();
if (graphicDelimiters.Count == 0)
{
MessageBox.Show("There are no graphic frame delimiters.", "Select Graphic Frames", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (m_RangeStart == m_RangeEnd)
{
MessageBox.Show("There is no selection. Start by approximately selecting the frames you want.", "Select Graphic Frames", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (m_RangeStart < graphicDelimiters[0].Time)
m_RangeStart = m_Data.TimeExtent.Min;
if (m_RangeEnd < graphicDelimiters[0].Time)
m_RangeEnd = graphicDelimiters[0].Time;
int i = 0;
for (; i < graphicDelimiters.Count - 1; ++i)
{
if (m_RangeStart > graphicDelimiters[i].Time && m_RangeStart < graphicDelimiters[i + 1].Time)
{
m_RangeStart = graphicDelimiters[i].Time;
break;
}
}
for (; i < graphicDelimiters.Count - 1; ++i)
{
if (m_RangeEnd > graphicDelimiters[i].Time && m_RangeEnd < graphicDelimiters[i + 1].Time)
{
m_RangeEnd = graphicDelimiters[i + 1].Time;
break;
}
}
if (m_RangeStart > graphicDelimiters.Last().Time)
m_RangeStart = graphicDelimiters.Last().Time;
if (m_RangeEnd > graphicDelimiters.Last().Time)
m_RangeEnd = m_Data.TimeExtent.Max;
FireSelectionChanged(true, true);
Redraw();
}
public void ZoomIn()
{
Time timeStepPerPixel = TimeStepPerPixel();
Time timeDx = (timeStepPerPixel);
const int DELTA = 240;
m_View.Zoom(timeDx * DELTA);
Redraw();
}
public void ZoomOut()
{
Time timeStepPerPixel = TimeStepPerPixel();
Time timeDx = (timeStepPerPixel);
const int DELTA = -240;
m_View.Zoom(timeDx * DELTA);
Redraw();
}
public void ZoomOnSelectedEvent()
{
ZoomOnEvent(m_SelectedProfileEvent);
Redraw();
}
public void SetEventsFilterString(string filter)
{
m_Filters.SetFilter(filter);
Redraw();
if (EventsFilterChanged != null)
EventsFilterChanged(this);
}
public string GetOriginalEventsFilterString()
{
return m_Filters.OriginalFilter;
}
public bool SetContextsVisibilityFilterString(string filter)
{
if (string.IsNullOrEmpty(filter))
filter = ".*";
try
{
Regex regex = new Regex(filter, RegexOptions.Compiled | RegexOptions.IgnoreCase);
m_ContextsVisibilityFilter = regex;
}
catch
{
return false;
}
bool selectionTimesHaveChanged = false;
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
{
bool wasHidden = context.IsHidden;
context.IsHidden = !m_ContextsVisibilityFilter.IsMatch(context.Name);
if (!wasHidden ^ context.IsHidden) // If the visibility has changed
selectionTimesHaveChanged |= !m_FilteredContexts.Contains(context.Name);
}
if (selectionTimesHaveChanged)
ComputeSelectionTimes();
Redraw();
if (ContextsFilterChanged != null)
ContextsFilterChanged(this);
return true;
}
public void SetParentShadowActive()
{
m_ShowParentShadow = !m_ShowParentShadow;
Redraw();
}
public void SetShowTinyEvents()
{
m_ShowTinyEvents = !m_ShowTinyEvents;
Redraw();
}
public string GetOriginalContextsVisibilityFilterString()
{
return m_ContextsVisibilityFilter.ToString();
}
public void FilterContext(string contextName)
{
if (m_FilteredContexts.Add(contextName))
{
if (ContextSelectionChanged != null)
ContextSelectionChanged(this, m_FilteredContexts);
ComputeSelectionTimes();
Redraw();
}
}
public void FilterContexts(IEnumerable<string> contextNames)
{
bool elementsWereAdded = false;
foreach (string contextName in contextNames)
elementsWereAdded |= m_FilteredContexts.Add(contextName);
if (elementsWereAdded)
{
if (ContextSelectionChanged != null)
ContextSelectionChanged(this, m_FilteredContexts);
ComputeSelectionTimes();
Redraw();
}
}
public void UnfilterContext(string contextName)
{
if (m_FilteredContexts.Remove(contextName))
{
if (ContextSelectionChanged != null)
ContextSelectionChanged(this, m_FilteredContexts);
ComputeSelectionTimes();
Redraw();
}
}
public void UnfilterContexts(IEnumerable<string> contextNames)
{
bool elementsWereRemoved = false;
foreach (string contextName in contextNames)
elementsWereRemoved |= m_FilteredContexts.Remove(contextName);
if (elementsWereRemoved)
{
if (ContextSelectionChanged != null)
ContextSelectionChanged(this, m_FilteredContexts);
ComputeSelectionTimes();
Redraw();
}
}
public bool IsAnyContextFilteredOrHidden()
{
if (m_FilteredContexts.Count > 0)
return true;
foreach (ProfileEventData.ProfileContext context in m_Data.Contexts.Values)
if (context.IsHidden)
return true;
return false;
}
void m_View_ViewChanged(ProfileEventTrace.View view)
{
// Cache the new time step
m_TimeStepPerPixel = (view.TimeEnd - view.TimeStart) / ClientSize.Width;
}
private Time TimeStepPerPixel()
{
return m_TimeStepPerPixel;
}
private void ProfileEventTrace_Closed(object sender, EventArgs e)
{
// Assumes this trace will never be reopened.
m_Summary.Close();
m_Summary = null;
if (m_TaskGraph != null)
{
m_TaskGraph.Close();
m_TaskGraph = null;
}
m_Doc = null;
m_Data = null;
}
}
}