Пример #1
0
    internal void Increment(TraceEvent data)
    {
#if DEBUG
        // Debug.Assert((byte)data.opcode != unchecked((byte)-1));        // Means PrepForCallback not done.
        Debug.Assert(data.TaskName != "ERRORTASK");
        Debug.Assert(data.OpcodeName != "ERROROPCODE");
#endif
        Count++;
        TaskStats task = this[data.TaskName];
        if (task.ProviderName == null)
        {
            task.ProviderName = data.ProviderName;
        }

        CallStackIndex index    = data.CallStackIndex();
        bool           hasStack = (index != CallStackIndex.Invalid);
        if (hasStack)
        {
            StackCount++;
        }
        task.Increment(data.OpcodeName, hasStack);
        StackWalkTraceData asStackWalk = data as StackWalkTraceData;
        if (asStackWalk != null)
        {
            StackWalkStats stackWalkStats = task.ExtraData as StackWalkStats;
            if (stackWalkStats == null)
            {
                stackWalkStats = new StackWalkStats();
                task.ExtraData = stackWalkStats;
            }
            stackWalkStats.Log(asStackWalk);
        }
    }
Пример #2
0
        /// <summary>
        /// Convert the TraceEvent callStack 'callStackIdx' into a StackSourceCallStack.  'callStackIdx is
        /// assumed to be related to the traceEvent 'data'.   'data' is used to determine the process and thread
        /// of the stack.  (TODO data may not be needed anymore as callStackIndexes do encode their thread (and thus process)).
        /// </summary>
        public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, TraceEvent data)
        {
            // This only happens if only have ONLY the thread and process (no addressses)
            // TODO do we care about this case?  Should we remove?
            var thread = data.Thread();
            StackSourceCallStackIndex topOfStack;

            if (thread == null)
            {
                var process = data.Process();
                if (process != null)
                {
                    topOfStack = GetCallStackForProcess(process);
                }
                else
                {
                    topOfStack = StackSourceCallStackIndex.Invalid;
                }
            }
            else
            {
                topOfStack = GetCallStackForThread(thread);
            }

            return(GetCallStack(callStackIndex, topOfStack, m_callStackMap));
        }
