private static bool AddStopMethodToAggregatedCallTree( ProfilerEvent?currentProfilerEvent, ref AggregatedEventNode currentAggregatedEventNode, ref Stack <ProfilerEvent> callStack) { if (currentAggregatedEventNode.Parent != null) { if (callStack.Count() == 0) { // Discard current tree while (currentAggregatedEventNode.Parent != null) { currentAggregatedEventNode = currentAggregatedEventNode.Parent; } currentAggregatedEventNode.Children.Clear(); return(false); } ProfilerEvent startEvent = callStack.Peek(); if (currentProfilerEvent.Value.ObjectType != startEvent.ObjectType || currentProfilerEvent.Value.ObjectId != startEvent.ObjectId || currentProfilerEvent.Value.StatementName != startEvent.StatementName) { // Skip stop event from empty functions return(false); } // We need to calculate duration for the previous statement and pop it from the statement call stack. if (currentAggregatedEventNode.EvaluatedType == EventType.Statement || currentAggregatedEventNode.EvaluatedType == EventType.StopMethod || // Always close non events. currentProfilerEvent.Value.IsNonAlEvent) { currentAggregatedEventNode = currentAggregatedEventNode.PopEventFromCallStackAndCalculateDuration(currentProfilerEvent.Value.TimeStampRelativeMSec); if (currentProfilerEvent.Value.SubType == EventSubType.AlEvent && currentAggregatedEventNode.SubType == EventSubType.AlEvent && currentAggregatedEventNode.Parent != null && currentAggregatedEventNode.Parent.Parent == null) { // Also pop function node created for root functions currentAggregatedEventNode = currentAggregatedEventNode.PopEventFromCallStackAndCalculateDuration(currentProfilerEvent.Value.TimeStampRelativeMSec); } } currentAggregatedEventNode.EvaluatedType = EventType.StopMethod; if (currentProfilerEvent.Value.IsAlEvent) { currentAggregatedEventNode.IsExecutingFunction = false; } callStack.Pop(); } return(true); }
/// <summary> /// Determines if the current object is equal to the <paramref name="obj"/> /// </summary> /// <param name="obj">The object to compare</param> /// <returns>true, if the two instances are equal</returns> public override bool Equals(object obj) { if (!(obj is ProfilerEvent)) { return(false); } ProfilerEvent other = (ProfilerEvent)obj; return(Type.Equals(other.Type) && SessionId.Equals(other.SessionId) && ObjectType.Equals(other.ObjectType) && ObjectId.Equals(other.ObjectId) && LineNumber.Equals(other.LineNumber) && StatementName.Equals(other.StatementName) && TimeStampRelativeMSec.Equals(other.TimeStampRelativeMSec)); }
/// <summary> /// Pushes event into call stack. It might get or create aggregated event. /// </summary> /// <param name="profilerEvent">The profiler event.</param> /// <returns>The aggregated event node.</returns> internal AggregatedEventNode PushEventIntoCallStack(ProfilerEvent profilerEvent) { Debug.Assert(profilerEvent.Type == EventType.Statement || profilerEvent.Type == EventType.StartMethod); AggregatedEventNode res = Children.Find(e => e.SessionId == profilerEvent.SessionId && e.ObjectType == profilerEvent.ObjectType && e.ObjectId == profilerEvent.ObjectId && e.LineNo == profilerEvent.LineNumber && e.StatementName == profilerEvent.StatementName); if (res != null) { // We need to initialize state of the AggregatedEventNode. // Otherwise duration will not be calculated correctly or we can get broken tree structure. res.EvaluatedType = profilerEvent.Type; res.TimeStampRelativeMSec = profilerEvent.TimeStampRelativeMSec; ++res.HitCount; return(res); } res = new AggregatedEventNode(this) { SessionId = profilerEvent.SessionId, Tenant = profilerEvent.Tenant, UserName = profilerEvent.UserName, AppId = profilerEvent.AppId, AppInfo = profilerEvent.AppInfo, ObjectType = profilerEvent.ObjectType, ObjectId = profilerEvent.ObjectId, LineNo = profilerEvent.LineNumber, StatementName = profilerEvent.StatementName, TimeStampRelativeMSec = profilerEvent.TimeStampRelativeMSec, OriginalType = profilerEvent.Type, EvaluatedType = profilerEvent.Type, SubType = profilerEvent.SubType, }; Children.Add(res); ++res.HitCount; return(res); }
private static bool PopEventFromCallStackIfSomeEventsWereMissing( ProfilerEvent?previousProfilerEvent, ProfilerEvent?currentProfilerEvent, ref AggregatedEventNode currentAggregatedEventNode, ref Stack <ProfilerEvent> callStack, out bool skipCurrentEvent) { if (currentAggregatedEventNode.Parent != null && currentAggregatedEventNode.OriginalType == EventType.StartMethod && currentAggregatedEventNode.SubType == EventSubType.SqlEvent && currentProfilerEvent.HasValue && !(currentProfilerEvent.Value.Type == EventType.StopMethod && currentProfilerEvent.Value.SubType == EventSubType.SqlEvent)) { // TODO: Here we have two consecutive start events. First event is of the SQL subtype. This should never happen because SQL queries cannot be nested. // TODO: It could indicates an issue in evening. // TODO: Need to pop previous event and push current. ProfilerEvent missingProfilerEvent = new ProfilerEvent { SessionId = currentAggregatedEventNode.SessionId, ObjectType = currentAggregatedEventNode.ObjectType, ObjectId = currentAggregatedEventNode.ObjectId, LineNo = currentAggregatedEventNode.LineNo, Type = EventType.StartMethod, StatementName = StopEventIsMissing + currentAggregatedEventNode.StatementName }; currentAggregatedEventNode = currentAggregatedEventNode.PopEventFromCallStackAndCalculateDuration(previousProfilerEvent.Value.TimeStampRelativeMSec); currentAggregatedEventNode = currentAggregatedEventNode.PushEventIntoCallStack(missingProfilerEvent); currentAggregatedEventNode = currentAggregatedEventNode.PopEventFromCallStackAndCalculateDuration(missingProfilerEvent.TimeStampRelativeMSec); if (currentProfilerEvent.Value.Type == EventType.StartMethod || currentProfilerEvent.Value.Type == EventType.Statement) { currentAggregatedEventNode = currentAggregatedEventNode.PushEventIntoCallStack(currentProfilerEvent.Value); } skipCurrentEvent = true; return(true); } if (currentAggregatedEventNode.Parent != null && previousProfilerEvent.HasValue && previousProfilerEvent.Value.Type == EventType.StopMethod && currentProfilerEvent.HasValue && currentProfilerEvent.Value.Type == EventType.StopMethod && currentProfilerEvent.Value.IsAlEvent != currentAggregatedEventNode.IsAlEvent) { //TODO: We hit this block for example in the case if Codeunit 1 trigger is called and it does not have any code. //TODO: We should consider if we want to fix it in the product. // Skip this event. Should never happen. Indicates a issue in the event generation. // Some events were missed. // Create fake start event. ProfilerEvent profilerEvent = currentProfilerEvent.Value; profilerEvent.Type = EventType.StartMethod; profilerEvent.StatementName = StartEventIsMissing + profilerEvent.StatementName; currentAggregatedEventNode = currentAggregatedEventNode.PushEventIntoCallStack(profilerEvent); currentAggregatedEventNode = currentAggregatedEventNode.PopEventFromCallStackAndCalculateDuration(currentProfilerEvent.Value.TimeStampRelativeMSec); skipCurrentEvent = false; return(true); } skipCurrentEvent = false; return(false); }
internal void AddEtwEventToAggregatedCallTree(TraceEvent traceEvent, int sessionId, int statementIndex, string statementName, EventType eventType, EventSubType eventSubType) { if (sessionId != this.profilingSessionId) { // we are interested only in events for the profiling session return; } if (this.firstEvent) { this.firstEvent = false; } string objectType = string.Empty; int objectId = 0; if (eventSubType == EventSubType.AlEvent) { // We don't have object type and id for the non AL events. objectType = (string)traceEvent.PayloadValue(NavEventsPayloadIndexes.ObjectTypePayloadIndex); objectId = (int)traceEvent.PayloadValue(NavEventsPayloadIndexes.ObjectIdPayloadIndex); } int lineNo = 0; if ((int)traceEvent.ID == NavEvents.ALFunctionStatement) { // Only statements have line numbers. lineNo = System.Convert.ToInt32(traceEvent.PayloadValue(NavEventsPayloadIndexes.LineNoPayloadIndex)); } string statement; if (statementIndex == NavEventsPayloadIndexes.NonPayloadIndex) { statement = statementName; } else { if (!string.IsNullOrEmpty(statementName)) { statement = statementName + (string)traceEvent.PayloadValue(statementIndex); } else { statement = (string)traceEvent.PayloadValue(statementIndex); } } statement = this.GetStatementFromTheCache(statement); ProfilerEvent?currentProfilerEvent = new ProfilerEvent { SessionId = sessionId, Type = eventType, SubType = eventSubType, ObjectType = objectType, ObjectId = objectId, LineNo = lineNo, StatementName = statement, TimeStampRelativeMSec = traceEvent.TimeStampRelativeMSec }; if (AddProfilerEventToAggregatedCallTree(this.previousProfilerEvent, currentProfilerEvent, ref this.currentAggregatedEventNode)) { this.previousProfilerEvent = currentProfilerEvent; } this.previousTraceEvent = traceEvent; }