private void OnSetGCHandle(SetGCHandleTraceData data) { if (ProcessId != data.ProcessID) { return; } // This is not a pinned handle. if ((GCHandleKind.AsyncPinned != data.Kind) && (GCHandleKind.Pinned != data.Kind)) { return; } PinningStackAnalysisObject objectInfo = GetPinningInfo(data.ObjectID); Debug.Assert(objectInfo != null); if (objectInfo == null) { return; } // TODO FIX NOW worry about duplicates between the public and private CLR providers. if (objectInfo.PinInfo == null) { objectInfo.PinInfo = new List <PinningStackAnalysisPinInfo>(); } var stackIndex = StackSource.GetCallStack(data.CallStackIndex(), data); objectInfo.PinInfo.Add(new PinningStackAnalysisPinInfo(data.TimeStampRelativeMSec, stackIndex, data.Kind)); }
/// <summary> /// Add a sample representing the pinned object allocation. /// </summary> private void WriteAllocationStack( Address objectAddress, PinningRoot pinnedRoot, PinningStackAnalysisObject liveObjectInfo) { // Get the pinned object from the pinned root. PinnedObject pinnedObject = null; foreach (PinnedObject o in pinnedRoot.PinnedObjects) { if (o.ObjectAddress == objectAddress) { pinnedObject = o; break; } } // This should not happen, but we put this here to ensure that we don't crash. if (null == pinnedObject) { System.Diagnostics.Debug.Assert(false, "Pinned object could not be found, but was found in the _RootTable."); return; } // Get the allocation call stack. StackSourceCallStackIndex rootCallStackIndex = liveObjectInfo.AllocStack; // Add the generation pseudo-node. string generationString = "GENERATION " + pinnedObject.Generation; StackSourceFrameIndex generationFrameIndex = _StackSource.Interner.FrameIntern(generationString); StackSourceCallStackIndex callStackIndex = _StackSource.Interner.CallStackIntern(generationFrameIndex, rootCallStackIndex); // Add the type of the object. string objectTypeString = "OBJECT_TYPE " + pinnedObject.ObjectType; StackSourceFrameIndex objectTypeFrameIndex = _StackSource.Interner.FrameIntern(objectTypeString); callStackIndex = _StackSource.Interner.CallStackIntern(objectTypeFrameIndex, callStackIndex); // Set the object instance. string objectInstanceString = "OBJECT_INSTANCE " + pinnedObject.ObjectAddress; StackSourceFrameIndex objectInstanceFrameIndex = _StackSource.Interner.FrameIntern(objectInstanceString); callStackIndex = _StackSource.Interner.CallStackIntern(objectInstanceFrameIndex, callStackIndex); // Setup the sample. _Sample.TimeRelativeMSec = liveObjectInfo.AllocationTimeRelativeMSec; _Sample.Metric = pinnedObject.ObjectSize; _Sample.StackIndex = callStackIndex; _StackSource.AddSample(_Sample); }
/// <summary> /// Write out a sample for each pin operation of the input object. /// </summary> private void WritePinningStacks( Address objectAddress, PinningRoot pinnedRoot, PinningStackAnalysisObject liveObjectInfo) { if (liveObjectInfo.PinInfo != null) { foreach (PinningStackAnalysisPinInfo pinInfo in liveObjectInfo.PinInfo) { // Get the pinning stack and the time. foreach (PinnedObject pinnedObject in pinnedRoot.PinnedObjects) { // Add the generation pseudo-node. string generationString = "GENERATION " + pinnedObject.Generation; StackSourceFrameIndex generationFrameIndex = _StackSource.Interner.FrameIntern(generationString); StackSourceCallStackIndex callStackIndex = _StackSource.Interner.CallStackIntern(generationFrameIndex, pinInfo.PinStack); // Add the root type. string rootTypeString = "ROOT_TYPE " + pinnedRoot.RootType.ToString(); StackSourceFrameIndex rootTypeFrameIndex = _StackSource.Interner.FrameIntern(rootTypeString); callStackIndex = _StackSource.Interner.CallStackIntern(rootTypeFrameIndex, callStackIndex); // Add the type of the object. string objectTypeString = "OBJECT_TYPE " + pinnedObject.ObjectType; StackSourceFrameIndex objectTypeFrameIndex = _StackSource.Interner.FrameIntern(objectTypeString); callStackIndex = _StackSource.Interner.CallStackIntern(objectTypeFrameIndex, callStackIndex); // Set the object instance. string objectInstanceString = "OBJECT_INSTANCE " + pinnedObject.ObjectAddress; StackSourceFrameIndex objectInstanceFrameIndex = _StackSource.Interner.FrameIntern(objectInstanceString); callStackIndex = _StackSource.Interner.CallStackIntern(objectInstanceFrameIndex, callStackIndex); // Set the metric to 1 since the metric represents the number of pin operations. _Sample.Metric = 1; // Set the call stack. _Sample.TimeRelativeMSec = pinInfo.PinTimeRelativeMSec; _Sample.StackIndex = callStackIndex; _StackSource.AddSample(_Sample); } } } }
/// <summary> /// Execute the pinned object analyzer. /// </summary> internal void Execute( GCPinnedObjectViewType viewType) { // Process the heap snapshot, and populate the root table and process id. ProcessHeapSnapshot(); // Instantiate the necessary trace event parsers. TraceEventDispatcher eventDispatcher = _TraceLog.Events.GetSource(); PerfViewTraceEventParser perfViewParser = new PerfViewTraceEventParser(eventDispatcher); // we want the state of the heap at the time the snapshot was taken. perfViewParser.TriggerHeapSnapshot += delegate(TriggerHeapSnapshotTraceData data) { eventDispatcher.StopProcessing(); }; var heapWithPinningInfo = new PinningStackAnalysis(eventDispatcher, _TraceLog.Processes.GetProcess(_ProcessID, _TraceLog.SessionDuration.TotalMilliseconds), _StackSource, _Log); // Process the ETL file up until we detect that the heap snapshot was taken. eventDispatcher.Process(); // Iterate through all pinned objects in the heap snapshot. foreach (KeyValuePair <Address, PinningRoot> pinnedPair in _RootTable) { // Try to match the object in the heap snapshot with an object in the ETL. PinningStackAnalysisObject liveObjectInfo = heapWithPinningInfo.GetPinningInfo(pinnedPair.Key); if (liveObjectInfo != null) { // Found a match, write the appropriate call stacks. if (viewType == GCPinnedObjectViewType.PinnedObjectAllocations) { WriteAllocationStack(pinnedPair.Key, pinnedPair.Value, liveObjectInfo); } else if (viewType == GCPinnedObjectViewType.PinnedHandles) { WritePinningStacks(pinnedPair.Key, pinnedPair.Value, liveObjectInfo); } } } }