Пример #3
0
        /// <summary>
        /// Find the StackSourceCallStackIndex for the TraceEvent call stack index 'callStackIndex' which has a top of its
        /// stack (above the stack, where the thread and process would normally go) as 'top'.  If callStackMap is non-null
        /// it is used as an interning table for CallStackIndex -> StackSourceCallStackIndex.  This can speed up the
        /// transformation dramatically.   It will still work if it is null.
        /// </summary>
        ///
        public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, StackSourceCallStackIndex top, CallStackMap callStackMap = null)
        {
            if (callStackIndex == CallStackIndex.Invalid)
            {
                return(top);
            }

            StackSourceCallStackIndex cachedValue;

            if (callStackMap != null)
            {
                cachedValue = callStackMap.Get(callStackIndex);
                if (cachedValue != StackSourceCallStackIndex.Invalid)
                {
                    return(cachedValue);
                }
            }

            var frameIdx = GetFrameIndex(m_log.CallStacks.CodeAddressIndex(callStackIndex));

            CallStackIndex            nonInternedCallerIdx = m_log.CallStacks.Caller(callStackIndex);
            StackSourceCallStackIndex callerIdx;

            if (nonInternedCallerIdx == CallStackIndex.Invalid)
            {
                callerIdx = top;

                if (!OnlyManagedCodeStacks)
                {
                    var frameName = GetFrameName(frameIdx, false);
                    var bangIdx   = frameName.IndexOf('!');
                    if (0 < bangIdx)
                    {
                        if (!(5 <= bangIdx && string.Compare(frameName, bangIdx - 5, "ntdll", 0, 5, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            var brokenFrame = m_Interner.FrameIntern("BROKEN", m_emptyModuleIdx);
                            callerIdx = m_Interner.CallStackIntern(brokenFrame, callerIdx);
                        }
                    }
                }
            }
            else
            {
                callerIdx = GetCallStack(nonInternedCallerIdx, top, callStackMap);
            }

            var ret = m_Interner.CallStackIntern(frameIdx, callerIdx);

            if (callStackMap != null)
            {
                callStackMap.Put(callStackIndex, ret);
            }

            return(ret);
        }
        private void OnGCAllocationTick(GCAllocationTickTraceData data)
        {
            TraceThread thread = data.Thread();

            Debug.Assert(thread != null);
            if (null == thread)
            {
                return;
            }

            // Attempt to charge the allocation to a request.
            ScenarioThreadState scenarioThreadState = m_Configuration.ScenarioThreadState[(int)thread.ThreadIndex];

            CallStackIndex            traceLogCallStackIndex = data.CallStackIndex();
            StackSourceCallStackIndex callStackIndex         = scenarioThreadState.GetCallStackIndex(m_OutputStackSource, thread, data);

            // Add the thread.
            StackSourceFrameIndex threadFrameIndex = m_OutputStackSource.Interner.FrameIntern(thread.VerboseThreadName);

            callStackIndex = m_OutputStackSource.Interner.CallStackIntern(threadFrameIndex, callStackIndex);

            // Get the allocation call stack index.
            callStackIndex = m_OutputStackSource.GetCallStack(traceLogCallStackIndex, callStackIndex, null);

            // Add the type.
            string typeName = data.TypeName;

            if (typeName.Length > 0)
            {
                StackSourceFrameIndex nodeIndex = m_OutputStackSource.Interner.FrameIntern("Type " + data.TypeName);
                callStackIndex = m_OutputStackSource.Interner.CallStackIntern(nodeIndex, callStackIndex);
            }

            // Add a notification for large objects.
            if (data.AllocationKind == GCAllocationKind.Large)
            {
                StackSourceFrameIndex nodeIndex = m_OutputStackSource.Interner.FrameIntern("LargeObject");
                callStackIndex = m_OutputStackSource.Interner.CallStackIntern(nodeIndex, callStackIndex);
            }

            // Set the time.
            m_Sample.TimeRelativeMSec = data.TimeStampRelativeMSec;

            // Set the metric.
            bool seenBadAllocTick = false;

            m_Sample.Metric = data.GetAllocAmount(ref seenBadAllocTick);

            // Set the stack index.
            m_Sample.StackIndex = callStackIndex;

            // Add the sample.
            m_OutputStackSource.AddSample(m_Sample);
        }
Пример #5
0
        // Caller only need to provide TraceThread
        public StackSourceCallStackIndex GetCallStackThread(CallStackIndex callStackIndex, TraceThread thread)
        {
            if (callStackIndex == CallStackIndex.Invalid)
            {
                if (thread == null)
                {
                    return(StackSourceCallStackIndex.Invalid);
                }
                return(GetCallStackForThread(thread));
            }
            var idx = (int)StackSourceCallStackIndex.Start + (int)callStackIndex;

            return((StackSourceCallStackIndex)idx);
        }
Пример #6
0
        /// <summary>
        /// Find the StackSourceCallStackIndex for the TraceEvent call stack index 'callStackIndex' which has a top of its
        /// stack as 'top'.  If callStckMap is non-null it is used as an interning table for CallStackIndex -> StackSourceCallStackIndex.
        /// This can speed up the transformation dramatically.
        /// </summary>
        public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, StackSourceCallStackIndex top,
                                                      Dictionary <int, StackSourceCallStackIndex> callStackMap)
        {
            if (callStackIndex == CallStackIndex.Invalid)
            {
                return(top);
            }

            StackSourceCallStackIndex cachedValue;

            if (callStackMap != null && callStackMap.TryGetValue((int)callStackIndex, out cachedValue))
            {
                return(cachedValue);
            }

            var frameIdx = GetFrameIndex(m_log.CallStacks.CodeAddressIndex(callStackIndex));

            CallStackIndex            nonInternedCallerIdx = m_log.CallStacks.Caller(callStackIndex);
            StackSourceCallStackIndex callerIdx;

            if (nonInternedCallerIdx == CallStackIndex.Invalid)
            {
                callerIdx = top;

                var frameName = GetFrameName(frameIdx, false);
                var bangIdx   = frameName.IndexOf('!');
                if (0 < bangIdx)
                {
                    if (!(5 <= bangIdx && string.Compare(frameName, bangIdx - 5, "ntdll", 0, 5, StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        var brokenFrame = m_Interner.FrameIntern("BROKEN", m_emptyModuleIdx);
                        callerIdx = m_Interner.CallStackIntern(brokenFrame, callerIdx);
                    }
                }
            }
            else
            {
                callerIdx = GetCallStack(nonInternedCallerIdx, top, callStackMap);
            }

            var ret = m_Interner.CallStackIntern(frameIdx, callerIdx);

            if (callStackMap != null)
            {
                callStackMap[(int)callStackIndex] = ret;
            }
            return(ret);
        }
        /// <summary>
        /// Mark the thread as unblocked.
        /// </summary>
        public void LogBlockingStop(
            ComputingResourceStateMachine stateMachine,
            TraceThread thread,
            TraceEvent data)
        {
            if ((null == stateMachine) || (null == thread) || (null == data))
            {
                return;
            }

            // Only add a sample if the thread was blocked.
            if (ThreadBlocked)
            {
                StackSourceSample            sample      = stateMachine.Sample;
                MutableTraceEventStackSource stackSource = stateMachine.StackSource;

                // Set the time and metric.
                sample.TimeRelativeMSec = this.BlockTimeStartRelativeMSec;
                sample.Metric           = (float)(data.TimeStampRelativeMSec - this.BlockTimeStartRelativeMSec);

                /* Generate the stack trace. */

                CallStackIndex            traceLogCallStackIndex = data.CallStackIndex();
                ScenarioThreadState       scenarioThreadState    = stateMachine.Configuration.ScenarioThreadState[ThreadIndex];
                StackSourceCallStackIndex callStackIndex         = scenarioThreadState.GetCallStackIndex(stateMachine.StackSource, thread, data);

                // Add the thread.
                StackSourceFrameIndex threadFrameIndex = stackSource.Interner.FrameIntern(thread.VerboseThreadName);
                callStackIndex = stackSource.Interner.CallStackIntern(threadFrameIndex, callStackIndex);

                // Add the full call stack.
                callStackIndex = stackSource.GetCallStack(traceLogCallStackIndex, callStackIndex, null);

                // Add Pseud-frames representing the kind of resource.
                StackSourceFrameIndex frameIndex = stackSource.Interner.FrameIntern("BLOCKED TIME");
                callStackIndex = stackSource.Interner.CallStackIntern(frameIndex, callStackIndex);

                // Add the call stack to the sample.
                sample.StackIndex = callStackIndex;

                // Add the sample.
                stackSource.AddSample(sample);

                // Mark the thread as executing.
                BlockTimeStartRelativeMSec = -1;
            }
        }
Пример #8
0
        /// <summary>
        /// Find the StackSourceCallStackIndex for the TraceEvent call stack index 'callStackIndex' which has a top of its
        /// stack as 'top'.  If callStckMap is non-null it is used as an interning table for CallStackIndex -> StackSourceCallStackIndex.
        /// This can speed up the transformation dramatically.
        /// </summary>
        /// <param name="callStackIndex"></param>
        /// <param name="top"></param>
        /// <param name="callStackMap"></param>
        /// <returns></returns>
        public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, StackSourceCallStackIndex top,
                                                      Dictionary <int, StackSourceCallStackIndex> callStackMap)
        {
            if (callStackIndex == CallStackIndex.Invalid)
            {
                return(top);
            }

            StackSourceCallStackIndex cachedValue;

            if (callStackMap != null && callStackMap.TryGetValue((int)callStackIndex, out cachedValue))
            {
                return(cachedValue);
            }

            bool isReasonableTopStack;
            var  frameIdx = GetFrameIndex(m_log.CallStacks.CodeAddressIndex(callStackIndex), out isReasonableTopStack);

            CallStackIndex            nonInternedCallerIdx = m_log.CallStacks.Caller(callStackIndex);
            StackSourceCallStackIndex callerIdx;

            if (nonInternedCallerIdx == CallStackIndex.Invalid)
            {
                callerIdx = top;
                if (!isReasonableTopStack)
                {
                    var brokenFrame = Interner.FrameIntern("BROKEN", m_emptyModuleIdx);
                    callerIdx = Interner.CallStackIntern(brokenFrame, callerIdx);
                }
            }
            else
            {
                callerIdx = GetCallStack(nonInternedCallerIdx, top, callStackMap);
            }

            var ret = Interner.CallStackIntern(frameIdx, callerIdx);

            if (callStackMap != null)
            {
                callStackMap[(int)callStackIndex] = ret;
            }
            return(ret);
        }
Пример #9
0
        // Note that this always returns a stack, since we know the thread and process.
        public StackSourceCallStackIndex GetCallStack(CallStackIndex callStackIndex, TraceEvent data)
        {
            if (callStackIndex == CallStackIndex.Invalid)
            {
                if (data == null)
                {
                    return(StackSourceCallStackIndex.Invalid);
                }
                var thread = data.Thread();
                if (thread == null)
                {
                    return(StackSourceCallStackIndex.Invalid);
                }
                return(GetCallStackForThread(thread));
            }
            var idx = (int)StackSourceCallStackIndex.Start + (int)callStackIndex;

            return((StackSourceCallStackIndex)idx);
        }
        /// <summary>
        /// Log a CPU sample on this thread.
        /// </summary>
        public void LogCPUSample(
            ComputingResourceStateMachine stateMachine,
            TraceThread thread,
            TraceEvent data)
        {
            if ((null == stateMachine) || (null == thread) || (null == data))
            {
                return;
            }

            StackSourceSample sample = stateMachine.Sample;

            sample.Metric           = 1;
            sample.TimeRelativeMSec = data.TimeStampRelativeMSec;
            MutableTraceEventStackSource stackSource = stateMachine.StackSource;

            // Attempt to charge the CPU to a request.
            CallStackIndex traceLogCallStackIndex = data.CallStackIndex();

            ScenarioThreadState       scenarioThreadState = stateMachine.Configuration.ScenarioThreadState[ThreadIndex];
            StackSourceCallStackIndex callStackIndex      = scenarioThreadState.GetCallStackIndex(stackSource, thread, data);

            // Add the thread.
            StackSourceFrameIndex threadFrameIndex = stackSource.Interner.FrameIntern(thread.VerboseThreadName);

            callStackIndex = stackSource.Interner.CallStackIntern(threadFrameIndex, callStackIndex);

            // Rest of the stack.
            // NOTE: Do not pass a call stack map into this method, as it will skew results.
            callStackIndex = stackSource.GetCallStack(traceLogCallStackIndex, callStackIndex, null);

            // Add the CPU frame.
            StackSourceFrameIndex cpuFrameIndex = stackSource.Interner.FrameIntern("CPU");

            callStackIndex = stackSource.Interner.CallStackIntern(cpuFrameIndex, callStackIndex);

            // Add the sample.
            sample.StackIndex = callStackIndex;
            stackSource.AddSample(sample);
        }
Пример #11
0
        internal void OnVirtualMem(VirtualAllocTraceData data)
        {
            VirtualAllocTraceData.VirtualAllocFlags flags = data.Flags;

            ModuleClass alloc = ModuleClass.Free;

            if ((flags & VirtualAllocTraceData.VirtualAllocFlags.MEM_COMMIT) != 0)
            {
                alloc = ModuleClass.Unknown;

                CallStackIndex s = m_stackDecoder.FirstFrame(data.EventIndex);

                while (s != CallStackIndex.Invalid)
                {
                    ModuleClass old = alloc;

                    alloc = m_stackDecoder.GetModuleClass(s);

                    if ((old == ModuleClass.OSUser) && (alloc != old))
                    {
                        break;
                    }

                    s = m_stackDecoder.GetCaller(s);
                }
            }
            else if ((flags & (VirtualAllocTraceData.VirtualAllocFlags.MEM_DECOMMIT | VirtualAllocTraceData.VirtualAllocFlags.MEM_RELEASE)) == 0)
            {
                return;
            }


            if (m_MemMap == null)
            {
                m_MemMap       = new Dictionary <ulong, ModuleClass[]>();
                m_ModuleVMSize = new ulong[(int)(ModuleClass.Max)];
            }

            Debug.Assert((data.BaseAddr % PageSize) == 0);
            Debug.Assert((data.Length % PageSize) == 0);

            ulong addr = data.BaseAddr;

            // TODO because of the algorithm below, we can't handle very large blocks of memory
            // because it is linear in size of the alloc or free.  It turns out that sometimes
            // we free very large chunks.  Thus cap it.  This is not accurate but at least we
            // complete.
            long len = data.Length / PageSize;

            if (len > 0x400000)     // Cap it at 4M pages = 16GB chunks.
            {
                len = 0x400000;
            }

            while (len > 0)
            {
                ModuleClass[] bit;

                ulong region = addr / OneMB;

                if (!m_MemMap.TryGetValue(region, out bit))
                {
                    bit = new ModuleClass[OneMB / PageSize];

                    m_MemMap[region] = bit;
                }

                int offset = (int)(addr % OneMB) / PageSize;

                if (alloc != bit[offset])
                {
                    ModuleClass old = bit[offset];

                    bit[offset] = alloc;

                    if (alloc != ModuleClass.Free)
                    {
                        if (old == ModuleClass.Free)
                        {
                            m_ModuleVMSize[(int)alloc] += PageSize;

                            m_VMSize += PageSize;

                            if (m_VMSize > m_MaxVMSize)
                            {
                                m_MaxVMSize = m_VMSize;
                            }
                        }
                    }
                    else
                    {
                        m_ModuleVMSize[(int)old] -= PageSize;

                        m_VMSize -= PageSize;
                    }
                }

                addr += PageSize;
                len--;
            }

            if (m_VMCurve == null)
            {
                m_VMCurve = new List <double>();
            }

            double clrSize   = m_ModuleVMSize[(int)ModuleClass.Clr] / OneMBD;
            double graphSize = m_ModuleVMSize[(int)ModuleClass.OSGraphics] / OneMBD;

            double win8StoreSize;

            if (m_stackDecoder.WwaHost)
            {
                win8StoreSize = m_ModuleVMSize[(int)ModuleClass.JScript] / OneMBD;
            }
            else
            {
                win8StoreSize = m_ModuleVMSize[(int)ModuleClass.Win8Store] / OneMBD;
            }

            m_VMCurve.Add(data.TimeStampRelativeMSec);
            m_VMCurve.Add(clrSize);
            m_VMCurve.Add(clrSize + graphSize);
            m_VMCurve.Add(clrSize + graphSize + win8StoreSize);
            m_VMCurve.Add(m_VMSize / OneMBD);
        }
Пример #12
0
    /// <summary>
    /// If you place a file called PerfViewExtensions\PerfViewStartup next to the PerfView.exe it will
    /// run execute commands in that file.  If you put
    ///
    /// DeclareFileView .etl "Demo View In Etl File" DemoDeclareFileView
    ///
    /// It will create a child node for all .etl files called 'Demo View In Etl File'  If you click
    /// on this node it will execute this user command.  It is passed the name of the file that was
    /// opened and the name of the view that was opened (in this case 'Demo View In Etl File').
    /// </summary>
    public void DemoDeclareFileView(string fileName, string viewName)
    {
        // This demo creates a view that shows you all the START events in a stack view.
        LogFile.WriteLine("************ In DemoDeclareFileView file = {0} view = {1}", fileName, viewName);

        // This is an example of opening an ETL file.
        ETLDataFile etlFile = OpenETLFile(fileName);

        // An ETLData file is a high level construct that knows about high level 'views' of the data (CPU stacks, thread time Stacks ...)

        // However if you want to create a new view, you probably want a TraceLog which is the underlying ETW data.
        TraceLog traceLog = etlFile.TraceLog;

        // A tracelog represent the whole ETL file (which has process, images, threads etc), we want events, and we want callbacks
        // for each event which is what GetSource() does.   THus we get a source (which we can add callbacks to)
        var eventSource = traceLog.Events.GetSource();

        // At this point create the 'output' of our routine.  Our goal is to produce stacks that we will view in the
        // stack viewer.   Thus we create an 'empty' one fo these.
        var stackSource = new MutableTraceEventStackSource(traceLog);
        // A stack source is  list of samples.  We create a sample structure, mutate it and then call AddSample() repeatedly to add samples.
        var sample = new StackSourceSample(stackSource);

        // Setup the callbacks, In this case we are going to watch for stacks where GCs happen
        eventSource.Clr.GCStart += delegate(GCStartTraceData data)
        {
            // An TraceLog should have a callstack associated with this event;
            CallStackIndex callStackIdx = data.CallStackIndex();
            if (callStackIdx != CallStackIndex.Invalid)
            {
                // Convert the TraceLog call stack to a MutableTraceEventStackSource call stack
                StackSourceCallStackIndex stackCallStackIndex = stackSource.GetCallStack(callStackIdx, data);

                // Add a pseudo frame on the bottom of the stack
                StackSourceFrameIndex frameIdxForName = stackSource.Interner.FrameIntern("GC Gen " + data.Depth + "Reason " + data.Reason);
                stackCallStackIndex = stackSource.Interner.CallStackIntern(frameIdxForName, stackCallStackIndex);

                // create a sample with that stack and add it to the stack source (list of samples)
                sample.Metric           = 1;
                sample.TimeRelativeMSec = data.TimeStampRelativeMSec;
                sample.StackIndex       = stackCallStackIndex;
                stackSource.AddSample(sample);
            }
        };
        // You can set up other callback for other events.

        // This causes the TraceLog source to actually spin through all the events calling our callbacks as requested.
        eventSource.Process();

        // We are done adding sample to our stack Source, so we tell the MutableTraceEventStackSource that.
        // after that is becomes viewable (and read-only).
        stackSource.DoneAddingSamples();

        // Take the stack source (raw data) and make it into a 'Stacks' allows you to add filtering to and send to 'OpendStackViewer'
        Stacks stacksForViewer = new Stacks(stackSource, viewName, etlFile);

        // Set any filtering options here.

        // Now we can display the viewer.
        OpenStackViewer(stacksForViewer);
    }