public void SaveClrJobs(string fileName) { using (var writer = new StreamWriter(fileName, false)) { var allClrJobs = new List <Tuple <ClrJob, ulong> >(); foreach (ISessionThreadBase thread in _sessionThreads.Values) { allClrJobs.AddRange(thread.ClrJobs.Select(clrJob => new Tuple <ClrJob, ulong>(clrJob, thread.OsThreadId))); } allClrJobs.Sort((x, y) => { ClrJob job1 = x.Item1; ClrJob job2 = y.Item1; int cmp = job1.Type.CompareTo(job2.Type); if (cmp == 0) { cmp = job1.StartNanoseconds.CompareTo(job2.StartNanoseconds); if (cmp == 0) { cmp = job1.EndNanoseconds.CompareTo(job2.EndNanoseconds); } } return(cmp); }); ClrJob prevJob = null; int n = 0; foreach (var tuple in allClrJobs) { ClrJob job = tuple.Item1; if ((prevJob != null) && (prevJob.Type != job.Type)) { n = 0; } prevJob = job; writer.WriteLine($"#{++n:D4} {job.Type} (TID={tuple.Item2}) " + $"{(job.StartNanoseconds / 1E6):F3} .. {(job.EndNanoseconds / 1E6):F3}"); } } }
private List <ClrJob> BuildClrJobs(Thread thread) { var result = new List <ClrJob>(); if (thread.Events == null) { return(result); } JitCompilationStarted jitCompilationStarted = null; Event jitCompilationStartedEvent = null; JitCachedFunctionSearchStarted jitCachedFunctionSearchStarted = null; Event jitCachedFunctionSearchStartedEvent = null; GarbageCollectionStarted garbageCollectionStarted = null; Event garbageCollectionStartedEvent = null; ClrJob prevClrJobJit = null; ClrJob prevClrJobGc = null; foreach (Event threadEvent in thread.Events) { ClrJob prevClrJob = null; ClrJob clrJob = null; ulong startMilliseconds = 0; ulong endMilliseconds = 0; switch (threadEvent.EventType) { case EventType.CompilationStarted: jitCompilationStartedEvent = threadEvent; jitCompilationStarted = (JitCompilationStarted)threadEvent.SourceObject; break; case EventType.CompilationFinished: if (jitCompilationStarted != null) { var jitCompilationFinished = (JitCompilationFinished)threadEvent.SourceObject; if (jitCompilationFinished.FunctionId == jitCompilationStarted.FunctionId) { clrJob = new ClrJob { Type = ClrJobType.JustInTimeCompilation }; prevClrJob = prevClrJobJit; startMilliseconds = jitCompilationStartedEvent.TimeMilliseconds; endMilliseconds = threadEvent.TimeMilliseconds; } jitCompilationStarted = null; } break; case EventType.CachedFunctionSearchStarted: jitCachedFunctionSearchStartedEvent = threadEvent; jitCachedFunctionSearchStarted = (JitCachedFunctionSearchStarted)threadEvent.SourceObject; break; case EventType.CachedFunctionSearchFinished: if (jitCachedFunctionSearchStarted != null) { var jitCachedFunctionSearchFinished = (JitCachedFunctionSearchFinished)threadEvent.SourceObject; if (jitCachedFunctionSearchFinished.FunctionId == jitCachedFunctionSearchStarted.FunctionId) { clrJob = new ClrJob { Type = ClrJobType.JustInTimeCompilation }; prevClrJob = prevClrJobJit; startMilliseconds = jitCachedFunctionSearchStartedEvent.TimeMilliseconds; endMilliseconds = threadEvent.TimeMilliseconds; } jitCachedFunctionSearchStarted = null; } break; case EventType.GarbageCollectionStarted: garbageCollectionStartedEvent = threadEvent; garbageCollectionStarted = (GarbageCollectionStarted)threadEvent.SourceObject; break; case EventType.GarbageCollectionFinished: if (garbageCollectionStarted != null) { var garbageCollectionFinished = (GarbageCollectionFinished)threadEvent.SourceObject; clrJob = new ClrJob { Type = ClrJobType.GarbageCollection }; prevClrJob = prevClrJobGc; startMilliseconds = garbageCollectionStartedEvent.TimeMilliseconds; endMilliseconds = threadEvent.TimeMilliseconds; garbageCollectionStarted = null; } break; } if (clrJob != null) { const int Factor = 1000000; clrJob.StartNanoseconds = startMilliseconds * Factor; clrJob.EndNanoseconds = endMilliseconds * Factor; if (prevClrJob != null) { if (clrJob.StartNanoseconds <= prevClrJob.EndNanoseconds) { // intersecting with previous event if (clrJob.EndNanoseconds <= prevClrJob.EndNanoseconds) { // ignore duplicate events or (unexpected case) events which are contained in previous ones if (clrJob.StartNanoseconds >= prevClrJob.StartNanoseconds) { continue; } // else unexpected: the next event start is before the previous event start } else // clrJob.EndNanoseconds > prevClrJob.EndNanoseconds { // combine events if (clrJob.StartNanoseconds >= prevClrJob.StartNanoseconds) { prevClrJob.EndNanoseconds = clrJob.EndNanoseconds; } else { // unexpected case but support it prevClrJob.StartNanoseconds = clrJob.StartNanoseconds; } continue; } } } result.Add(clrJob); if (clrJob.Type == ClrJobType.GarbageCollection) { prevClrJobGc = clrJob; } else if (clrJob.Type == ClrJobType.JustInTimeCompilation) { prevClrJobJit = clrJob; } } } // foreach return(result); }