private ulong MakeCallStack(ProfilerSession ps, uint[] callStack, ObjectType type, uint size) { ulong typeid = FindType(ps, type); string flags = String.Format("1 {0} {1}", typeid, size); //"1" means a type id and size come before the call stack. return(MakeCallStackInternal(ps, callStack, flags)); }
public Exporter_CLRProfiler(ProfilerSession ps, string file) : base(ps, file) { m_methodIdLookup = new Dictionary <uint, uint>(); m_typeIdLookup = new Dictionary <ObjectType, ulong>(); m_nextMethodId = 1; m_nextTypeId = 1; m_nextCallstackId = 1; ps.OnEventAdd += new ProfilerSession.OnProfilerEventAddHandler(ProcessEvent); }
public Exporter_CLRProfiler(ProfilerSession ps, string file) : base(ps, file) { m_methodIdLookup = new Dictionary<uint, uint>(); m_typeIdLookup = new Dictionary<ObjectType, ulong>(); m_nextMethodId = 1; m_nextTypeId = 1; m_nextCallstackId = 1; ps.OnEventAdd += new ProfilerSession.OnProfilerEventAddHandler(ProcessEvent); }
public Exporter(ProfilerSession ps, string file) { if (!String.IsNullOrEmpty(file)) { m_fileName = file; } else { m_fileName = Path.GetTempFileName(); } m_fs = new FileStream(m_fileName, FileMode.Create, FileAccess.Write, FileShare.Read); m_sw = new StreamWriter(m_fs); }
private ulong FindType(_PRF.ProfilerSession ps, ObjectType type) { if (m_typeIdLookup.ContainsKey(type)) { return(m_typeIdLookup[type]); } else { //FIXME: Need to know which types are finalizable StringBuilder typeName = new StringBuilder(ps.ResolveTypeName(type.Type)); for (int i = 0; i < type.Rank; i++) { typeName.Append("[]"); } ulong typeid = m_nextTypeId++; m_typeIdLookup.Add(type, typeid); m_sw.WriteLine("t {0} 0 {1}", typeid, typeName.ToString()); return(typeid); } }
private ulong MakeCallStackInternal(ProfilerSession ps, uint[] callStack, string flags) { uint[] transStack = new uint[callStack.Length]; ulong id = m_nextCallstackId; m_nextCallstackId++; for (uint i = 0; i < callStack.Length; i++) { transStack[i] = FindMethod(ps, callStack[i]); } m_sw.Write("n {0} {1}", id, flags); for (uint i = 0; i < transStack.Length; i++) { m_sw.Write(" {0}", transStack[i]); } m_sw.WriteLine(); return(id); }
private uint FindMethod(_PRF.ProfilerSession ps, uint md) { if (m_methodIdLookup.ContainsKey(md)) { return(m_methodIdLookup[md]); } else { uint methodid = m_nextMethodId++; m_methodIdLookup.Add(md, methodid); string methodName; try { methodName = ps.m_engine.GetMethodName(md, true); } catch { methodName = "UNKNOWN METHOD"; } m_sw.WriteLine("f {0} {1} (UNKNOWN_ARGUMENTS) 0 0", methodid, methodName); return(methodid); } }
private ulong MakeCallStack(ProfilerSession ps, uint[] callStack, ObjectType type, uint size) { ulong typeid = FindType(ps, type); string flags = String.Format("1 {0} {1}", typeid, size); //"1" means a type id and size come before the call stack. return MakeCallStackInternal(ps, callStack, flags); }
private void bwConnecter_DoWork(System.Object sender, DoWorkEventArgs e) { BackgroundConnectorArguments bca = (BackgroundConnectorArguments)e.Argument; _DBG.PortDefinition port = bca.connectPort; Debug.Assert(m_engine == null); e.Result = false; #if USE_CONNECTION_MANAGER m_engine = m_port.DebugPortSupplier.Manager.Connect(port); #else m_engine = new _DBG.Engine(port); #endif m_killEmulator = false; lock (m_engine) { m_engine.StopDebuggerOnConnect = true; m_engine.OnCommand += new _DBG.CommandEventHandler(OnWPCommand); m_engine.OnMessage += new _DBG.MessageEventHandler(OnWPMessage); m_engine.Start(); const int retries = 50; bool connected = false; for (int i = 0; connected == false && i < retries; i++) { if (bwConnecter.CancellationPending) { e.Cancel = true; return; } connected = m_engine.TryToConnect(1, 100, false, _DBG.ConnectionSource.TinyCLR); } if (connected) { if (m_engine.Capabilities.Profiling == false) { throw new ApplicationException("This device is not running a version of TinyCLR that supports profiling."); } //Move IsDeviceInInitializeState(), IsDeviceInExitedState(), GetDeviceState(),EnsureProcessIsInInitializedState() to Debugger.dll? uint executionMode = 0; m_engine.SetExecutionMode(0, 0, out executionMode); if (bca.reboot || (executionMode & _WP.Commands.Debugging_Execution_ChangeConditions.c_State_Mask) != _WP.Commands.Debugging_Execution_ChangeConditions.c_State_Initialize) { m_engine.RebootDevice(_DBG.Engine.RebootOption.RebootClrWaitForDebugger); m_engine.TryToConnect(10, 1000); m_engine.SetExecutionMode(0, 0, out executionMode); Debug.Assert((executionMode & _WP.Commands.Debugging_Execution_ChangeConditions.c_State_Mask) == _WP.Commands.Debugging_Execution_ChangeConditions.c_State_Initialize); } m_engine.ThrowOnCommunicationFailure = true; m_session = new _PRF.ProfilerSession(m_engine); if (m_exporter != null) { m_exporter.Close(); } switch (bca.exporter) { case BackgroundConnectorArguments.ExporterType.CLRProfiler: m_exporter = new _PRF.Exporter_CLRProfiler(m_session, bca.outputFileName); break; #if DEBUG case BackgroundConnectorArguments.ExporterType.OffProf: m_exporter = new _PRF.Exporter_OffProf(m_session, bca.outputFileName); break; #endif default: throw new ArgumentException("Unsupported export format"); } m_session.EnableProfiling(); e.Result = true; } } return; }
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("<<< HEAP COMPACTION END"); // on CLR Profiler side: Need to preserve objects not relocated. sess.HeapBytesFree = m_freeBytes; HeapCompactionEnd hc = new HeapCompactionEnd(); sess.AddEvent(hc); }
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("<<< GARBAGE COLLECTION BEGIN"); sess.HeapBytesFree = m_freeBytes; GarbageCollectionEnd gc = new GarbageCollectionEnd(); gc.liveObjects = new List<uint>(sess.m_liveObjectTable); sess.AddEvent(gc); }
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("ALLOC: Object freed from address {0}", m_address); int objIndex = sess.m_liveObjectTable.BinarySearch(m_address); if (objIndex > -1) { sess.m_liveObjectTable.RemoveAt(objIndex); ObjectDeletion delete = new ObjectDeletion(); delete.address = m_address; sess.AddEvent(delete); } }
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 override void Process(ProfilerSession sess) { Tracing.PacketTrace("CALLS: Function returned on thread {0}", sess.m_currentThreadPID); if (sess.m_threadCallStacks.ContainsKey(sess.m_currentThreadPID)) { Debug.Assert(sess.m_threadCallStacks[sess.m_currentThreadPID].Count > 0); sess.m_threadCallStacks[sess.m_currentThreadPID].Pop(); } FunctionReturn f = new FunctionReturn(); f.m_thread = sess.m_currentThreadPID; f.duration = m_duration; sess.AddEvent(f); }
internal override void Process(ProfilerSession sess) { if (sess.m_currentHeapDump == null) { //Lost heap-dump start packet, and probably the roots too. throw new System.IO.IOException(); } HeapDumpObject hdo = new HeapDumpObject(); hdo.m_address = m_address; hdo.m_size = m_size; if(m_dt == _DBG.RuntimeDataType.DATATYPE_CLASS || m_dt == _DBG.RuntimeDataType.DATATYPE_VALUETYPE) { sess.ResolveTypeName(m_typedef); //Cache type name. hdo.m_type = new ObjectType(m_typedef); } else { _DBG.RuntimeDataType dt = (_DBG.RuntimeDataType)m_dt; if (dt == _DBG.RuntimeDataType.DATATYPE_SZARRAY) { sess.ResolveTypeName(m_arrayElementType); //Cache type name. hdo.m_type = new ObjectType(m_arrayElementType, m_arrayLevels); } else { hdo.m_type = new ObjectType((uint)m_dt); } } hdo.m_references = m_refs; Tracing.PacketTrace("object @ {0} ({1})", m_address, hdo.m_type); sess.m_currentHeapDump.m_objectTable.Add(hdo); }
public Exporter_OffProf(ProfilerSession ps, string file) : base(ps, file) { ps.OnEventAdd += new ProfilerSession.OnProfilerEventAddHandler(ProcessEvent); m_sess = ps; }
private ulong MakeCallStack(ProfilerSession ps, uint[] callStack) { return(MakeCallStackInternal(ps, callStack, "0")); //"0" means no referenced call stack or type or size. }
private void ProcessEvent(_PRF.ProfilerSession ps, _PRF.ProfilerEvent pe) { switch (pe.Type) { case _PRF.ProfilerEvent.EventType.Call: { _PRF.FunctionCall f = (_PRF.FunctionCall)pe; m_currentThread = f.m_thread; ThreadState ts; if (m_htThreads.ContainsKey(m_currentThread)) { ts = m_htThreads[m_currentThread]; } else { ts = new ThreadState(); ts.m_threadID = f.m_thread; m_htThreads[f.m_thread] = ts; } Call c = new Call(); c.Function = f.m_callStack[f.m_callStack.Length - 1]; try { m_sess.m_engine.GetMethodName(c.Function, true); } catch { } ts.m_call.AddChild(c); ts.m_call = c; break; } case _PRF.ProfilerEvent.EventType.Return: { _PRF.FunctionReturn f = (_PRF.FunctionReturn)pe; ThreadState ts; if (m_htThreads.ContainsKey(m_currentThread)) { ts = m_htThreads[m_currentThread]; } else { ts = new ThreadState(); ts.m_threadID = f.m_thread; m_htThreads[f.m_thread] = ts; } if ((f.duration & 0x80000000) == 0) { //OffView really really doesn't like negative times. ts.m_call.Duration += f.duration; } if (ts.m_call.Parent != null) { //Make timing inclusive. ts.m_call.Parent.Duration += ts.m_call.Duration; } ts.m_call = ts.m_call.Parent; break; } case _PRF.ProfilerEvent.EventType.ContextSwitch: { _PRF.ContextSwitch c = (_PRF.ContextSwitch)pe; m_currentThread = c.m_thread; break; } } }
internal override void Process(ProfilerSession sess) { if (sess.m_currentHeapDump == null) { //Lost heap-dump start packet. throw new System.IO.IOException(); } HeapDumpRoot hdr = new HeapDumpRoot(); hdr.m_address = m_address; switch(m_source) { case Packets.Commands.RootTypes.Root_AppDomain: hdr.m_type = HeapDumpRoot.RootType.AppDomain; break; case Packets.Commands.RootTypes.Root_Assembly: hdr.m_type = HeapDumpRoot.RootType.Assembly; break; case Packets.Commands.RootTypes.Root_Finalizer: hdr.m_type = HeapDumpRoot.RootType.Finalizer; break; case Packets.Commands.RootTypes.Root_Stack: hdr.m_type = HeapDumpRoot.RootType.Stack; break; case Packets.Commands.RootTypes.Root_Thread: hdr.m_type = HeapDumpRoot.RootType.Thread; break; } hdr.m_flags = HeapDumpRoot.RootFlags.None; hdr.m_method = m_method; sess.m_currentHeapDump.m_rootTable.Add(hdr); }
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(); }
internal override void Process(ProfilerSession sess) { m_thread = sess.m_currentThreadPID; if (m_assembly == 0) { m_assembly = sess.m_currentAssembly; } else { sess.m_currentAssembly = m_assembly; } uint md = m_assembly << Packets.Commands.Bits.AssemblyShift | m_method; Tracing.PacketTrace("CALLS: Thread {0} called function {1}", m_thread, md); if (!sess.m_threadCallStacks.ContainsKey(m_thread)) { sess.m_threadCallStacks.Add(m_thread, new Stack<uint>()); } sess.m_threadCallStacks[m_thread].Push(md); FunctionCall f = new FunctionCall(); f.m_thread = m_thread; f.m_callStack = sess.m_threadCallStacks[m_thread].ToArray(); Array.Reverse(f.m_callStack); sess.m_engine.GetMethodName(md, true); //Cache method name information while we still have a device. sess.AddEvent(f); }
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("CALLS: Switched to thread {0}", m_thread); ContextSwitch c = new ContextSwitch(); c.m_thread = m_thread; sess.m_currentThreadPID = m_thread; sess.AddEvent(c); }
internal void StartProfiler(string device, string logFile, string transport, string exePath, string buildPath, ArrayList referenceList, bool isDevEnvironment, string assemblyName ) { try { PortDefinition port = Utils.GetPort(device, transport, exePath); m_engine = new Engine(port); m_session = new ProfilerSession(m_engine); #if DEBUG m_exporter = new Exporter_OffProf(m_session, logFile); #endif lock (m_engine) { m_engine.StopDebuggerOnConnect = true; m_engine.Start(); bool connected = false; connected = m_engine.TryToConnect(20, 500, true, ConnectionSource.TinyCLR); if (connected) { if (m_engine.Capabilities.Profiling == false) { throw new ApplicationException("This device is not running a version of TinyCLR that supports profiling."); } // Deploy the test files to the device. Utils.DeployToDevice(buildPath, referenceList, m_engine, transport, isDevEnvironment, assemblyName); // Move IsDeviceInInitializeState(), IsDeviceInExitedState(), // GetDeviceState(),EnsureProcessIsInInitializedState() to Debugger.dll? m_engine.RebootDevice(Engine.RebootOption.RebootClrWaitForDebugger); if (!m_engine.TryToConnect(100, 500)) { throw new ApplicationException("Connection Failed"); } m_engine.ThrowOnCommunicationFailure = true; m_session.EnableProfiling(); m_session.SetProfilingOptions(true, false); m_engine.OnCommand += new CommandEventHandler(OnWPCommand); m_engine.ResumeExecution(); } else { throw new ApplicationException("Connection failed"); } } } catch (Exception ex) { SoftDisconnectDone(null, null); throw ex; } }
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("ALLOC: Objects relocated"); List<uint> newTable = new List<uint>(); for (int i = 0; i < sess.m_liveObjectTable.Count; i++ ) { uint ptr = sess.m_liveObjectTable[i]; uint j; for (j = 0; j < reloc.Length; j++) { if (ptr >= reloc[j].m_start && ptr <= reloc[j].m_end) { newTable.Add(ptr + reloc[j].m_offset); break; } } if (j == reloc.Length) { //No relocation for this object. newTable.Add(ptr); } } newTable.Sort(); sess.m_liveObjectTable = newTable; ObjectRelocation or = new ObjectRelocation(); or.m_relocationRegions = reloc; sess.AddEvent(or); }
internal abstract void Process(ProfilerSession sess);
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("GARBAGE COLLECTION BEGIN >>>"); sess.HeapBytesFree = m_freeBytes; GarbageCollectionBegin gc = new GarbageCollectionBegin(); sess.AddEvent(gc); }
internal override void Process(ProfilerSession sess) { sess.LastKnownTime += m_time; }
internal override void Process(ProfilerSession sess) { Tracing.PacketTrace("HEAP COMPACTION BEGIN >>>"); sess.HeapBytesFree = m_freeBytes; HeapCompactionBegin hc = new HeapCompactionBegin(); sess.AddEvent(hc); }
internal override void Process(ProfilerSession sess) { sess.HeapStart = m_heapAddress; sess.HeapBytesReserved = m_heapLength; }
internal override void Process(ProfilerSession sess) { if(sess.m_currentHeapDump != null) { //We lost a heap-dump end packet somewhere. //Insert one to clean up the last heap dump. HeapDumpStopPacket hdep = new HeapDumpStopPacket(null); hdep.Process(sess); } // Heap dump should update live object table. sess.m_currentHeapDump = new HeapDump(); Tracing.PacketTrace("HEAP DUMP BEGIN======================>"); }
private ulong MakeCallStack(ProfilerSession ps, uint[] callStack) { return MakeCallStackInternal(ps, callStack, "0"); //"0" means no referenced call stack or type or size. }
internal override void Process(ProfilerSession sess) { if (sess.m_currentHeapDump == null) { return; } //No heap dump to finish sess.HeapBytesUsed = m_heapBytesUsed; sess.AddEvent(sess.m_currentHeapDump); sess.m_currentHeapDump = null; Tracing.PacketTrace("<======================HEAP DUMP END"); }
private ulong MakeCallStackInternal(ProfilerSession ps, uint[] callStack, string flags) { uint[] transStack = new uint[callStack.Length]; ulong id = m_nextCallstackId; m_nextCallstackId++; for (uint i = 0; i < callStack.Length; i++) { transStack[i] = FindMethod(ps, callStack[i]); } m_sw.Write("n {0} {1}", id, flags); for (uint i = 0; i < transStack.Length; i++) { m_sw.Write(" {0}", transStack[i]); } m_sw.WriteLine(); return id; }