Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMassimiliano Mantione <massi@mono-cvs.ximian.com>2008-10-10 18:20:44 +0400
committerMassimiliano Mantione <massi@mono-cvs.ximian.com>2008-10-10 18:20:44 +0400
commit73b0c1958f596be55064326243c3fcf08587e7d1 (patch)
tree31686544c2f29dd7900fba9f68ece395f66c8f64 /Mono.Profiler
parent348248edb15c4370a7fca451cda2da070ad4fe46 (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.cs232
-rw-r--r--Mono.Profiler/profiler-decoder-library/ChangeLog8
-rw-r--r--Mono.Profiler/profiler-decoder-library/Decoder.cs153
-rw-r--r--Mono.Profiler/profiler-decoder-library/EventProcessor.cs13
-rw-r--r--Mono.Profiler/profiler-decoder-library/ObjectModel.cs213
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;