diff options
author | Massimiliano Mantione <massi@mono-cvs.ximian.com> | 2008-10-10 18:20:44 +0400 |
---|---|---|
committer | Massimiliano Mantione <massi@mono-cvs.ximian.com> | 2008-10-10 18:20:44 +0400 |
commit | 73b0c1958f596be55064326243c3fcf08587e7d1 (patch) | |
tree | 31686544c2f29dd7900fba9f68ece395f66c8f64 /Mono.Profiler | |
parent | 348248edb15c4370a7fca451cda2da070ad4fe46 (diff) |
Added support for handling the stack trace of each allocation event.
svn path=/trunk/mono-tools/; revision=115434
Diffstat (limited to 'Mono.Profiler')
-rw-r--r-- | Mono.Profiler/profiler-decoder-library/BaseTypes.cs | 232 | ||||
-rw-r--r-- | Mono.Profiler/profiler-decoder-library/ChangeLog | 8 | ||||
-rw-r--r-- | Mono.Profiler/profiler-decoder-library/Decoder.cs | 153 | ||||
-rw-r--r-- | Mono.Profiler/profiler-decoder-library/EventProcessor.cs | 13 | ||||
-rw-r--r-- | Mono.Profiler/profiler-decoder-library/ObjectModel.cs | 213 |
5 files changed, 603 insertions, 16 deletions
diff --git a/Mono.Profiler/profiler-decoder-library/BaseTypes.cs b/Mono.Profiler/profiler-decoder-library/BaseTypes.cs index c9c1c72b..78a24d10 100644 --- a/Mono.Profiler/profiler-decoder-library/BaseTypes.cs +++ b/Mono.Profiler/profiler-decoder-library/BaseTypes.cs @@ -48,6 +48,26 @@ namespace Mono.Profiler { uint StartOffset {get; set;} uint EndOffset {get; set;} } + public struct StackSectionElement<LC,LM> where LC : ILoadedClass where LM : ILoadedMethod<LC> { + LM method; + public LM Method { + get { + return method; + } + set { + method = value; + } + } + bool isBeingJitted; + public bool IsBeingJitted { + get { + return isBeingJitted; + } + set { + isBeingJitted = value; + } + } + } public interface IExecutableMemoryRegion<UFR> : ILoadedElement where UFR : IUnmanagedFunctionFromRegion { ulong StartAddress {get;} ulong EndAddress {get;} @@ -133,6 +153,8 @@ namespace Mono.Profiler { void MethodJitEnd (LM m, ulong counter, bool success); void MethodFreed (LM m, ulong counter); + void AdjustStack (uint lastValidFrame, uint topSectionSize, StackSectionElement<LC,LM>[] topSection); + void MethodStatisticalHit (LM m); void UnknownMethodStatisticalHit (); void UnmanagedFunctionStatisticalHit (UFR f); @@ -164,6 +186,9 @@ namespace Mono.Profiler { void AllocationSummaryStart (uint collection, ulong startCounter, DateTime startTime); void ClassAllocationSummary (LC c, uint reachableInstances, uint reachableBytes, uint unreachableInstances, uint unreachableBytes); void AllocationSummaryEnd (uint collection, ulong endCounter, DateTime endTime); + + void InitializeData (byte[] data, uint currentOffset); + void DataProcessed (uint offset); } public class BaseLoadedElement : ILoadedElement { @@ -632,6 +657,7 @@ namespace Mono.Profiler { public enum DirectiveCodes { END = 0, ALLOCATIONS_CARRY_CALLER = 1, + ALLOCATIONS_HAVE_STACK = 2, LAST } @@ -646,8 +672,19 @@ namespace Mono.Profiler { allocationsCarryCallerMethod = true; } + bool allocationsHaveStackTrace; + public bool AllocationsHaveStackTrace { + get { + return allocationsHaveStackTrace; + } + } + public void AllocationsHaveStackTraceReceived () { + allocationsHaveStackTrace = true; + } + public DirectivesHandler () { allocationsCarryCallerMethod = false; + allocationsHaveStackTrace = false; } } @@ -699,6 +736,8 @@ namespace Mono.Profiler { public virtual void MethodJitEnd (LM m, ulong counter, bool success) {} public virtual void MethodFreed (LM m, ulong counter) {} + public virtual void AdjustStack (uint lastValidFrame, uint topSectionSize, StackSectionElement<LC,LM>[] topSection) {} + public virtual void MethodStatisticalHit (LM m) {} public virtual void UnknownMethodStatisticalHit () {} public virtual void UnmanagedFunctionStatisticalHit (UFR f) {} @@ -730,6 +769,199 @@ namespace Mono.Profiler { public virtual void AllocationSummaryStart (uint collection, ulong startCounter, DateTime startTime) {} public virtual void ClassAllocationSummary (LC c, uint reachableInstances, uint reachableBytes, uint unreachableInstances, uint unreachableBytes) {} public virtual void AllocationSummaryEnd (uint collection, ulong endCounter, DateTime endTime) {} + + public virtual void InitializeData (byte[] data, uint currentOffset) {} + public virtual void DataProcessed (uint offset) {} + } + + public class DebugProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> : BaseProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> where LC : ILoadedClass where LM : ILoadedMethod<LC> where UFR : IUnmanagedFunctionFromRegion where UFI : IUnmanagedFunctionFromID<MR,UFR> where MR : IExecutableMemoryRegion<UFR> where EH : ILoadedElementHandler<LC,LM,UFR,UFI,MR,HO,HS> where HO: IHeapObject<HO,LC> where HS: IHeapSnapshot<HO,LC> { + uint currentOffset; + public uint CurrentOffset { + get { + return currentOffset; + } + } + + byte[] data; + TextWriter output; + + public DebugProfilerEventHandler (EH loadedElements, TextWriter output) : base (loadedElements) { + this.output = output; + this.data = null; + this.currentOffset = 0; + } + + public override void Start (uint version, string runtimeFile, ProfilerFlags flags, ulong startCounter, DateTime startTime) { + output.WriteLine (""); + } + public override void End (uint version, ulong endCounter, DateTime endTime) { + output.WriteLine (""); + } + + public override void StartBlock (ulong startCounter, DateTime startTime, ulong threadId) { + output.WriteLine ("StartBlock: startCounter {0}, startTime {1}, threadId {2}", startCounter, startTime, threadId); + } + public override void EndBlock (ulong endCounter, DateTime endTime, ulong threadId) { + output.WriteLine ("StartBlock: endCounter {0}, endTime {1}, threadId {2}", endCounter, endTime, threadId); + } + + public override void ModuleLoaded (ulong threadId, ulong startCounter, ulong endCounter, string name, bool success) { + output.WriteLine ("ModuleLoaded"); + } + public override void ModuleUnloaded (ulong threadId, ulong startCounter, ulong endCounter, string name) { + output.WriteLine ("ModuleUnloaded"); + } + public override void AssemblyLoaded (ulong threadId, ulong startCounter, ulong endCounter, string name, bool success) { + output.WriteLine ("AssemblyLoaded"); + } + public override void AssemblyUnloaded (ulong threadId, ulong startCounter, ulong endCounter, string name) { + output.WriteLine ("AssemblyUnloaded"); + } + public override void ApplicationDomainLoaded (ulong threadId, ulong startCounter, ulong endCounter, string name, bool success) { + output.WriteLine ("ApplicationDomainLoaded"); + } + public override void ApplicationDomainUnloaded (ulong threadId, ulong startCounter, ulong endCounter, string name) { + output.WriteLine ("ApplicationDomainUnloaded"); + } + + public override void SetCurrentThread (ulong threadId) { + output.WriteLine ("SetCurrentThread"); + } + + public override void ClassStartLoad (LC c, ulong counter) { + output.WriteLine ("ClassStartLoad"); + } + public override void ClassEndLoad (LC c, ulong counter, bool success) { + output.WriteLine ("ClassEndLoad"); + } + public override void ClassStartUnload (LC c, ulong counter) { + output.WriteLine ("ClassStartUnload"); + } + public override void ClassEndUnload (LC c, ulong counter) { + output.WriteLine ("ClassEndUnload"); + } + + public override void Allocation (LC c, uint size, LM caller, bool jitTime, ulong counter) { + output.WriteLine ("Allocation"); + } + public override void Exception (LC c, ulong counter) { + output.WriteLine ("Exception"); + } + + public override void MethodEnter (LM m, ulong counter) { + output.WriteLine ("MethodEnter"); + } + public override void MethodExit (LM m, ulong counter) { + output.WriteLine ("MethodExit"); + } + public override void MethodJitStart (LM m, ulong counter) { + output.WriteLine ("MethodJitStart"); + } + public override void MethodJitEnd (LM m, ulong counter, bool success) { + output.WriteLine ("MethodJitEnd"); + } + public override void MethodFreed (LM m, ulong counter) { + output.WriteLine ("MethodFreed"); + } + + public override void AdjustStack (uint lastValidFrame, uint topSectionSize, StackSectionElement<LC,LM>[] topSection) { + output.WriteLine ("AdjustStack"); + } + + public override void MethodStatisticalHit (LM m) { + output.WriteLine ("MethodStatisticalHit"); + } + public override void UnknownMethodStatisticalHit () { + output.WriteLine ("UnknownMethodStatisticalHit"); + } + public override void UnmanagedFunctionStatisticalHit (UFR f) { + output.WriteLine ("UnmanagedFunctionStatisticalHit"); + } + public override void UnmanagedFunctionStatisticalHit (UFI f) { + output.WriteLine ("UnmanagedFunctionStatisticalHit"); + } + public override void UnknownUnmanagedFunctionStatisticalHit (MR region, uint offset) { + output.WriteLine ("UnknownUnmanagedFunctionStatisticalHit"); + } + public override void UnknownUnmanagedFunctionStatisticalHit (ulong address) { + output.WriteLine ("UnknownUnmanagedFunctionStatisticalHit"); + } + public override void StatisticalCallChainStart (uint chainDepth) { + output.WriteLine ("StatisticalCallChainStart"); + } + + public override void ThreadStart (ulong threadId, ulong counter) { + output.WriteLine ("ThreadStart"); + } + public override void ThreadEnd (ulong threadId, ulong counter) { + output.WriteLine ("ThreadEnd"); + } + + public override void GarbageCollectionStart (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionStart"); + } + public override void GarbageCollectionEnd (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionEnd"); + } + public override void GarbageCollectionMarkStart (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionMarkStart"); + } + public override void GarbageCollectionMarkEnd (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionMarkEnd"); + } + public override void GarbageCollectionSweepStart (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionSweepStart"); + } + public override void GarbageCollectionSweepEnd (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionSweepEnd"); + } + public override void GarbageCollectionResize (uint collection, ulong newSize) { + output.WriteLine ("GarbageCollectionResize"); + } + public override void GarbageCollectionStopWorldStart (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionStopWorldStart"); + } + public override void GarbageCollectionStopWorldEnd (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionStopWorldEnd"); + } + public override void GarbageCollectionStartWorldStart (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionStartWorldStart"); + } + public override void GarbageCollectionStartWorldEnd (uint collection, uint generation, ulong counter) { + output.WriteLine ("GarbageCollectionStartWorldEnd"); + } + + public override void HeapReportStart (HS snapshot) { + output.WriteLine ("HeapReportStart"); + } + public override void HeapObjectUnreachable (LC c, uint size) { + output.WriteLine ("HeapObjectUnreachable"); + } + public override void HeapObjectReachable (HO o) { + output.WriteLine ("HeapObjectReachable"); + } + public override void HeapReportEnd (HS snapshot) { + output.WriteLine ("HeapReportEnd"); + } + + public override void AllocationSummaryStart (uint collection, ulong startCounter, DateTime startTime) { + output.WriteLine ("AllocationSummaryStart"); + } + public override void ClassAllocationSummary (LC c, uint reachableInstances, uint reachableBytes, uint unreachableInstances, uint unreachableBytes) { + output.WriteLine ("ClassAllocationSummary"); + } + public override void AllocationSummaryEnd (uint collection, ulong endCounter, DateTime endTime) { + output.WriteLine ("AllocationSummaryEnd"); + } + + public override void InitializeData (byte[] data, uint currentOffset) { + this.data = data; + this.currentOffset = currentOffset; + } + public override void DataProcessed (uint offset) { + BlockData.DumpData (data, output, currentOffset, offset); + currentOffset = offset; + } } public class BaseExecutableMemoryRegion<UFR> : BaseLoadedElement, IExecutableMemoryRegion<UFR> where UFR : IUnmanagedFunctionFromRegion, new() { diff --git a/Mono.Profiler/profiler-decoder-library/ChangeLog b/Mono.Profiler/profiler-decoder-library/ChangeLog index 6ff74049..9b89ce7b 100644 --- a/Mono.Profiler/profiler-decoder-library/ChangeLog +++ b/Mono.Profiler/profiler-decoder-library/ChangeLog @@ -1,3 +1,11 @@ +2008-10-10 Massimiliano Mantione <massi@ximian.com> + * BaseTypes.cs: + - Added support for handling the stack trace of each allocation event. + - Added a DebugProfilerEventHandler which helps detecting decoder bugs. + * ObjectModel.cs: Likewise. + * ObjectModel.cs: Likewise. + * Decoder.cs: Likewise. + 2008-09-17 Massimiliano Mantione <massi@ximian.com> * ObjectModel.cs: Add "jit time support" to the call stack. * EventProcessor.cs: Likewise. diff --git a/Mono.Profiler/profiler-decoder-library/Decoder.cs b/Mono.Profiler/profiler-decoder-library/Decoder.cs index e6111fa7..1f5a4b3c 100644 --- a/Mono.Profiler/profiler-decoder-library/Decoder.cs +++ b/Mono.Profiler/profiler-decoder-library/Decoder.cs @@ -249,6 +249,7 @@ namespace Mono.Profiler { GC_STOP_WORLD = 6, GC_START_WORLD = 7, JIT_TIME_ALLOCATION = 8, + STACK_SECTION = 9, MASK = 15 } GenericEvent GenericEventFromEventCode (int eventCode) { @@ -296,11 +297,14 @@ namespace Mono.Profiler { public void Decode<LC,LM,UFR,UFI,MR,EH,HO,HS> (IProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> handler) where LC : ILoadedClass where LM : ILoadedMethod<LC> where UFR : IUnmanagedFunctionFromRegion where UFI : IUnmanagedFunctionFromID<MR,UFR> where MR : IExecutableMemoryRegion<UFR> where EH : ILoadedElementHandler<LC,LM,UFR,UFI,MR,HO,HS> where HO: IHeapObject<HO,LC> where HS: IHeapSnapshot<HO,LC> { uint offsetInBlock = 0; + StackSectionElement<LC,LM>[] stackSection = new StackSectionElement<LC,LM> [32]; if (data == null) { throw new DecodingException (this, 0, "Decoding used block"); } + handler.InitializeData (data, 0); + try { //LogLine (" *** DECODING at offset {0} (code {1})", fileOffset, code); switch (code) { @@ -319,6 +323,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK INTRO: version {0}, runtimeFile {1}, flags {2}, startCounter {3}, startTime {4}", version, runtimeFile, (ProfilerFlags) flags, startCounter, startTime); handler.Start (version, runtimeFile, (ProfilerFlags) flags, startCounter, microsecondsFromEpochToDateTime (startTime)); + handler.DataProcessed (offsetInBlock); break; } case BlockCode.END : { @@ -332,6 +337,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK END: version {0}, endCounter {1}, endTime {2}", version, endCounter, endTime); handler.End (version, endCounter, microsecondsFromEpochToDateTime (endTime)); + handler.DataProcessed (offsetInBlock); break; } case BlockCode.LOADED : { @@ -348,14 +354,17 @@ namespace Mono.Profiler { switch ((LoadedItemInfo) kind) { case LoadedItemInfo.APPDOMAIN: { handler.ApplicationDomainLoaded (threadId, startCounter, endCounter, itemName, success); + handler.DataProcessed (offsetInBlock); break; } case LoadedItemInfo.ASSEMBLY: { handler.AssemblyLoaded (threadId, startCounter, endCounter, itemName, success); + handler.DataProcessed (offsetInBlock); break; } case LoadedItemInfo.MODULE: { handler.ModuleLoaded (threadId, startCounter, endCounter, itemName, success); + handler.DataProcessed (offsetInBlock); break; } default: { @@ -376,14 +385,17 @@ namespace Mono.Profiler { switch ((LoadedItemInfo) kind) { case LoadedItemInfo.APPDOMAIN: { handler.ApplicationDomainUnloaded (threadId, startCounter, endCounter, itemName); + handler.DataProcessed (offsetInBlock); break; } case LoadedItemInfo.ASSEMBLY: { handler.AssemblyUnloaded (threadId, startCounter, endCounter, itemName); + handler.DataProcessed (offsetInBlock); break; } case LoadedItemInfo.MODULE: { handler.ModuleUnloaded (threadId, startCounter, endCounter, itemName); + handler.DataProcessed (offsetInBlock); break; } default: { @@ -400,6 +412,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK MAPPING (START): startCounter {0}, startTime {1}, threadId {2}", startCounter, startTime, threadId); handler.StartBlock (startCounter, microsecondsFromEpochToDateTime (startTime), threadId); handler.SetCurrentThread (threadId); + handler.DataProcessed (offsetInBlock); uint itemId; for (itemId = ReadUint (ref offsetInBlock); itemId != 0; itemId = ReadUint (ref offsetInBlock)) { @@ -420,6 +433,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK MAPPING (END): endCounter {0}, endTime {1}", endCounter, endTime); handler.EndBlock (endCounter, microsecondsFromEpochToDateTime (endTime), threadId); + handler.DataProcessed (offsetInBlock); break; } case BlockCode.EVENTS : { @@ -430,6 +444,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (START): startCounter {0}, startTime {1}, threadId {2}", startCounter, startTime, threadId); handler.StartBlock (startCounter, microsecondsFromEpochToDateTime (startTime), threadId); handler.SetCurrentThread (threadId); + handler.DataProcessed (offsetInBlock); ulong baseCounter = ReadUlong (ref offsetInBlock); @@ -450,6 +465,7 @@ namespace Mono.Profiler { } //LogLine ("BLOCK EVENTS (PACKED:CLASS_ALLOCATION): classId {0}, classSize {1}, callerId {2}", classId, classSize, callerId); handler.Allocation (handler.LoadedElements.GetClass (classId), classSize, (callerId != 0) ? handler.LoadedElements.GetMethod (callerId) : default (LM), false, 0); + handler.DataProcessed (offsetInBlock); break; } case PackedEventCode.CLASS_EVENT: { @@ -461,6 +477,7 @@ namespace Mono.Profiler { baseCounter += counterDelta; //LogLine ("BLOCK EVENTS (CLASS:EXCEPTION): classId {0}, counterDelta {1}", classId, counterDelta); handler.Exception (handler.LoadedElements.GetClass (classId), baseCounter); + handler.DataProcessed (offsetInBlock); break; } case ClassEvent.LOAD: { @@ -471,8 +488,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (CLASS:LOAD): classId {0}, classSize {1}, kind {2}", classId, counterDelta, kind); if (kind == EventKind.START) { handler.ClassStartLoad (handler.LoadedElements.GetClass (classId), baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.ClassEndLoad (handler.LoadedElements.GetClass (classId), baseCounter, EventSuccessFromEventCode (packedData)); + handler.DataProcessed (offsetInBlock); } break; } @@ -484,8 +503,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (CLASS:UNLOAD): classId {0}, counterDelta {1}, kind {2}", classId, counterDelta, kind); if (kind == EventKind.START) { handler.ClassStartUnload (handler.LoadedElements.GetClass (classId), baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.ClassEndUnload (handler.LoadedElements.GetClass (classId), baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -504,6 +525,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (PACKED:METHOD_ENTER): methodId {0}, counterDelta {1}", methodId, counterDelta); handler.MethodEnter (handler.LoadedElements.GetMethod (methodId), baseCounter); + handler.DataProcessed (offsetInBlock); break; } case PackedEventCode.METHOD_EXIT_EXPLICIT: { @@ -515,6 +537,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (PACKED:METHOD_EXIT_EXPLICIT): methodId {0}, counterDelta {1}", methodId, counterDelta); handler.MethodExit (handler.LoadedElements.GetMethod (methodId), baseCounter); + handler.DataProcessed (offsetInBlock); break; } case PackedEventCode.METHOD_EXIT_IMPLICIT: { @@ -530,6 +553,7 @@ namespace Mono.Profiler { baseCounter += counterDelta; //LogLine ("BLOCK EVENTS (METHOD:FREED): methodId {0}, counterDelta {1}", methodId, counterDelta); handler.MethodFreed (handler.LoadedElements.GetMethod (methodId), baseCounter); + handler.DataProcessed (offsetInBlock); break; } case MethodEvent.JIT: { @@ -540,8 +564,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (METHOD:JIT): methodId {0}, counterDelta {1}, kind {2}", methodId, counterDelta, kind); if (kind == EventKind.START) { handler.MethodJitStart (handler.LoadedElements.GetMethod (methodId), baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.MethodJitEnd (handler.LoadedElements.GetMethod (methodId), baseCounter, EventSuccessFromEventCode (packedData)); + handler.DataProcessed (offsetInBlock); } break; } @@ -564,8 +590,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (OTHER:GC_COLLECTION): generation {0}, counterDelta {1}, kind {2}", generation, counterDelta, kind); if (kind == EventKind.START) { handler.GarbageCollectionStart (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.GarbageCollectionEnd (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -579,8 +607,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (OTHER:GC_MARK): generation {0}, counterDelta {1}, kind {2}", generation, counterDelta, kind); if (kind == EventKind.START) { handler.GarbageCollectionMarkStart (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.GarbageCollectionMarkEnd (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -594,8 +624,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (OTHER:GC_SWEEP): generation {0}, counterDelta {1}, kind {2}", generation, counterDelta, kind); if (kind == EventKind.START) { handler.GarbageCollectionSweepStart (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.GarbageCollectionSweepEnd (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -604,6 +636,7 @@ namespace Mono.Profiler { uint collection = ReadUint (ref offsetInBlock); //LogLine ("BLOCK EVENTS (OTHER:GC_RESIZE): newSize {0}, collection {1}", newSize, collection); handler.GarbageCollectionResize (collection, newSize); + handler.DataProcessed (offsetInBlock); break; } case GenericEvent.GC_STOP_WORLD: { @@ -616,8 +649,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (OTHER:GC_STOP_WORLD): generation {0}, counterDelta {1}, kind {2}", generation, counterDelta, kind); if (kind == EventKind.START) { handler.GarbageCollectionStopWorldStart (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.GarbageCollectionStopWorldEnd (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -631,8 +666,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (OTHER:GC_START_WORLD): generation {0}, counterDelta {1}, kind {2}", generation, counterDelta, kind); if (kind == EventKind.START) { handler.GarbageCollectionStartWorldStart (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.GarbageCollectionStartWorldEnd (collection, generation, baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -644,8 +681,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK EVENTS (OTHER:THREAD): eventThreadId {0}, counterDelta {1}, kind {2}", eventThreadId, counterDelta, kind); if (kind == EventKind.START) { handler.ThreadStart (eventThreadId, baseCounter); + handler.DataProcessed (offsetInBlock); } else { handler.ThreadEnd (eventThreadId, baseCounter); + handler.DataProcessed (offsetInBlock); } break; } @@ -658,6 +697,26 @@ namespace Mono.Profiler { } //LogLine ("BLOCK EVENTS (OTHER:JIT_TIME_ALLOCATION): classId {0}, classSize {1}, callerId {2}", classId, classSize, callerId); handler.Allocation (handler.LoadedElements.GetClass (classId), classSize, (callerId != 0) ? handler.LoadedElements.GetMethod (callerId) : default (LM), true, 0); + handler.DataProcessed (offsetInBlock); + break; + } + case GenericEvent.STACK_SECTION: { + uint lastValidFrame = ReadUint (ref offsetInBlock); + uint topSectionSize = ReadUint (ref offsetInBlock); + + if (stackSection.Length < topSectionSize) { + stackSection = new StackSectionElement<LC,LM> [topSectionSize * 2]; + } + + for (int i = 0; i < topSectionSize; i++) { + uint methodId = ReadUint (ref offsetInBlock); + stackSection [i].IsBeingJitted = ((methodId & 1) != 0) ? true : false; + methodId >>= 1; + stackSection [i].Method = handler.LoadedElements.GetMethod (methodId); + } + + handler.AdjustStack (lastValidFrame, topSectionSize, stackSection); + handler.DataProcessed (offsetInBlock); break; } default: { @@ -676,6 +735,7 @@ namespace Mono.Profiler { ulong endTime = ReadUlong (ref offsetInBlock); //LogLine ("BLOCK EVENTS (END): endCounter {0}, endTime {1}", endCounter, endTime); handler.EndBlock (endCounter, microsecondsFromEpochToDateTime (endTime), threadId); + handler.DataProcessed (offsetInBlock); break; } case BlockCode.STATISTICAL : { @@ -684,6 +744,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK STATISTICAL (START): startCounter {0}, startTime {1}", startCounter, startTime); handler.StartBlock (startCounter, microsecondsFromEpochToDateTime (startTime), 0); + handler.DataProcessed (offsetInBlock); uint id; for (id = ReadUint (ref offsetInBlock); id != (uint) StatisticalCode.END; id = ReadUint (ref offsetInBlock)) { @@ -694,8 +755,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK STATISTICAL (METHOD): methodId {0}", methodId); if (methodId != 0) { handler.MethodStatisticalHit (handler.LoadedElements.GetMethod (methodId)); + handler.DataProcessed (offsetInBlock); } else { handler.UnknownMethodStatisticalHit (); + handler.DataProcessed (offsetInBlock); } break; } @@ -703,6 +766,7 @@ namespace Mono.Profiler { uint functionId = id >> 3; UFI function = handler.LoadedElements.GetUnmanagedFunctionByID (functionId); handler.UnmanagedFunctionStatisticalHit (function); + handler.DataProcessed (offsetInBlock); break; } case StatisticalCode.UNMANAGED_FUNCTION_NEW_ID: { @@ -712,6 +776,7 @@ namespace Mono.Profiler { MR region = handler.LoadedElements.GetExecutableMemoryRegion (regionId); UFI function = handler.LoadedElements.NewUnmanagedFunction (functionId, name, region); handler.UnmanagedFunctionStatisticalHit (function); + handler.DataProcessed (offsetInBlock); break; } case StatisticalCode.UNMANAGED_FUNCTION_OFFSET_IN_REGION: { @@ -723,14 +788,17 @@ namespace Mono.Profiler { if (function != null) { //LogLine ("BLOCK STATISTICAL (FUNCTION): regionId {0}, offset {1}", regionId, offset); handler.UnmanagedFunctionStatisticalHit (function); + handler.DataProcessed (offsetInBlock); } else { //LogLine ("BLOCK STATISTICAL (FUNCTION): regionId {0}, unknown offset {1}", regionId, offset); handler.UnknownUnmanagedFunctionStatisticalHit (region, offset); + handler.DataProcessed (offsetInBlock); } } else { ulong address = ReadUlong (ref offsetInBlock); //LogLine ("BLOCK STATISTICAL (FUNCTION): unknown address {0}", address); handler.UnknownUnmanagedFunctionStatisticalHit (address); + handler.DataProcessed (offsetInBlock); } break; } @@ -738,6 +806,7 @@ namespace Mono.Profiler { uint chainDepth = id >> 3; //LogLine ("BLOCK STATISTICAL (CHAIN): starting chain of depth {0}", chainDepth); handler.StatisticalCallChainStart (chainDepth); + handler.DataProcessed (offsetInBlock); break; } case StatisticalCode.REGIONS: { @@ -762,6 +831,7 @@ namespace Mono.Profiler { //} } handler.LoadedElements.SortExecutableMemoryRegions (); + handler.DataProcessed (offsetInBlock); break; } } @@ -782,11 +852,13 @@ namespace Mono.Profiler { HS snapshot = handler.LoadedElements.NewHeapSnapshot (collection, jobStartCounter, microsecondsFromEpochToDateTime (jobStartTime), jobEndCounter, microsecondsFromEpochToDateTime (jobEndTime), handler.LoadedElements.Classes, handler.LoadedElements.RecordHeapSnapshots); handler.HeapReportStart (snapshot); + handler.DataProcessed (offsetInBlock); ulong startCounter = ReadUlong (ref offsetInBlock); ulong startTime = ReadUlong (ref offsetInBlock); //LogLine ("BLOCK HEAP_DATA (START): ({0}:{1}-{2}:{3}) startCounter {4}, startTime {5}", jobStartCounter, jobStartTime, jobEndCounter, jobEndTime, startCounter, startTime); handler.StartBlock (startCounter, microsecondsFromEpochToDateTime (startTime), 0); + handler.DataProcessed (offsetInBlock); ulong item; ulong[] references = new ulong [50]; @@ -800,6 +872,7 @@ namespace Mono.Profiler { LC c = handler.LoadedElements.GetClass (classId); //LogLine (" Class id {0}, size {1}", classId, size); handler.HeapObjectUnreachable (c, size); + handler.DataProcessed (offsetInBlock); break; } case HeapSnapshotCode.OBJECT: { @@ -818,6 +891,7 @@ namespace Mono.Profiler { LC c = handler.LoadedElements.GetClass (classId); HO o = snapshot.NewHeapObject (objectId, c, size, references, referencesCount); handler.HeapObjectReachable (o); + handler.DataProcessed (offsetInBlock); break; } default: { @@ -826,11 +900,13 @@ namespace Mono.Profiler { } } handler.HeapReportEnd (snapshot); + handler.DataProcessed (offsetInBlock); ulong endCounter = ReadUlong (ref offsetInBlock); ulong endTime = ReadUlong (ref offsetInBlock); //LogLine ("BLOCK HEAP_DATA (END): endCounter {0}, endTime {1}", endCounter, endTime); handler.EndBlock (endCounter, microsecondsFromEpochToDateTime (endTime), 0); + handler.DataProcessed (offsetInBlock); break; } case BlockCode.HEAP_SUMMARY : { @@ -841,6 +917,7 @@ namespace Mono.Profiler { //LogLine ("BLOCK HEAP_SUMMARY (START): ([]{0}:{1}) startCounter {4}, startTime {5}", collection, startCounter, startTime); handler.StartBlock (startCounter, microsecondsFromEpochToDateTime (startTime), 0); handler.AllocationSummaryStart (collection, startCounter, microsecondsFromEpochToDateTime (startTime)); + handler.DataProcessed (offsetInBlock); uint id; for (id = ReadUint (ref offsetInBlock); id != 0; id = ReadUint (ref offsetInBlock)) { @@ -851,19 +928,23 @@ namespace Mono.Profiler { LC c = handler.LoadedElements.GetClass (id); handler.ClassAllocationSummary (c, reachableInstances, reachableBytes, unreachableInstances, unreachableBytes); + handler.DataProcessed (offsetInBlock); } ulong endCounter = ReadUlong (ref offsetInBlock); ulong endTime = ReadUlong (ref offsetInBlock); handler.AllocationSummaryEnd (collection, endCounter, microsecondsFromEpochToDateTime (endTime)); + handler.DataProcessed (offsetInBlock); //LogLine ("BLOCK HEAP_SUMMARY (END): endCounter {0}, endTime {1}", endCounter, endTime); handler.EndBlock (endCounter, microsecondsFromEpochToDateTime (endTime), 0); + handler.DataProcessed (offsetInBlock); break; } case BlockCode.DIRECTIVES : { ulong startCounter = ReadUlong (ref offsetInBlock); ulong startTime = ReadUlong (ref offsetInBlock); handler.StartBlock (startCounter, microsecondsFromEpochToDateTime (startTime), 0); + handler.DataProcessed (offsetInBlock); //LogLine ("BLOCK DIRECTIVES (START): startCounter {0}, startTime {1}", startCounter, startTime); DirectiveCodes directive = (DirectiveCodes) ReadUint (ref offsetInBlock); @@ -873,6 +954,10 @@ namespace Mono.Profiler { //LogLine ("BLOCK DIRECTIVES (START): ALLOCATIONS_CARRY_CALLER"); handler.Directives.AllocationsCarryCallerMethodReceived (); break; + case DirectiveCodes.ALLOCATIONS_HAVE_STACK: + //LogLine ("BLOCK DIRECTIVES (START): ALLOCATIONS_HAVE_STACK"); + handler.Directives.AllocationsHaveStackTraceReceived (); + break; default: throw new DecodingException (this, offsetInBlock, String.Format ("unknown directive {0}", directive)); } @@ -883,6 +968,7 @@ namespace Mono.Profiler { ulong endCounter = ReadUlong (ref offsetInBlock); ulong endTime = ReadUlong (ref offsetInBlock); handler.EndBlock (endCounter, microsecondsFromEpochToDateTime (endTime), 0); + handler.DataProcessed (offsetInBlock); //LogLine ("BLOCK DIRECTIVES (END): endCounter {0}, endTime {1}", endCounter, endTime); break; } @@ -895,12 +981,79 @@ namespace Mono.Profiler { throw new DecodingException (this, offsetInBlock, String.Format ("Block ended at offset {0} but its declared length is {1}", offsetInBlock, length)); } } catch (DecodingException e) { + if (handleExceptions) { + HandleDecodingException<LC,LM,UFR,UFI,MR,EH,HO,HS> (e, offsetInBlock, handler); + } throw e; } catch (Exception e) { + if (handleExceptions) { + HandleRegularException<LC,LM,UFR,UFI,MR,EH,HO,HS> (e, offsetInBlock, handler); + } throw new DecodingException(this, offsetInBlock, e.Message, e); } } + bool handleExceptions = true; + + void DumpDebugInformation<LC,LM,UFR,UFI,MR,EH,HO,HS> (uint offsetInBlock, IProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> handler) where LC : ILoadedClass where LM : ILoadedMethod<LC> where UFR : IUnmanagedFunctionFromRegion where UFI : IUnmanagedFunctionFromID<MR,UFR> where MR : IExecutableMemoryRegion<UFR> where EH : ILoadedElementHandler<LC,LM,UFR,UFI,MR,HO,HS> where HO: IHeapObject<HO,LC> where HS: IHeapSnapshot<HO,LC> { + if (debugLog != null) { + debugLog.WriteLine ("Attempting to decode data printing block contents..."); + handleExceptions = false; + try { + DebugProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> debugHandler = + new DebugProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> (handler.LoadedElements, debugLog); + debugLog.WriteLine ("Current block of type {0} (file offset {1}, length {2})", Code, FileOffset, Length); + Decode (debugHandler); + + } catch (Exception e) { + debugLog.WriteLine ("While attempting decoding, got exception {0}", e.Message); + DumpData (data, debugLog, offsetInBlock - 8, offsetInBlock + 24); + } finally { + handleExceptions = true; + } + } + } + void HandleDecodingException<LC,LM,UFR,UFI,MR,EH,HO,HS> (DecodingException e, uint offsetInBlock, IProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> handler) where LC : ILoadedClass where LM : ILoadedMethod<LC> where UFR : IUnmanagedFunctionFromRegion where UFI : IUnmanagedFunctionFromID<MR,UFR> where MR : IExecutableMemoryRegion<UFR> where EH : ILoadedElementHandler<LC,LM,UFR,UFI,MR,HO,HS> where HO: IHeapObject<HO,LC> where HS: IHeapSnapshot<HO,LC> { + if (debugLog != null) { + debugLog.WriteLine ("ERROR: DecodingException in block of code {0}, length {1}, file offset {2}, block offset {3}: {4}", e.FailingData.Code, e.FailingData.Length, e.FailingData.FileOffset, e.OffsetInBlock, e.Message); + debugLog.WriteLine (e.StackTrace); + if (e.InnerException != null) { + debugLog.WriteLine ("Original stack trace:"); + debugLog.WriteLine (e.InnerException.StackTrace); + } + DumpDebugInformation<LC,LM,UFR,UFI,MR,EH,HO,HS> (offsetInBlock, handler); + } + + throw e; + } + void HandleRegularException<LC,LM,UFR,UFI,MR,EH,HO,HS> (Exception e, uint offsetInBlock, IProfilerEventHandler<LC,LM,UFR,UFI,MR,EH,HO,HS> handler) where LC : ILoadedClass where LM : ILoadedMethod<LC> where UFR : IUnmanagedFunctionFromRegion where UFI : IUnmanagedFunctionFromID<MR,UFR> where MR : IExecutableMemoryRegion<UFR> where EH : ILoadedElementHandler<LC,LM,UFR,UFI,MR,HO,HS> where HO: IHeapObject<HO,LC> where HS: IHeapSnapshot<HO,LC> { + if (debugLog != null) { + debugLog.WriteLine ("ERROR: Exception in block of code {0}, length {1}, file offset {2}, block offset {3}: {4}", Code, Length, FileOffset, offsetInBlock, e.Message); + debugLog.WriteLine (e.StackTrace); + DumpDebugInformation<LC,LM,UFR,UFI,MR,EH,HO,HS> (offsetInBlock, handler); + } + + throw e; + } + + static public void DumpData (byte[] data, TextWriter output, uint startOffset, uint endOffset) { + uint currentIndex = 0; + while (startOffset < endOffset) { + if (currentIndex % 8 == 0) { + if ((currentIndex != 0)) { + output.WriteLine (); + } + output.Write (" [{0}-{1}]", startOffset, startOffset + 7); + } + output.Write (" "); + output.Write (data [startOffset]); + + startOffset ++; + currentIndex ++; + } + output.WriteLine (); + } + public BlockData (uint fileOffset, BlockCode code, int length, byte[] data) { this.fileOffset = fileOffset; this.code = code; diff --git a/Mono.Profiler/profiler-decoder-library/EventProcessor.cs b/Mono.Profiler/profiler-decoder-library/EventProcessor.cs index 65c76b52..cf7e580b 100644 --- a/Mono.Profiler/profiler-decoder-library/EventProcessor.cs +++ b/Mono.Profiler/profiler-decoder-library/EventProcessor.cs @@ -208,13 +208,21 @@ namespace Mono.Profiler { public override void ClassEndUnload (LoadedClass c, ulong counter) {} public override void Allocation (LoadedClass c, uint size, LoadedMethod caller, bool jitTime, ulong counter) { + StackTrace trace; + + if (Directives.AllocationsHaveStackTrace) { + trace = StackTrace.NewStackTrace (stack); + } else { + trace = null; + } + if (caller == null) { if ((stack != null) && (stack.StackTop != null)) { caller = stack.StackTop.Method; jitTime = stack.StackTop.IsBeingJitted; } } - c.InstanceCreated (size, caller, jitTime); + c.InstanceCreated (size, caller, jitTime, trace); } public override void Exception (LoadedClass c, ulong counter) {} @@ -239,6 +247,9 @@ namespace Mono.Profiler { public override void MethodFreed (LoadedMethod m, ulong counter) {} + public override void AdjustStack (uint lastValidFrame, uint topSectionSize, StackSectionElement<LoadedClass,LoadedMethod>[] topSection) { + stack.AdjustStack (lastValidFrame, topSectionSize, topSection); + } uint remainingCallersInChain; IStatisticalHitItem lastCallee; diff --git a/Mono.Profiler/profiler-decoder-library/ObjectModel.cs b/Mono.Profiler/profiler-decoder-library/ObjectModel.cs index 23a3d2b2..badb09c1 100644 --- a/Mono.Profiler/profiler-decoder-library/ObjectModel.cs +++ b/Mono.Profiler/profiler-decoder-library/ObjectModel.cs @@ -47,7 +47,7 @@ namespace Mono.Profiler { return a.AllocatedBytes.CompareTo (b.AllocatedBytes); }; - internal void InstanceCreated (uint size, LoadedMethod method, bool jitTime) { + internal void InstanceCreated (uint size, LoadedMethod method, bool jitTime, StackTrace stackTrace) { allocatedBytes += size; currentlyAllocatedBytes += size; if (method != null) { @@ -71,7 +71,7 @@ namespace Mono.Profiler { callerMethod = new AllocationsPerMethod (method); methods.Add (method.ID, callerMethod); } - callerMethod.Allocation (size); + callerMethod.Allocation (size, stackTrace); } } @@ -79,14 +79,8 @@ namespace Mono.Profiler { currentlyAllocatedBytes -= size; } - public class AllocationsPerMethod { - LoadedMethod method; - public LoadedMethod Method { - get { - return method; - } - } - + public abstract class AllocationsPerItem<T> { + protected T item; uint allocatedBytes; public uint AllocatedBytes { get { @@ -99,22 +93,88 @@ namespace Mono.Profiler { return allocatedInstances; } } - internal void Allocation (uint allocatedBytes) { + protected void InternalAllocation (uint allocatedBytes) { this.allocatedBytes += allocatedBytes; this.allocatedInstances ++; } - public static Comparison<AllocationsPerMethod> CompareByAllocatedBytes = delegate (AllocationsPerMethod a, AllocationsPerMethod b) { + + public static Comparison<AllocationsPerItem<T>> CompareByAllocatedBytes = delegate (AllocationsPerItem<T> a, AllocationsPerItem<T> b) { return a.AllocatedBytes.CompareTo (b.AllocatedBytes); }; - public static Comparison<AllocationsPerMethod> CompareByAllocatedInstances = delegate (AllocationsPerMethod a, AllocationsPerMethod b) { + public static Comparison<AllocationsPerItem<T>> CompareByAllocatedInstances = delegate (AllocationsPerItem<T> a, AllocationsPerItem<T> b) { return a.AllocatedInstances.CompareTo (b.AllocatedInstances); }; - public AllocationsPerMethod (LoadedMethod method) { - this.method = method; + protected AllocationsPerItem (T item) { + this.item = item; + allocatedInstances = 0; allocatedBytes = 0; } } + public class AllocationsPerMethod : AllocationsPerItem<LoadedMethod> { + public LoadedMethod Method { + get { + return item; + } + } + + Dictionary<uint,AllocationsPerStackTrace> stackTraces; + public AllocationsPerStackTrace[] StackTraces { + get { + if (stackTraces != null) { + AllocationsPerStackTrace[] result = new AllocationsPerStackTrace [stackTraces.Count]; + stackTraces.Values.CopyTo (result, 0); + return result; + } else { + return new AllocationsPerStackTrace [0]; + } + } + } + public int StackTracesCount { + get { + if (stackTraces != null) { + return stackTraces.Count; + } else { + return 0; + } + } + } + + internal void Allocation (uint allocatedBytes, StackTrace stackTrace) { + InternalAllocation (allocatedBytes); + if (stackTrace != null) { + if (stackTraces == null) { + stackTraces = new Dictionary<uint,AllocationsPerStackTrace> (); + } + + AllocationsPerStackTrace allocationsPerStackTrace; + if (stackTraces.ContainsKey (stackTrace.ID)) { + allocationsPerStackTrace = stackTraces [stackTrace.ID]; + } else { + allocationsPerStackTrace = new AllocationsPerStackTrace (stackTrace); + stackTraces [stackTrace.ID] = allocationsPerStackTrace; + } + allocationsPerStackTrace.Allocation (allocatedBytes); + } + } + + public AllocationsPerMethod (LoadedMethod method) : base (method) { + } + } + public class AllocationsPerStackTrace : AllocationsPerItem<StackTrace> { + public StackTrace Trace { + get { + return item; + } + } + + internal void Allocation (uint allocatedBytes) { + InternalAllocation (allocatedBytes); + } + + public AllocationsPerStackTrace (StackTrace trace) : base (trace) { + } + } Dictionary<uint,AllocationsPerMethod> allocationsPerMethod; public AllocationsPerMethod[] Methods { @@ -158,6 +218,114 @@ namespace Mono.Profiler { } } + public class StackTrace { + LoadedMethod topMethod; + public LoadedMethod TopMethod { + get { + return topMethod; + } + } + StackTrace caller; + public StackTrace Caller { + get { + return caller; + } + } + bool methodIsBeingJitted; + public bool MethodIsBeingJitted { + get { + return methodIsBeingJitted; + } + } + uint level; + public uint Level { + get { + return level; + } + } + uint id; + public uint ID { + get { + return id; + } + } + + static uint nextFreeId = 1; + + StackTrace (LoadedMethod topMethod, StackTrace caller, bool methodIsBeingJitted) { + this.topMethod = topMethod; + this.caller = caller; + this.methodIsBeingJitted = methodIsBeingJitted; + this.level = caller != null ? caller.level + 1 : 1; + this.id = nextFreeId; + nextFreeId ++; + } + + bool MatchesCallStack (CallStack.StackFrame stack) { + StackTrace currentTrace = this; + + while ((currentTrace != null) && (stack != null)) { + if (currentTrace.TopMethod != stack.Method) { + return false; + } + if (currentTrace.methodIsBeingJitted != stack.IsBeingJitted) { + return false; + } + currentTrace = currentTrace.Caller; + stack = stack.Caller; + } + + if ((currentTrace == null) && (stack == null)) { + return true; + } else { + return false; + } + } + + internal static StackTrace NewStackTrace (CallStack stack) { + return NewStackTrace (stack.StackTop); + } + + static StackTrace NewStackTrace (CallStack.StackFrame frame) { + if (frame == null) { + return null; + } + + if (frame.Level> (uint) tracesByLevel.Length) { + Dictionary<uint,List<StackTrace>> [] newTracesByLevel = new Dictionary<uint,List<StackTrace>> [frame.Level * 2]; + Array.Copy (tracesByLevel, newTracesByLevel, tracesByLevel.Length); + tracesByLevel = newTracesByLevel; + } + + Dictionary<uint,List<StackTrace>> tracesByMethod = tracesByLevel [frame.Level]; + if (tracesByLevel [frame.Level] == null) { + tracesByMethod = new Dictionary<uint,List<StackTrace>> (); + tracesByLevel [frame.Level] = tracesByMethod; + } + + List<StackTrace> traces; + if (tracesByMethod.ContainsKey (frame.Method.ID)) { + traces = tracesByMethod [frame.Method.ID]; + } else { + traces = new List<StackTrace> (); + tracesByMethod [frame.Method.ID] = traces; + } + + foreach (StackTrace trace in traces) { + if (trace.MatchesCallStack (frame)) { + return trace; + } + } + + StackTrace callerTrace = NewStackTrace (frame.Caller); + StackTrace result = new StackTrace (frame.Method, callerTrace, frame.IsBeingJitted); + traces.Add (result); + return result; + } + + static Dictionary<uint,List<StackTrace>> [] tracesByLevel = new Dictionary<uint,List<StackTrace>> [64]; + } + class CallStack { internal class StackFrame { LoadedMethod method; @@ -292,6 +460,21 @@ namespace Mono.Profiler { PopMethod (method, counter, true); } + internal void AdjustStack (uint lastValidFrame, uint topSectionSize, StackSectionElement<LoadedClass,LoadedMethod>[] topSection) { + if (Depth >= lastValidFrame) { + while (Depth > lastValidFrame) { + StackFrame lastTop = stackTop; + stackTop = stackTop.Caller; + StackFrame.FreeFrame (lastTop); + } + for (int i = (int) topSectionSize - 1; i >= 0; i--) { + stackTop = StackFrame.FrameFactory (topSection [i].Method, 0, topSection [i].IsBeingJitted, stackTop); + } + } else { + throw new Exception (String.Format ("Depth is {0} but lastValidFrame is {1}", Depth, lastValidFrame)); + } + } + internal CallStack (ulong threadId) { this.threadId = threadId; stackTop = null; |