public int FindNode(Point point, ThreadScroll scroll, out EventFrame eventFrame, out EventNode eventNode) { ITick tick = scroll.PixelToTime(point.X); int index = Data.Utils.BinarySearchExactIndex(EventData.Events, tick.Start); EventFrame resultFrame = null; EventNode resultNode = null; int resultLevel = -1; if (index >= 0) { EventFrame frame = EventData.Events[index]; int desiredLevel = (int)(point.Y / RenderParams.BaseHeight); GetTree(frame).ForEachChild((node, level) => { if (level > desiredLevel || resultFrame != null) { return(false); } if (level == desiredLevel) { EventNode evNode = (node as EventNode); if (evNode.Entry.Intersect(tick.Start)) { resultFrame = frame; resultNode = evNode; resultLevel = level; return(false); } } return(true); }); } eventFrame = resultFrame; eventNode = resultNode; return(resultLevel); }
public override void OnMouseClick(Point point, ThreadScroll scroll) { EventNode node = null; EventFrame frame = null; int level = FindNode(point, scroll, out frame, out node); if (EventNodeSelected != null) { ITick tick = scroll.PixelToTime(point.X); if (frame == null) { frame = FindFrame(tick); } if (frame != null) { EventNodeSelected(this, frame, node, tick); } } }
public void FocusOn(EventFrame frame, EventNode node) { if (!IsFrameVisible(frame)) { double minRange = frame.Duration * FocusFrameExtent; if (Range < minRange) { Range = minRange; } Position = Durable.TicksToMs(frame.Header.Start - timeRange.Start) + (frame.Duration - Range) / 2; } FocusedFrame = frame; FocusedNode = node; UpdateBar(); Refresh(); }
void RenderFPSLines(System.Windows.Media.DrawingContext drawingContext, List <EventFrame> frames, KeyValuePair <int, int> interval) { double scale = AdornedElement.RenderSize.Width / Range; if (scale < RenderFPSLineLimit) { return; } double height = Extent.Height; StreamGeometry geometry = new StreamGeometry(); using (StreamGeometryContext geometryContext = geometry.Open()) { for (int i = interval.Key; i <= interval.Value; ++i) { EventFrame frame = frames[i]; double posX = (frame.Header.StartMS - timeRange.StartMS - Position) * scale; Point point = new Point(posX, fpsTriangleSize); geometryContext.BeginFigure(point, true, true); geometryContext.LineTo(new Point(posX - fpsTriangleSize / 2, 0), false, false); geometryContext.LineTo(new Point(posX + fpsTriangleSize / 2, 0), false, false); drawingContext.DrawLine(fpsPen, new Point(posX, 0), new Point(posX, height - SpaceHeight)); double maxTextWidth = Math.Max(frame.Duration * scale - 8, 0.0); if (MaxDrawTextThreshold > maxTextWidth && maxTextWidth > MinDrawTextThreshold) { FormattedText text = new FormattedText(String.Format("{0:0.###}ms", frame.Duration).Replace(',', '.'), culture, FlowDirection.LeftToRight, fontDuration, 12, fpsBrush); text.MaxLineCount = 1; text.MaxTextWidth = maxTextWidth; text.Trimming = TextTrimming.None; drawingContext.DrawText(text, new Point(posX + maxTextWidth / 2 - text.Width / 2, -2)); } } } drawingContext.DrawGeometry(fpsBrush, null, geometry); }
public void FocusOn(EventFrame frame, EventNode node) { Group = frame.Group; SelectionList.Clear(); SelectionList.Add(new Selection() { Frame = frame, Node = node }); Interval interval = scroll.TimeToUnit(node != null ? (IDurable)node.Entry : (IDurable)frame); if (!scroll.ViewUnit.Intersect(interval)) { scroll.ViewUnit.Width = interval.Width * DefaultFrameZoom; scroll.ViewUnit.Left = interval.Left - (scroll.ViewUnit.Width - interval.Width) * 0.5; scroll.ViewUnit.Normalize(); UpdateBar(); } UpdateSurface(); }
private void Flush() { EventDescription desc = FunctionSearchDataGrid.SelectedItem as EventDescription; if (desc != null) { if (Group != null) { double maxDuration = 0; EventFrame maxFrame = null; Entry maxEntry = null; foreach (ThreadData thread in Group.Threads) { foreach (EventFrame frame in thread.Events) { List <Entry> entries = null; if (frame.ShortBoard.TryGetValue(desc, out entries)) { foreach (Entry entry in entries) { if (entry.Duration > maxDuration) { maxFrame = frame; maxEntry = entry; maxDuration = entry.Duration; } } } } } if (maxFrame != null && maxEntry != null) { EventNode maxNode = maxFrame.Root.FindNode(maxEntry); RaiseEvent(new TimeLine.FocusFrameEventArgs(TimeLine.FocusFrameEvent, new EventFrame(maxFrame, maxNode), null)); } } } }
private void SampleFunction(EventFrame eventFrame, EventNode node, bool single) { List <Callstack> callstacks = new List <Callstack>(); FrameGroup group = eventFrame.Group; if (single) { Utils.ForEachInsideIntervalStrict(group.Threads[eventFrame.Header.ThreadIndex].Callstacks, node.Entry, callstack => callstacks.Add(callstack)); } else { EventDescription desc = node.Entry.Description; foreach (ThreadData thread in group.Threads) { HashSet <Callstack> accumulator = new HashSet <Callstack>(); foreach (EventFrame currentFrame in thread.Events) { List <Entry> entries = null; if (currentFrame.ShortBoard.TryGetValue(desc, out entries)) { foreach (Entry entry in entries) { Utils.ForEachInsideIntervalStrict(thread.Callstacks, entry, c => accumulator.Add(c)); } } } callstacks.AddRange(accumulator); } } if (callstacks.Count > 0) { SamplingFrame frame = new SamplingFrame(callstacks); Profiler.TimeLine.FocusFrameEventArgs args = new Profiler.TimeLine.FocusFrameEventArgs(Profiler.TimeLine.FocusFrameEvent, frame); RaiseEvent(args); } }
private void ApplyDescriptionFilterToFramesTimeLine(HashSet <Object> filter) { Application.Current.Dispatcher.BeginInvoke(new Action(() => { foreach (Data.Frame frame in frames) { EventFrame eventFrame = frame as EventFrame; if (eventFrame != null) { if (filter == null) { eventFrame.FilteredDescription = ""; } else { double timeInMs = eventFrame.CalculateFilteredTime(filter); eventFrame.FilteredDescription = String.Format("{0:0.000}", timeInMs); } } } })); }
void InitThreadList(SamplingFrame frame) { Frame = frame; List <ThreadRow> rows = new List <ThreadRow>(); if (frame != null) { List <Entry> entries = new List <Entry>(); SamplingNode root = frame.Root; BuildEntryList(entries, root, 0.0); EventFrame eventFrame = new EventFrame(new FrameHeader() { Start = 0, Finish = Durable.MsToTick(root.Duration) }, entries, frame.Group); ThreadData threadData = new ThreadData(null) { Events = new List <EventFrame> { eventFrame } }; EventsThreadRow row = new EventsThreadRow(frame.Group, new ThreadDescription() { Name = "Sampling Node" }, threadData, Settings); row.LimitMaxDepth = false; row.EventNodeHover += Row_EventNodeHover; rows.Add(row); ThreadViewControl.Scroll.ViewUnit.Width = 1.0; ThreadViewControl.InitRows(rows, eventFrame.Header); } else { ThreadViewControl.InitRows(rows, null); } }
private void OpenFrame(object source, FocusFrameEventArgs args) { Data.Frame frame = args.Frame; if (frame is EventFrame) { EventThreadViewControl.Highlight(frame as EventFrame, null); } if (frame is EventFrame) { EventFrame eventFrame = frame as EventFrame; FrameGroup group = eventFrame.Group; if (eventFrame.RootEntry != null) { EventDescription desc = eventFrame.RootEntry.Description; FunctionSummaryVM.Load(group, desc); FunctionInstanceVM.Load(group, desc); FunctionSamplingVM.Load(group, desc); SysCallsSamplingVM.Load(group, desc); FrameInfoControl.SetFrame(frame, null); } } if (frame != null && frame.Group != null) { if (!ReferenceEquals(SummaryVM.Summary, frame.Group.Summary)) { SummaryVM.Summary = frame.Group.Summary; SummaryVM.CaptureName = _captureName; } } }
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; } } } }
public void FocusOn(EventFrame frame, EventNode node) { Group = frame.Group; canvas.FocusOn(frame, node); }
EventTree GetTree(EventFrame frame) { return(frame.Root); }
private void Row_EventNodeSelected(ThreadRow row, EventFrame frame, EventNode node, ITick tick) { RaiseEvent(new TimeLine.FocusFrameEventArgs(TimeLine.FocusFrameEvent, frame, node, tick)); }
public override object Deserialize(IDictionary <string, object> dictionary, Type type, JavaScriptSerializer serializer) { if (type == typeof(TimelineDelta)) { var obj = new TimelineDelta(); if (dictionary.ContainsKey("0-10")) { obj.StartToTen = serializer.ConvertToType <float>(dictionary["0-10"]); } if (dictionary.ContainsKey("10-20")) { obj.TenToTwenty = serializer.ConvertToType <float>(dictionary["10-20"]); } if (dictionary.ContainsKey("20-30")) { obj.TwentyToThirty = serializer.ConvertToType <float>(dictionary["20-30"]); } if (dictionary.ContainsKey("30-end")) { obj.ThirtyToEnd = serializer.ConvertToType <float>(dictionary["30-end"]); } return(obj); } if (type == typeof(ParticipantFrames)) { var obj = new ParticipantFrames(); obj.frames = new List <ParticipantFrame>(); foreach (KeyValuePair <string, object> pair in dictionary) { obj.frames.Add(serializer.ConvertToType <ParticipantFrame>(pair.Value)); } return(obj); } if (type == typeof(EventFrame)) { var obj = new EventFrame(); if (dictionary.ContainsKey("type")) { if ("WARD_PLACED" == (string)dictionary["type"]) { return(GetTypeFromDictionary <WardPlacedFrame>(dictionary, serializer)); } else if ("WARD_KILL" == (string)dictionary["type"]) { return(GetTypeFromDictionary <WardKillFrame>(dictionary, serializer)); } else if ("ELITE_MONSTER_KILL" == (string)dictionary["type"]) { return(GetTypeFromDictionary <EliteMonsterKillFrame>(dictionary, serializer)); } else if ("CHAMPION_KILL" == (string)dictionary["type"]) { return(GetTypeFromDictionary <ChampionKillFrame>(dictionary, serializer)); } else if ("BUILDING_KILL" == (string)dictionary["type"]) { return(GetTypeFromDictionary <BuildingKillFrame>(dictionary, serializer)); } } //Unknown type? return(obj); } return(null); }
bool IsFrameVisible(EventFrame frame) { double framePos = frame.Header.StartMS - timeRange.StartMS; return(Position < framePos && framePos < Position + Range); }
void OnRenderFrame(System.Windows.Media.DrawingContext drawingContext, EventFrame frame, double rowOffset, int maxDepth, Brush backgroundBrush) { Rect rectangle = CalculateRect(frame.Header, rowOffset, maxDepth * BlockHeight); if (rectangle.Width < MinDrawFrameThreshold) { return; } bool isFilterReady = false; double filteredValue = 0.0; if (Filter != null) { isFilterReady = Filter.TryGetFilteredFrameTime(frame, out filteredValue); } //drawingContext.DrawRectangle(Filter != null && isFilterReady ? Brushes.LimeGreen : Brushes.Gray, null, rectangle); if (Filter == null) { List <KeyValuePair <Entry, Rect> > rects = new List <KeyValuePair <Entry, Rect> >(); foreach (EventNode node in frame.CategoriesTree.Children) { GenerateEventNode(node, rectangle, 0, maxDepth, rects); } if (rects.Count > 0 || frame.Synchronization.Count > 0) { foreach (var item in rects) { if (brushes.ContainsKey(item.Key.Description.Color) == false) { UInt32 color = item.Key.Description.Color; var sysColor = Color.FromArgb((byte)(color >> 24), (byte)(color >> 16), (byte)(color >> 8), (byte)(color)); var brush = new SolidColorBrush(sysColor); brushes.Add(color, brush); } drawingContext.DrawRectangle(brushes[item.Key.Description.Color], borderPen, item.Value); } foreach (EventData entry in frame.Synchronization) { Rect rect = CalculateRect(entry, rowOffset, SyncLineHeight); if (rect.Width > DrawThreshold) { drawingContext.DrawRectangle(Brushes.OrangeRed, null, rect); } } foreach (var item in rects) { if (item.Value.Width < MinDrawTextThreshold || item.Value.Width > MaxDrawTextThreshold) { continue; } FormattedText categoryText = new FormattedText(item.Key.Description.Name, culture, FlowDirection.LeftToRight, fontCategoryName, 11, Brushes.Black, null, TextFormattingMode.Display); categoryText.MaxTextWidth = item.Value.Width - textOffset.X; categoryText.Trimming = TextTrimming.None; categoryText.MaxLineCount = 1; drawingContext.DrawText(categoryText, item.Value.Location + textOffset); } } } if (rectangle.Width > DrawThreshold) { drawingContext.DrawRectangle(null, borderPen, rectangle); double value = frame.Duration; if (Filter != null) { if (isFilterReady) { double ratio = filteredValue / frame.Duration; value = filteredValue; drawingContext.DrawRectangle(Brushes.Tomato, null, new Rect(rectangle.X, rectangle.Y, rectangle.Width * ratio, rectangle.Height)); } } if (Filter != null) { FormattedText timingText = new FormattedText(String.Format("{0:0.###}ms", value).Replace(',', '.'), culture, FlowDirection.LeftToRight, fontDuration, 12, Brushes.Black); timingText.MaxTextWidth = rectangle.Width; timingText.MaxLineCount = 1; timingText.Trimming = TextTrimming.None; Point point = new Point(rectangle.Left + 1, rectangle.Bottom - timingText.Height + 1); drawingContext.DrawText(timingText, point); } } }
EventTree GetTree(EventFrame frame) { return(IsExpanded ? frame.Root : frame.CategoriesTree); }