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); } }
private void OnObjectAllocated(TraceEvent data, Address objectID, Address classID, long size, long representativeSize) { if (data.ProcessID != m_processID) { return; } Debug.Assert(GetObjectInfo(objectID) == null); // new objects should be unique. var objectData = AllocateObject(); var stackIndex = m_stackSource.GetCallStack(data.CallStackIndex(), data); // Add object type as a pseudo-frame to the stack TypeInfo typeInfo; if (!m_classNamesAsFrames.TryGetValue(classID, out typeInfo)) { typeInfo.FrameIdx = m_stackSource.Interner.FrameIntern("Type <Unknown>"); } objectData.ClassFrame = typeInfo.FrameIdx; objectData.AllocStack = stackIndex; objectData.Size = (int)size; objectData.RepresentativeSize = (int)representativeSize; var timeStamp = data.TimeStampRelativeMSec; // Insure that timeStamps move forward in time and are unique, so they can be used as object IDs. var verySmall = 1; while (timeStamp <= m_lastAllocTimeRelativeMSec) { timeStamp = m_lastAllocTimeRelativeMSec + verySmall * .0000001; // Add a 10th of a ns. verySmall = verySmall * 2; // Depending on how long the trace has run, this may not change timestamp, so keep making it bigger until it does. } m_lastAllocTimeRelativeMSec = timeStamp; objectData.AllocationTimeRelativeMSec = timeStamp; Debug.WriteLine(string.Format("Object Allocated {0:x} Size {1:x} Rep {2:x} {3}", objectID, size, representativeSize, typeInfo.TypeName)); m_currentHeapSize += (uint)objectData.RepresentativeSize; if (OnObjectCreate != null) { if (!OnObjectCreate(objectID, objectData)) { return; } } var allocGen = 0; if (objectData.Size >= 85000) // Large objects go into Gen 2 { allocGen = 2; } m_ObjsInGen[allocGen][(Address)objectID] = objectData; // Put the object into Gen 0; }
private StackSourceCallStackIndex GetStack(TraceEvent event_) { // Console.WriteLine("Getting Stack for sample at {0:f4}", sample.TimeStampRelativeMSec); int ret = (int)event_.CallStackIndex(); if (ret == (int)CallStackIndex.Invalid) { var thread = event_.Thread(); if (thread == null) { return(StackSourceCallStackIndex.Invalid); } // If the event is a sample profile, or page fault we can make a one element stack with the EIP in the event CodeAddressIndex codeAddrIdx = CodeAddressIndex.Invalid; var asSampleProfile = event_ as SampledProfileTraceData; if (asSampleProfile != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } else { var asPageFault = event_ as MemoryHardFaultTraceData; if (asPageFault != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } } if (codeAddrIdx != CodeAddressIndex.Invalid) { // Encode the code address for the given thread. int pseudoStackIndex = GetPseudoStack(thread.ThreadIndex, codeAddrIdx); // Psuedostacks happen after all the others. if (0 <= pseudoStackIndex) { ret = m_log.CallStacks.Count + 2 * m_log.Threads.Count + m_log.Processes.Count + pseudoStackIndex; } } // If we have run out of pseudo-stacks, we encode the stack as being at the thread. if (ret == (int)CallStackIndex.Invalid) { ret = m_log.CallStacks.Count + (int)thread.ThreadIndex; } } else { // We expect the thread we get when looking at the CallStack to match the thread of the event. Debug.Assert(m_log.CallStacks.Thread((CallStackIndex)ret).ThreadID == event_.ThreadID); Debug.Assert(event_.Thread().Process.ProcessID == event_.ProcessID); } ret = ret + (int)StackSourceCallStackIndex.Start; return((StackSourceCallStackIndex)ret); }
private StackSourceCallStackIndex GetStack(TraceEvent event_) { // Console.WriteLine("Getting Stack for sample at {0:f4}", sample.TimeStampRelativeMSec); var ret = (int)event_.CallStackIndex(); if (ret == (int)CallStackIndex.Invalid) { var thread = event_.Thread(); if (thread == null) { return(StackSourceCallStackIndex.Invalid); } // If the event is a sample profile, or page fault we can make a one element stack with the EIP in the event CodeAddressIndex codeAddrIdx = CodeAddressIndex.Invalid; var asSampleProfile = event_ as SampledProfileTraceData; if (asSampleProfile != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } else { var asPageFault = event_ as PageFaultHardFaultTraceData; if (asPageFault != null) { codeAddrIdx = asSampleProfile.IntructionPointerCodeAddressIndex(); } } if (codeAddrIdx != CodeAddressIndex.Invalid) { // Encode the code address for the given thread. int pseudoStackIndex = GetPseudoStack(thread.ThreadIndex, codeAddrIdx); if (pseudoStackIndex < 0) { return(StackSourceCallStackIndex.Start); } // Psuedostacks happen after all the others. ret = m_log.CallStacks.MaxCallStackIndex + 2 * m_log.Threads.MaxThreadIndex + m_log.Processes.MaxProcessIndex + pseudoStackIndex; } else { // Otherwise we encode the stack as being at the thread. ret = m_log.CallStacks.MaxCallStackIndex + (int)thread.ThreadIndex; } } ret = ret + (int)StackSourceCallStackIndex.Start; return((StackSourceCallStackIndex)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; } }
/// <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); }
internal ETWEventRecord(ETWEventSource source, TraceEvent data, Dictionary <string, int> columnOrder, int nonRestFields, double durationMSec) : base(nonRestFields) { m_source = source; m_name = data.ProviderName + "/" + data.EventName; m_processName = data.ProcessName; if (!m_processName.StartsWith("(")) { m_processName += " (" + data.ProcessID + ")"; } m_timeStampRelativeMSec = data.TimeStampRelativeMSec; m_idx = data.EventIndex; // Compute the data column var restString = new StringBuilder(); // Deal with the special HasStack, ThreadID and ActivityID, DataLength fields; var hasStack = data.CallStackIndex() != CallStackIndex.Invalid; if (hasStack) { AddField("HasStack", hasStack.ToString(), columnOrder, restString); } var asCSwitch = data as CSwitchTraceData; if (asCSwitch != null) { AddField("HasBlockingStack", (asCSwitch.BlockingStack() != CallStackIndex.Invalid).ToString(), columnOrder, restString); } AddField("ThreadID", data.ThreadID.ToString("n0"), columnOrder, restString); AddField("ProcessorNumber", data.ProcessorNumber.ToString(), columnOrder, restString); if (0 < durationMSec) { AddField("DURATION_MSEC", durationMSec.ToString("n3"), columnOrder, restString); } var payloadNames = data.PayloadNames; if (payloadNames.Length == 0 && data.EventDataLength != 0) { // WPP events look classic and use the EventID as their discriminator if (data.IsClassicProvider && data.ID != 0) { AddField("EventID", ((int)data.ID).ToString(), columnOrder, restString); } AddField("DataLength", data.EventDataLength.ToString(), columnOrder, restString); } try { for (int i = 0; i < payloadNames.Length; i++) { AddField(payloadNames[i], data.PayloadString(i), columnOrder, restString); } } catch (Exception e) { AddField("ErrorParsingFields", e.Message, columnOrder, restString); } var message = data.FormattedMessage; if (message != null) { AddField("FormattedMessage", message, columnOrder, restString); } if (source.m_needsComputers) { TraceThread thread = data.Thread(); if (thread != null) { TraceActivity activity = source.m_activityComputer.GetCurrentActivity(thread); if (activity != null) { string id = activity.ID; if (Math.Abs(activity.StartTimeRelativeMSec - m_timeStampRelativeMSec) < .0005) { id = "^" + id; // Indicates it is at the start of the task. } AddField("ActivityInfo", id, columnOrder, restString); } var startStopActivity = source.m_startStopActivityComputer.GetCurrentStartStopActivity(thread, data); if (startStopActivity != null) { string name = startStopActivity.Name; string parentName = "$"; if (startStopActivity.Creator != null) { parentName = startStopActivity.Creator.Name; } AddField("StartStopActivity", name + "/P=" + parentName, columnOrder, restString); } } } // We pass 0 as the process ID for creating the activityID because we want uniform syntax. if (data.ActivityID != Guid.Empty) { AddField("ActivityID", StartStopActivityComputer.ActivityPathString(data.ActivityID), columnOrder, restString); } Guid relatedActivityID = data.RelatedActivityID; if (relatedActivityID != Guid.Empty) { AddField("RelatedActivityID", StartStopActivityComputer.ActivityPathString(data.RelatedActivityID), columnOrder, restString); } if (data.ContainerID != null) { AddField("ContainerID", data.ContainerID, columnOrder, restString); } m_asText = restString.ToString(); }