internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("ALLOC: Object allocated at address {0}", m_address); ObjectAllocation alloc = new ObjectAllocation(); alloc.m_thread = sess.m_currentThreadPID; alloc.m_address = m_address; alloc.m_size = m_size; if (!sess.m_threadCallStacks.ContainsKey(sess.m_currentThreadPID)) { sess.m_threadCallStacks.Add(sess.m_currentThreadPID, new Stack<uint>()); } alloc.m_callStack = sess.m_threadCallStacks[sess.m_currentThreadPID].ToArray(); Array.Reverse(alloc.m_callStack); sess.ResolveTypeName(m_type); //Cache type name. if (sess.m_liveObjectTable.BinarySearch(m_address) < 0) { sess.m_liveObjectTable.Add(m_address); sess.m_liveObjectTable.Sort(); } alloc.m_objectType = new ObjectType(m_type, m_rank); sess.AddEvent(alloc); }
internal void ProcessEvent(_PRF.ProfilerSession ps, _PRF.ProfilerEvent pe) { ulong callstack; if (m_processedFirstEvent == false) { m_processedFirstEvent = true; m_startTime = pe.Time; m_lastWrittenTime = pe.Time; } else { if (pe.Time >= m_lastWrittenTime + 1) { // Mimic the 5-ms granularity of the CLRProfiler. m_sw.WriteLine("i {0}", pe.Time - m_startTime); m_lastWrittenTime = pe.Time; } } switch (pe.Type) { case _PRF.ProfilerEvent.EventType.HeapDump: { _PRF.HeapDump hd = (_PRF.HeapDump)pe; foreach (_PRF.HeapDumpRoot hdr in hd.RootTable) { uint md = 0; if (hdr.m_type == HeapDumpRoot.RootType.Stack) { /* This needs to come first because it has the side effect of writing a * method definition out if one doesn't exist for it yet. */ md = FindMethod(ps, hdr.m_method); } m_sw.Write("e 0x{0:x8} ", hdr.m_address); switch (hdr.m_type) { case HeapDumpRoot.RootType.Finalizer: m_sw.Write("2 "); break; case HeapDumpRoot.RootType.Stack: m_sw.Write("1 "); break; default: m_sw.Write("0 "); break; } switch (hdr.m_flags) { case HeapDumpRoot.RootFlags.Pinned: m_sw.Write("1 "); break; default: m_sw.Write("0 "); break; } switch (hdr.m_type) { case HeapDumpRoot.RootType.Stack: m_sw.WriteLine("{0}", md); break; default: m_sw.WriteLine("0"); break; } } foreach (_PRF.HeapDumpObject hdo in hd.ObjectTable) { ulong typeid = FindType(ps, hdo.m_type); m_sw.Write("o 0x{0:x8} {1} {2}", hdo.m_address, typeid, hdo.m_size); if (hdo.m_references != null) { foreach (uint ptr in hdo.m_references) { m_sw.Write(" 0x{0:x8}", ptr); } } m_sw.WriteLine(); } break; } case _PRF.ProfilerEvent.EventType.Call: { _PRF.FunctionCall f = (_PRF.FunctionCall)pe; callstack = MakeCallStack(ps, f.m_callStack); m_sw.WriteLine("c {0} {1}", f.m_thread, callstack); break; } case _PRF.ProfilerEvent.EventType.Return: case _PRF.ProfilerEvent.EventType.ContextSwitch: //The CLRProfiler does not care about function timing; it's primary goal is to display memory usage over time, and barely considers function calls break; case _PRF.ProfilerEvent.EventType.Allocation: { _PRF.ObjectAllocation a = (_PRF.ObjectAllocation)pe; callstack = MakeCallStack(ps, a.m_callStack, a.m_objectType, a.m_size); m_sw.WriteLine("! {0} 0x{1:x} {2}", a.m_thread, a.m_address, callstack); break; } case _PRF.ProfilerEvent.EventType.Relocation: { _PRF.ObjectRelocation r = (_PRF.ObjectRelocation)pe; for (uint i = 0; i < r.m_relocationRegions.Length; i++) { m_sw.WriteLine("u 0x{0:x} 0x{1:x} {2}", r.m_relocationRegions[i].m_start, r.m_relocationRegions[i].m_start + r.m_relocationRegions[i].m_offset, r.m_relocationRegions[i].m_end - r.m_relocationRegions[i].m_start); } break; } case _PRF.ProfilerEvent.EventType.Deallocation: { _PRF.ObjectDeletion d = (_PRF.ObjectDeletion)pe; break; } case _PRF.ProfilerEvent.EventType.GarbageCollectionBegin: { _PRF.GarbageCollectionBegin gc = (_PRF.GarbageCollectionBegin)pe; uint lastObjAddress = ps.m_liveObjectTable[ps.m_liveObjectTable.Count - 1] + 1; m_sw.WriteLine("b 1 0 0 0x{0:x} {1} {2} 0", ps.HeapStart, lastObjAddress, ps.HeapBytesReserved); break; } case _PRF.ProfilerEvent.EventType.GarbageCollectionEnd: { _PRF.GarbageCollectionEnd gc = (_PRF.GarbageCollectionEnd)pe; for (int i = 0; i < gc.liveObjects.Count; i++) { //Send length of 1 for single object, regardless of true object length. m_sw.WriteLine("v 0x{0:x} 1", gc.liveObjects[i]); } uint lastObjAddress = ps.m_liveObjectTable[ps.m_liveObjectTable.Count - 1] + 1; m_sw.WriteLine("b 0 0 0 0x{0:x} {1} {2} 0", ps.HeapStart, lastObjAddress, ps.HeapBytesReserved); break; } case _PRF.ProfilerEvent.EventType.HeapCompactionBegin: { _PRF.HeapCompactionBegin gc = (_PRF.HeapCompactionBegin)pe; uint lastObjAddress = ps.m_liveObjectTable[ps.m_liveObjectTable.Count - 1] + 1; m_sw.WriteLine("b 1 0 0 0x{0:x} {1} {2} 0", ps.HeapStart, lastObjAddress, ps.HeapBytesReserved); break; } case _PRF.ProfilerEvent.EventType.HeapCompactionEnd: { _PRF.HeapCompactionEnd gc = (_PRF.HeapCompactionEnd)pe; uint lastObjAddress = ps.m_liveObjectTable[ps.m_liveObjectTable.Count - 1] + 1; m_sw.WriteLine("b 0 0 0 0x{0:x} {1} {2} 0", ps.HeapStart, lastObjAddress, ps.HeapBytesReserved); break; } } m_sw.Flush(); }