Esempio n. 1
0
        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);
        }
Esempio n. 4
0
        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;
        }