Browse Source

Parallel Stacks v0.3

pull/15/head
Eusebiu Marcu 15 years ago
parent
commit
a860840709
  1. 117
      src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackPad.cs
  2. 122
      src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ThreadStack.xaml.cs

117
src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackPad.cs

@ -23,9 +23,11 @@ namespace Debugger.AddIn.Pads.ParallelPad
{ {
private DrawSurface surface; private DrawSurface surface;
private Process debuggedProcess; private Process debuggedProcess;
private ParallelStacksGraph graph;
private List<ThreadStack> currentThreadStacks = new List<ThreadStack>(); private List<ThreadStack> currentThreadStacks = new List<ThreadStack>();
#region Overrides
protected override void InitializeComponents() protected override void InitializeComponents()
{ {
surface = new DrawSurface(); surface = new DrawSurface();
@ -52,16 +54,6 @@ namespace Debugger.AddIn.Pads.ParallelPad
RefreshPad(); RefreshPad();
} }
void OnReset(object sender, EventArgs e)
{
currentThreadStacks.Clear();
}
void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
RefreshPad();
}
public override void RefreshPad() public override void RefreshPad()
{ {
@ -101,7 +93,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
if (stack == null) if (stack == null)
continue; continue;
if (stack.ThreadStackParent != null && if (stack.ThreadStackParent != null &&
(stack.ThreadStackChildren == null || stack.ThreadStackChildren.Length == 0)) (stack.ThreadStackChildren == null || stack.ThreadStackChildren.Count == 0))
continue; continue;
graph.AddVertex(stack); graph.AddVertex(stack);
@ -113,12 +105,24 @@ namespace Debugger.AddIn.Pads.ParallelPad
surface.SetGraph(graph); surface.SetGraph(graph);
} }
} }
#endregion
#region Private Methods
ParallelStacksGraph graph; private void OnReset(object sender, EventArgs e)
{
currentThreadStacks.Clear();
}
private void debuggedProcess_Paused(object sender, ProcessEventArgs e)
{
RefreshPad();
}
void AddChildren(ThreadStack parent) private void AddChildren(ThreadStack parent)
{ {
if(parent.ThreadStackChildren == null || parent.ThreadStackChildren.Length == 0) if(parent.ThreadStackChildren == null || parent.ThreadStackChildren.Count == 0)
return; return;
foreach (var ts in parent.ThreadStackChildren) foreach (var ts in parent.ThreadStackChildren)
@ -128,7 +132,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
graph.AddVertex(ts); graph.AddVertex(ts);
graph.AddEdge(new ParallelStacksEdge(parent, ts)); graph.AddEdge(new ParallelStacksEdge(parent, ts));
if (ts.ThreadStackChildren == null || ts.ThreadStackChildren.Length == 0) if (ts.ThreadStackChildren == null || ts.ThreadStackChildren.Count == 0)
continue; continue;
AddChildren(ts); AddChildren(ts);
@ -160,7 +164,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
foreach (var stack in currentThreadStacks) { foreach (var stack in currentThreadStacks) {
int count = stack.ItemCollection.Count; int count = stack.ItemCollection.Count;
dynamic frame = stack.ItemCollection[count - 1]; dynamic frame = stack.ItemCollection[count - 1];
string fullname = frame.MethodName; string fullname = frame.MethodName + stack.Level.ToString();
if (!commonFrameThreads.ContainsKey(fullname)) if (!commonFrameThreads.ContainsKey(fullname))
commonFrameThreads.Add(fullname, new List<ThreadStack>()); commonFrameThreads.Add(fullname, new List<ThreadStack>());
@ -217,7 +221,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
// remove last [frameIndex] and create a new ThreadStack as the parent of what remained in the children // remove last [frameIndex] and create a new ThreadStack as the parent of what remained in the children
var threadIds = new List<uint>(); var threadIds = new List<uint>();
var parentItems = new Stack<ExpandoObject>(); var parentItems = new Stack<ExpandoObject>();
int j = 0;
while (frameIndex > 0) { while (frameIndex > 0) {
for (int i = 0 ; i < listOfCurrentStacks.Count; ++i) { for (int i = 0 ; i < listOfCurrentStacks.Count; ++i) {
var stack = listOfCurrentStacks[i]; var stack = listOfCurrentStacks[i];
@ -229,24 +233,31 @@ namespace Debugger.AddIn.Pads.ParallelPad
#endif #endif
if (i == 0) if (i == 0)
parentItems.Push(stack.ItemCollection[indexToRemove]); parentItems.Push(stack.ItemCollection[indexToRemove]);
if (i == j)
threadIds.AddRange(stack.ThreadIds);
stack.ItemCollection.RemoveAt(indexToRemove); stack.ItemCollection.RemoveAt(indexToRemove);
} }
j++;
frameIndex--; frameIndex--;
} }
// update thread ids
for (int i = 0 ; i < listOfCurrentStacks.Count; ++i)
threadIds.AddRange(listOfCurrentStacks[i].ThreadIds);
// remove stacks with no items // remove stacks with no items
for (int i = listOfCurrentStacks.Count - 1; i >= 0; --i) { for (int i = listOfCurrentStacks.Count - 1; i >= 0; --i) {
var stack = listOfCurrentStacks[i]; var stack = listOfCurrentStacks[i];
if (stack.ItemCollection.Count == 0) if (stack.ItemCollection.Count == 0)
listOfCurrentStacks.Remove(stack); listOfCurrentStacks.Remove(stack);
} }
// increase the Level
for (int i = 0 ; i < listOfCurrentStacks.Count; ++i)
listOfCurrentStacks[i].Level++;
// create new parent stack // create new parent stack
ThreadStack commonParent = new ThreadStack(); ThreadStack commonParent = new ThreadStack();
commonParent.ThreadIds = threadIds; commonParent.UpdateThreadIds(threadIds.ToArray());
commonParent.ItemCollection = parentItems.ToObservable(); commonParent.ItemCollection = parentItems.ToObservable();
commonParent.Process = debuggedProcess; commonParent.Process = debuggedProcess;
commonParent.FrameSelected += threadStack_FrameSelected; commonParent.FrameSelected += threadStack_FrameSelected;
@ -259,15 +270,48 @@ namespace Debugger.AddIn.Pads.ParallelPad
continue; continue;
} }
dynamic item = stack.ItemCollection[stack.ItemCollection.Count - 1]; dynamic item = stack.ItemCollection[stack.ItemCollection.Count - 1];
// add the parent to the parent
if (stack.ThreadStackParent != null) {
// remove stack from it's parent because it will have the commonParent as parent
stack.ThreadStackParent.ThreadStackChildren.Remove(stack);
commonParent.ThreadStackParent = stack.ThreadStackParent;
commonParent.ThreadStackParent.ThreadStackChildren.Add(commonParent);
// set level
commonParent.Level = stack.Level - 1;
}
// update thread ids
var parent = commonParent.ThreadStackParent;
if (parent != null) {
if (parent.ThreadIds != null)
{
var list = new List<uint>();
foreach (uint id in commonParent.ThreadIds) {
if (!parent.ThreadIds.Contains(id)) {
list.Add(id);
}
}
parent.UpdateThreadIds(list.ToArray());
}
}
stack.ThreadStackParent = commonParent; stack.ThreadStackParent = commonParent;
string currentName = item.MethodName; string currentName = item.MethodName + stack.Level.ToString();;
var newList = new List<ThreadStack>();
newList.Add(stack);
commonFrameThreads.Add(currentName, newList); // add name or add to list
if (!commonFrameThreads.ContainsKey(currentName)) {
var newList = new List<ThreadStack>();
newList.Add(stack);
commonFrameThreads.Add(currentName, newList);
}
else {
var list = commonFrameThreads[currentName];
list.Add(stack);
}
} }
commonParent.ThreadStackChildren = listOfCurrentStacks.ToArray(); commonParent.ThreadStackChildren = listOfCurrentStacks.Clone();
commonFrameThreads[frameName].Clear(); commonFrameThreads[frameName].Clear();
commonFrameThreads[frameName].Add(commonParent); commonFrameThreads[frameName].Add(commonParent);
currentThreadStacks.Add(commonParent); currentThreadStacks.Add(commonParent);
@ -289,8 +333,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
ThreadStack threadStack = new ThreadStack(); ThreadStack threadStack = new ThreadStack();
threadStack.FrameSelected += threadStack_FrameSelected; threadStack.FrameSelected += threadStack_FrameSelected;
threadStack.ThreadIds = new List<uint>(); threadStack.UpdateThreadIds(thread.ID);
threadStack.ThreadIds.Add(thread.ID);
threadStack.Process = debuggedProcess; threadStack.Process = debuggedProcess;
currentThreadStacks.Add(threadStack); currentThreadStacks.Add(threadStack);
@ -299,7 +342,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
threadStack.IsSelected = threadStack.ThreadIds.Contains(debuggedProcess.SelectedThread.ID); threadStack.IsSelected = threadStack.ThreadIds.Contains(debuggedProcess.SelectedThread.ID);
} }
void threadStack_FrameSelected(object sender, EventArgs e) private void threadStack_FrameSelected(object sender, EventArgs e)
{ {
foreach (var ts in this.currentThreadStacks) { foreach (var ts in this.currentThreadStacks) {
ts.IsSelected = false; ts.IsSelected = false;
@ -346,6 +389,8 @@ namespace Debugger.AddIn.Pads.ParallelPad
return result; return result;
} }
#endregion
} }
internal static class StackFrameExtensions internal static class StackFrameExtensions
@ -366,6 +411,18 @@ namespace Debugger.AddIn.Pads.ParallelPad
internal static class ParallelStackExtensions internal static class ParallelStackExtensions
{ {
internal static List<T> Clone<T>(this List<T> listToClone)
{
if (listToClone == null)
return null;
List<T> result = new List<T>();
foreach (var item in listToClone)
result.Add(item);
return result;
}
internal static ObservableCollection<T> ToObservable<T>(this Stack<T> stack) internal static ObservableCollection<T> ToObservable<T>(this Stack<T> stack)
{ {
if (stack == null) if (stack == null)

122
src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ThreadStack.xaml.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Dynamic; using System.Dynamic;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@ -25,22 +26,28 @@ namespace Debugger.AddIn.Pads.ParallelPad
DependencyProperty.Register("IsSelected", typeof(bool), typeof(ThreadStack), DependencyProperty.Register("IsSelected", typeof(bool), typeof(ThreadStack),
new FrameworkPropertyMetadata()); new FrameworkPropertyMetadata());
public event EventHandler FrameSelected; public event EventHandler FrameSelected;
private ObservableCollection<ExpandoObject> itemCollection = new ObservableCollection<ExpandoObject>(); private ObservableCollection<ExpandoObject> itemCollection = new ObservableCollection<ExpandoObject>();
private ToolTip toolTip = new ToolTip(); private ToolTip toolTip = new ToolTip();
private List<uint> threadIds = new List<uint>();
public ThreadStack() public ThreadStack()
{ {
InitializeComponent(); InitializeComponent();
ToolTip = toolTip; datagrid.ToolTip = toolTip;
ToolTipOpening += new ToolTipEventHandler(OnToolTipOpening); datagrid.ToolTipOpening += OnToolTipOpening;
datagrid.PreviewMouseMove += new MouseEventHandler(datagrid_PreviewMouseMove);
datagrid.MouseLeave += delegate { toolTip.IsOpen = false; };
} }
#region Public Properties
public Process Process { get; set; } public Process Process { get; set; }
public int Level { get; set; }
public bool IsSelected { public bool IsSelected {
get { return (bool)GetValue(IsSelectedProperty); } get { return (bool)GetValue(IsSelectedProperty); }
set { set {
@ -61,9 +68,13 @@ namespace Debugger.AddIn.Pads.ParallelPad
public ThreadStack ThreadStackParent { get; set; } public ThreadStack ThreadStackParent { get; set; }
public ThreadStack[] ThreadStackChildren { get; set; } public List<ThreadStack> ThreadStackChildren { get; set; }
public List<uint> ThreadIds { get; set; } public List<uint> ThreadIds {
get {
return threadIds;
}
}
public ObservableCollection<ExpandoObject> ItemCollection { public ObservableCollection<ExpandoObject> ItemCollection {
get { get {
@ -73,14 +84,23 @@ namespace Debugger.AddIn.Pads.ParallelPad
set { set {
itemCollection = value; itemCollection = value;
this.datagrid.ItemsSource = itemCollection; this.datagrid.ItemsSource = itemCollection;
if (ThreadIds.Count > 1)
this.HeaderText.Text = ThreadIds.Count.ToString() + " Threads";
else
this.HeaderText.Text = "1 Thread";
} }
} }
#endregion
#region Public Methods
public void UpdateThreadIds(params uint[] threadIds)
{
this.threadIds.AddRange(threadIds);
if (this.threadIds.Count > 1)
this.HeaderText.Text = this.threadIds.Count.ToString() + " Threads";
else
this.HeaderText.Text = "1 Thread";
}
public void ClearImages() public void ClearImages()
{ {
foreach(dynamic item in itemCollection) { foreach(dynamic item in itemCollection) {
@ -88,7 +108,11 @@ namespace Debugger.AddIn.Pads.ParallelPad
} }
} }
void SelectParent(bool isSelected) #endregion
#region Private Methods
private void SelectParent(bool isSelected)
{ {
var ts = this.ThreadStackParent; var ts = this.ThreadStackParent;
while(ts != null) { while(ts != null) {
@ -97,7 +121,24 @@ namespace Debugger.AddIn.Pads.ParallelPad
} }
} }
void Datagrid_MouseDoubleClick(object sender, MouseButtonEventArgs e) void datagrid_PreviewMouseMove(object sender, MouseEventArgs e)
{
var result = VisualTreeHelper.HitTest(this, e.GetPosition(this));
if (result != null)
{
var row = TryFindParent<DataGridRow>(result.VisualHit);
if (row != null)
{
datagrid.SelectedItem = row.DataContext;
if (toolTip.IsOpen)
toolTip.IsOpen = false;
toolTip.IsOpen = true;
e.Handled = true;
}
}
}
private void Datagrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{ {
if (Process.IsRunning) return; if (Process.IsRunning) return;
@ -114,7 +155,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
} }
} }
void SelectFrame(uint threadId, ExpandoObject selectedItem) private void SelectFrame(uint threadId, ExpandoObject selectedItem)
{ {
if (selectedItem == null) if (selectedItem == null)
return; return;
@ -142,7 +183,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
} }
} }
void Datagrid_MouseRightButtonUp(object sender, MouseButtonEventArgs e) private void Datagrid_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{ {
if (Process.IsRunning) return; if (Process.IsRunning) return;
@ -154,7 +195,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
datagrid.ContextMenu.IsOpen = true; datagrid.ContextMenu.IsOpen = true;
} }
ContextMenu CreateContextMenu(ExpandoObject item) private ContextMenu CreateContextMenu(ExpandoObject item)
{ {
dynamic obj = item; dynamic obj = item;
@ -177,7 +218,7 @@ namespace Debugger.AddIn.Pads.ParallelPad
return menu; return menu;
} }
void OnToolTipOpening(object sender, ToolTipEventArgs e) private void OnToolTipOpening(object sender, ToolTipEventArgs e)
{ {
StackPanel panel = new StackPanel(); StackPanel panel = new StackPanel();
@ -196,7 +237,6 @@ namespace Debugger.AddIn.Pads.ParallelPad
{ {
if (selectedItem.MethodName == frame.GetMethodName()) if (selectedItem.MethodName == frame.GetMethodName())
{ {
// TODO : get method parameter values
TextBlock tb = new TextBlock(); TextBlock tb = new TextBlock();
tb.Text = thread.ID + ": " + CallStackPadContent.GetFullName(frame); tb.Text = thread.ID + ": " + CallStackPadContent.GetFullName(frame);
panel.Children.Add(tb); panel.Children.Add(tb);
@ -207,5 +247,53 @@ namespace Debugger.AddIn.Pads.ParallelPad
this.toolTip.Content = panel; this.toolTip.Content = panel;
} }
#endregion
#region Static Methods
private static T TryFindParent<T>(DependencyObject child) where T : DependencyObject
{
if (child is T) return child as T;
DependencyObject parentObject = GetParentObject(child);
if (parentObject == null) return null;
var parent = parentObject as T;
if (parent != null && parent is T)
{
return parent;
}
else
{
return TryFindParent<T>(parentObject);
}
}
private static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null) return null;
ContentElement contentElement = child as ContentElement;
if (contentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
FrameworkContentElement fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
FrameworkElement frameworkElement = child as FrameworkElement;
if (frameworkElement != null)
{
DependencyObject parent = frameworkElement.Parent;
if (parent != null) return parent;
}
return VisualTreeHelper.GetParent(child);
}
#endregion
} }
} }
Loading…
Cancel
Save