public EventsThreadRow(FrameGroup group, ThreadDescription desc, ThreadData data) { Description = desc; EventData = data; Group = group; MaxDepth = 1; Header = new ThreadNameView() { DataContext = this }; UpdateThreadsDepth(); switch (Controls.Settings.LocalSettings.Data.ThreadExpandMode) { case Controls.LocalSettings.ExpandMode.CollapseAll: _isExpanded = false; break; case Controls.LocalSettings.ExpandMode.ExpandAll: _isExpanded = true; break; case Controls.LocalSettings.ExpandMode.ExpandMain: _isExpanded = group.MainThread.Description == desc; break; } }
private static ProcessGroup GetProcessGroup(FrameGroup group, UInt64 threadID) { if (threadID == 0) { return(ProcessGroup.None); } ThreadData thread = group.GetThread(threadID); if (thread != null) { return(ProcessGroup.CurrentProcess); } ThreadDescription desc = null; if (group.Board.ThreadDescriptions.TryGetValue(threadID, out desc)) { if (desc.IsIdle) { return(ProcessGroup.None); } } return(ProcessGroup.OtherProcess); }
public EventsThreadRow(FrameGroup group, ThreadDescription desc, ThreadData data, ThreadViewSettings settings) { Description = desc; EventData = data; Group = group; MaxDepth = 1; Settings = settings; Header = new ThreadNameView() { DataContext = this }; UpdateThreadsDepth(); switch (Settings?.ThreadExpandMode) { case ExpandMode.CollapseAll: _isExpanded = false; break; case ExpandMode.ExpandAll: _isExpanded = true; break; case ExpandMode.ExpandMain: _isExpanded = desc.ThreadIndex == group.Board.MainThreadIndex; break; } }
List <EventsThreadRow> GenerateThreadRows(FrameGroup group) { id2row.Clear(); List <EventsThreadRow> eventThreads = new List <EventsThreadRow>(); for (int i = 0; i < Math.Min(group.Board.Threads.Count, group.Threads.Count); ++i) { ThreadData data = group.Threads[i]; ThreadDescription thread = data.Description; if (thread.IsIdle) { continue; } bool threadHasData = false; if (data.Events != null) { double duration = 0.0; foreach (EventFrame frame in data.Events) { duration += frame.Duration; if (duration > MIN_THREAD_ACCUMULATED_DURATION) { threadHasData = true; break; } } } if (thread.Origin == ThreadDescription.Source.Core) { threadHasData = true; } if (threadHasData) { EventsThreadRow row = new EventsThreadRow(group, thread, data, Settings); eventThreads.Add(row); id2row.Add(row.Description.ThreadIndex, row); row.EventNodeHover += Row_EventNodeHover; row.EventNodeSelected += Row_EventNodeSelected; } if (GenerateSamplingThreads && data.Callstacks != null && data.Callstacks.Count > 3) { ThreadData samplingData = GenerateSamplingThread(group, data); EventsThreadRow row = new EventsThreadRow(group, new ThreadDescription() { Name = thread.Name + " [Sampling]", Origin = ThreadDescription.Source.Sampling }, samplingData, Settings); eventThreads.Add(row); row.EventNodeHover += Row_EventNodeHover; row.EventNodeSelected += Row_EventNodeSelected; } } return(SortRows(eventThreads)); }
public override void OnMouseHover(Point point, ThreadScroll scroll, List <object> dataContext) { EventNode node = null; EventFrame frame = null; ITick tick = scroll.PixelToTime(point.X); if (FindNode(point, scroll, out frame, out node) != -1) { dataContext.Add(node); } // show current sync info if (EventData.Sync != null && EventData.Sync != null) { int index = Data.Utils.BinarySearchClosestIndex(EventData.Sync, tick.Start); if (index != -1) { bool insideWaitInterval = false; WaitInterval interval = new WaitInterval() { Start = EventData.Sync[index].Finish, Reason = EventData.Sync[index].Reason }; if (index + 1 < EventData.Sync.Count) { if (EventData.Sync[index].Finish < tick.Start && tick.Start < EventData.Sync[index + 1].Start) { UInt64 threadId = EventData.Sync[index].NewThreadId; ThreadDescription threadDesc = null; Group.Board.ThreadDescriptions.TryGetValue(threadId, out threadDesc); interval.newThreadDesc = threadDesc; interval.newThreadId = threadId; interval.Finish = EventData.Sync[index + 1].Start; dataContext.Add(interval); insideWaitInterval = true; } } if (!insideWaitInterval) { interval.Reason = SyncReason.SyncReasonActive; interval.Start = EventData.Sync[index].Start; interval.Finish = EventData.Sync[index].Finish; interval.core = (byte)EventData.Sync[index].Core; dataContext.Add(interval); } } } if (node != null) { // build all intervals inside selected node int from = Data.Utils.BinarySearchClosestIndex(frame.Synchronization, node.Entry.Start); int to = Data.Utils.BinarySearchClosestIndex(frame.Synchronization, node.Entry.Finish); if (from >= 0 && to >= from) { IntPair[] waitInfo = new IntPair[(int)SyncReason.SyncReasonCount]; for (int index = from; index <= to; ++index) { SyncReason reason = frame.Synchronization[index].Reason; int reasonIndex = (int)reason; long idleStart = frame.Synchronization[index].Finish; long idleFinish = (index + 1 < frame.Synchronization.Count) ? frame.Synchronization[index + 1].Start : frame.Finish; if (idleStart > node.Entry.Finish) { continue; } long idleStartClamped = Math.Max(idleStart, node.Entry.Start); long idleFinishClamped = Math.Min(idleFinish, node.Entry.Finish); long durationInTicks = idleFinishClamped - idleStartClamped; waitInfo[reasonIndex].duration += durationInTicks; waitInfo[reasonIndex].count++; } NodeWaitIntervalList intervals = new NodeWaitIntervalList(); for (int i = 0; i < waitInfo.Length; i++) { if (waitInfo[i].count > 0) { NodeWaitInterval interval = new NodeWaitInterval() { Start = 0, Finish = waitInfo[i].duration, Reason = (SyncReason)i, NodeInterval = node.Entry, Count = waitInfo[i].count }; intervals.Add(interval); } } intervals.Sort((a, b) => { return(Comparer <long> .Default.Compare(b.Finish, a.Finish)); }); if (intervals.Count > 0) { dataContext.Add(intervals); } } } // FindNode if (EventData.Callstacks != null && scroll.DrawCallstacks != 0) { int startIndex = Data.Utils.BinarySearchClosestIndex(EventData.Callstacks, tick.Start); for (int i = startIndex; (i <= startIndex + 1) && (i < EventData.Callstacks.Count) && (i != -1); ++i) { double pixelPos = scroll.TimeToPixel(EventData.Callstacks[i]); if (Math.Abs(pixelPos - point.X) < CallstackMarkerRadius * 1.2 && (EventData.Callstacks[i].Reason & scroll.DrawCallstacks) != 0) { dataContext.Add(EventData.Callstacks[i]); break; } } } }
void InitThreadList(FrameGroup group) { rows.Clear(); id2row.Clear(); ThreadList.RowDefinitions.Clear(); ThreadList.Children.Clear(); if (group == null) { return; } rows.Add(new HeaderThreadRow(group) { GradientTop = (BroAlternativeBackground as SolidColorBrush).Color, GradientBottom = (BroBackground as SolidColorBrush).Color, SplitLines = (BroBackground as SolidColorBrush).Color, TextColor = Colors.Gray }); for (int i = 0; i < Math.Min(group.Board.Threads.Count, group.Threads.Count); ++i) { ThreadDescription thread = group.Board.Threads[i]; ThreadData data = group.Threads[i]; bool threadHasData = false; if ((data.Callstacks != null && data.Callstacks.Count > 3) || /*(data.Sync != null && data.Sync.Intervals.Count > 0) || */ (data.Events != null && data.Events.Count > 0)) { threadHasData = true; } if (threadHasData) { EventsThreadRow row = new EventsThreadRow(group, thread, data); rows.Add(row); id2row.Add(i, row); row.EventNodeHover += Row_EventNodeHover; row.EventNodeSelected += Row_EventNodeSelected; } } scroll.TimeSlice = group.Board.TimeSlice; scroll.Height = 0.0; scroll.Width = surface.ActualWidth * RenderSettings.dpiScaleX; rows.ForEach(row => scroll.Height += row.Height); rows.ForEach(row => row.BuildMesh(surface, scroll)); ThreadList.Margin = new Thickness(0, 0, 3, 0); double offset = 0.0; for (int threadIndex = 0; threadIndex < rows.Count; ++threadIndex) { ThreadRow row = rows[threadIndex]; row.Offset = offset; ThreadList.RowDefinitions.Add(new RowDefinition()); Thickness margin = new Thickness(0, 0, 0, 0); Label labelName = new Label() { Content = row.Name, Margin = margin, Padding = new Thickness(), FontWeight = FontWeights.Bold, Height = row.Height / RenderSettings.dpiScaleY, VerticalContentAlignment = VerticalAlignment.Center }; Grid.SetRow(labelName, threadIndex); if (threadIndex % 2 == 1) { labelName.Background = BroAlternativeBackground; } ThreadList.Children.Add(labelName); offset += row.Height; } InitBackgroundMesh(); }
public EventsThreadRow(FrameGroup group, ThreadDescription desc, ThreadData data) { Description = desc; EventData = data; Group = group; MaxDepth = 1; List <EventNode> rootCategories = new List <EventNode>(); List <EventNode> nodesToProcess = new List <EventNode>(); foreach (EventFrame frame in data.Events) { // Fill holes in timeline from regular events (not categories) // ------------------------------------------------------------------------------------------------------ const double thresholdMs = 0.1; EventTree categoriesTree = frame.CategoriesTree; rootCategories.Clear(); foreach (EventNode node in frame.CategoriesTree.Children) { rootCategories.Add(node); } if (rootCategories.Count != 0) { nodesToProcess.Clear(); foreach (EventNode node in frame.Root.Children) { nodesToProcess.Add(node); } while (nodesToProcess.Count > 0) { EventNode node = nodesToProcess[0]; nodesToProcess.RemoveAt(0); bool nodeIntersectWithCategories = false; foreach (EventNode categoryNode in rootCategories) { // drop nodes less than thresholdMs ms if (node.Entry.Duration < thresholdMs) { nodeIntersectWithCategories = true; break; } // node is entirely inside the categoryNode if (node.Entry.Start >= categoryNode.Entry.Start && node.Entry.Finish <= categoryNode.Entry.Finish) { nodeIntersectWithCategories = true; break; } // node is partially inside the categoryNode if (node.Entry.Intersect(categoryNode.Entry)) { foreach (EventNode tmp in node.Children) { nodesToProcess.Add(tmp); } nodeIntersectWithCategories = true; break; } } if (nodeIntersectWithCategories == false && node.Entry.Duration >= thresholdMs) { // node is not intersect with any categoryNode (add to category tree) EventNode fakeCategoryNode = new EventNode(frame.CategoriesTree, node.Entry); node.Entry.SetOverrideColor(GenerateColorFromString(node.Entry.Description.FullName)); rootCategories.Add(fakeCategoryNode); frame.CategoriesTree.Children.Add(fakeCategoryNode); } } } // ------------------------------------------------------------------------------------------------------ MaxDepth = Math.Max(frame.CategoriesTree.Depth, MaxDepth); } }