public static StackSource AnyStacks(this TraceLog eventLog, TraceProcess process = null, bool showUnknownAddresses = false, Predicate <TraceEvent> predicate = null) { var stackSource = new MutableTraceEventStackSource(eventLog); var sample = new StackSourceSample(stackSource); TraceEvents events = process == null?eventLog.Events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID != 0) : process.EventsInProcess.Filter(x => predicate == null || predicate(x)); var eventSource = events.GetSource(); eventSource.AllEvents += data => { var callStackIdx = data.CallStackIndex(); StackSourceCallStackIndex stackIndex = callStackIdx != CallStackIndex.Invalid ? stackSource.GetCallStack(callStackIdx, data) : StackSourceCallStackIndex.Invalid; var eventNodeName = "Event " + data.ProviderName + "/" + data.EventName; stackIndex = stackSource.Interner.CallStackIntern(stackSource.Interner.FrameIntern(eventNodeName), stackIndex); sample.StackIndex = stackIndex; sample.TimeRelativeMSec = data.TimeStampRelativeMSec; sample.Metric = 1; stackSource.AddSample(sample); }; eventSource.Process(); stackSource.DoneAddingSamples(); return(stackSource); }
internal void StopScan(StreamscanrequestStartArgs_V1TraceData data) { // Get the requesting user process based on the PID logged inside the engine. TraceProcess process = _traceLog.Processes.GetProcess(data.PID, data.TimeStampRelativeMSec); ProcessIndex processIndex = process.ProcessIndex; if (processIndex == ProcessIndex.Invalid) { return; } // Get the file scan operation. Dictionary <ThreadIndex, FileScanOperation> processContainer = GetOrCreateProcessContainer(processIndex); FileScanOperation operation = processContainer.Values.Where(s => s.File.Equals(data.Path, System.StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (operation != null) { operation.StopTimeRelativeMSec = data.TimeStampRelativeMSec; // Create the stack. StackSourceFrameIndex fileNodeIndex = _stackSource.Interner.FrameIntern($"File ({operation.File})"); StackSourceFrameIndex reasonNodeIndex = _stackSource.Interner.FrameIntern($"Reason ({(operation.Reason != null ? operation.Reason : "Unknown")})"); StackSourceFrameIndex resultNodeIndex = _stackSource.Interner.FrameIntern($"Scan Result ({operation.Result})"); _sample.StackIndex = _stackSource.Interner.CallStackIntern(resultNodeIndex, operation.RequestorStack); _sample.StackIndex = _stackSource.Interner.CallStackIntern(reasonNodeIndex, _sample.StackIndex); _sample.StackIndex = _stackSource.Interner.CallStackIntern(fileNodeIndex, _sample.StackIndex); _sample.Metric = (float)(operation.StopTimeRelativeMSec - operation.StartTimeRelativeMSec); _sample.TimeRelativeMSec = operation.StartTimeRelativeMSec; _stackSource.AddSample(_sample); } }
public static bool ManagedProcess(this TraceProcess process) { return(process.LoadedModules.Where(module => module.Name.Equals("clr", StringComparison.OrdinalIgnoreCase) || module.Name.Equals("coreclr", StringComparison.OrdinalIgnoreCase) || module.Name.Equals("mscorwks", StringComparison.OrdinalIgnoreCase)).Count() > 0); }
/// <summary> /// Constructs a new processor for the provided data files. /// </summary> /// <param name="preprocessor">The preprocessor to use (copies everything)</param> public EventProcessor(EventProcessor preprocessor) { // Copy stuff we already calculated this.TraceLog = preprocessor.TraceLog; this.Counters = preprocessor.Counters; this.Start = preprocessor.Start; this.End = preprocessor.End; this.Duration = preprocessor.Duration; this.Interval = preprocessor.Interval; this.Count = preprocessor.Count; this.CoreCount = preprocessor.CoreCount; this.Process = preprocessor.Process; this.Threads = preprocessor.Threads; this.Frames = preprocessor.Frames; this.Faults = preprocessor.Faults; this.Switches = preprocessor.Switches; this.Lifetimes = preprocessor.Lifetimes; this.LockAcquisitions = preprocessor.LockAcquisitions; // A last switch per core for (int i = 0; i < this.CoreCount; ++i) { this.LookupLastSwitch.Add(i, null); } }
private GCHeapSimulator CreateNewSimulator(TraceProcess process) { var ret = new GCHeapSimulator(m_source, process, m_stackSource, m_log, UseOnlyAllocTicks); OnNewGCHeapSimulator?.Invoke(ret); return(ret); }
public PgoTraceProcess(TraceProcess traceProcess) { TraceProcess = traceProcess; foreach (var assemblyLoadTrace in traceProcess.EventsInProcess.ByEventType <AssemblyLoadUnloadTraceData>()) { _assemblyToCLRInstanceIDMap[assemblyLoadTrace.AssemblyID] = assemblyLoadTrace.ClrInstanceID; } }
public DiagnosticProcessInfo(TraceProcess p, bool isCoreProcess = false) { Name = p.Name; Id = p.ProcessID; CPUMSec = p.CPUMSec; SiteName = GetSiteName(p); IsCoreProcess = isCoreProcess; }
public static void ToXml(TextWriter writer, TraceProcess stats, TraceLoadedDotNetRuntime runtime, string indent) { JITStatsEx statsEx = JITStatsEx.Create(runtime); // TODO pay attention to indent; writer.Write(" <JitProcess Process=\"{0}\" ProcessID=\"{1}\" JitTimeMSec=\"{2:n3}\" Count=\"{3}\" ILSize=\"{4}\" NativeSize=\"{5}\"", stats.Name, stats.ProcessID, runtime.JIT.Stats().TotalCpuTimeMSec, runtime.JIT.Stats().Count, runtime.JIT.Stats().TotalILSize, runtime.JIT.Stats().TotalNativeSize); if (stats.CPUMSec != 0) { writer.Write(" ProcessCpuTimeMsec=\"{0}\"", stats.CPUMSec); } if (!string.IsNullOrEmpty(stats.CommandLine)) { writer.Write(" CommandLine=\"{0}\"", XmlUtilities.XmlEscape(stats.CommandLine, false)); } writer.WriteLine(">"); writer.WriteLine(" <JitEvents>"); foreach (TraceJittedMethod _event in runtime.JIT.Methods) { ToXml(writer, _event); } writer.WriteLine(" </JitEvents>"); writer.WriteLine(" <ModuleStats Count=\"{0}\" TotalCount=\"{1}\" TotalJitTimeMSec=\"{2:n3}\" TotalILSize=\"{3}\" TotalNativeSize=\"{4}\">", statsEx.TotalModuleStats.Count, runtime.JIT.Stats().Count, runtime.JIT.Stats().TotalCpuTimeMSec, runtime.JIT.Stats().TotalILSize, runtime.JIT.Stats().TotalNativeSize); // Sort the module list by Jit Time; List <string> moduleNames = new List <string>(statsEx.TotalModuleStats.Keys); moduleNames.Sort(delegate(string x, string y) { double diff = statsEx.TotalModuleStats[y].TotalCpuTimeMSec - statsEx.TotalModuleStats[x].TotalCpuTimeMSec; if (diff > 0) { return(1); } else if (diff < 0) { return(-1); } return(0); }); foreach (string moduleName in moduleNames) { JITStats info = statsEx.TotalModuleStats[moduleName]; writer.Write("<Module"); writer.Write(" JitTimeMSec={0}", StringUtilities.QuotePadLeft(info.TotalCpuTimeMSec.ToString("n3"), 11)); writer.Write(" Count={0}", StringUtilities.QuotePadLeft(info.Count.ToString(), 7)); writer.Write(" ILSize={0}", StringUtilities.QuotePadLeft(info.TotalILSize.ToString(), 9)); writer.Write(" NativeSize={0}", StringUtilities.QuotePadLeft(info.TotalNativeSize.ToString(), 9)); writer.Write(" Name=\"{0}\"", moduleName); writer.WriteLine("/>"); } writer.WriteLine(" </ModuleStats>"); writer.WriteLine(" </JitProcess>"); }
// Advanced usage public StackSourceCallStackIndex GetCallStackForProcess(TraceProcess process) { string ptrSize = process.Is64Bit ? "64" : "32"; var processName = "Process" + ptrSize + " " + process.Name + " (" + process.ProcessID + ")"; var internedProcessFrame = Interner.FrameIntern(processName, m_emptyModuleIdx); var processStack = Interner.CallStackIntern(internedProcessFrame, StackSourceCallStackIndex.Invalid); return(processStack); }
public PinningStackAnalysis(TraceEventDispatcher source, TraceProcess process, MutableTraceEventStackSource stackSource, TextWriter log) : base(source, process, stackSource, log) { var clrPrivateParser = new ClrPrivateTraceEventParser(source); clrPrivateParser.GCSetGCHandle += OnSetGCHandle; source.Clr.GCSetGCHandle += OnSetGCHandle; AllocateObject = () => new PinningStackAnalysisObject(); }
GCHeapSimulator CreateNewSimulator(TraceProcess process) { var ret = new GCHeapSimulator(m_source, process, m_stackSource, m_log, UseOnlyAllocTicks); if (OnNewGCHeapSimulator != null) { OnNewGCHeapSimulator(ret); } return(ret); }
/// <summary> /// Find the depth of a process (0 means I have no parent). /// </summary> private static int ParentDepth(TraceProcess process) { int ret = 0; while (process.Parent != null && process.ProcessID != 0) { process = process.Parent; ret++; } return(ret); }
public void WriteIssuesForProcess(TraceProcess process, List <AutomatedAnalysisIssue> issues) { _writer.WriteLine($"<H3>Process {process.ProcessID}: {process.CommandLine}</H3>"); _writer.WriteLine("<Table Border=\"1\">"); _writer.WriteLine("<TR><TH>Issue Title</TH><TH>Notes</TH></TR>"); foreach (AutomatedAnalysisIssue issue in issues) { _writer.WriteLine($"<TR><TD>{issue.Title}</TD><TD>{issue.Description}<BR/><BR/>More details: <A HREF=\"{issue.URL}\">{issue.URL}</A></TD></TR>"); } _writer.WriteLine("</Table>"); }
public static StackSource CPUStacks(this TraceLog eventLog, TraceProcess process = null, bool showUnknownAddresses = false, Predicate <TraceEvent> predicate = null) { TraceEvents events = process == null?eventLog.Events.Filter(x => (predicate == null || predicate(x)) && x is SampledProfileTraceData && x.ProcessID != 0) : process.EventsInProcess.Filter(x => (predicate == null || predicate(x)) && x is SampledProfileTraceData); var traceStackSource = new TraceEventStackSource(events) { ShowUnknownAddresses = showUnknownAddresses }; return(traceStackSource); }
public GCHeapSimulator this[TraceProcess process] { get { var ret = m_simulators[(int)process.ProcessIndex]; if (ret == null) { m_simulators[(int)process.ProcessIndex] = ret = CreateNewSimulator(process); } return(ret); } }
private StackView GetCPUStacks(Process process) { StackView stackView = null; TraceProcess traceProcess = UnderlyingSource.Processes[(ProcessIndex)process.UniqueID]; if (traceProcess != null) { StackSource stackSource = UnderlyingSource.CPUStacks(traceProcess); stackView = new StackView(traceProcess.Log, stackSource, SymbolReader); } return(stackView); }
StackView ITrace.GetCPUStacks(AnalyzerTraceProcess process) { StackView stackView = null; TraceProcess traceProcess = TraceLog.Processes[(ProcessIndex)process.UniqueID]; if (traceProcess != null) { StackSource stackSource = TraceLog.CPUStacks(traceProcess); stackView = new StackView(traceProcess.Log, stackSource, SymbolReader); } return(stackView); }
public static StackSource Exceptions(this TraceEvents events, TraceProcess process = null, Predicate <TraceEvent> predicate = null) { // optimization only if (process != null) { var start = Math.Max(events.StartTimeRelativeMSec, process.StartTimeRelativeMsec); var end = Math.Min(events.EndTimeRelativeMSec, process.EndTimeRelativeMsec); events = events.FilterByTime(start, end); events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID == process.ProcessID); } else { events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID != 0); // TODO: Is it really correc that x.ProcessID != 0 should be there? What if we want see these? } var eventSource = events.GetSource(); var stackSource = new MutableTraceEventStackSource(events.Log) { ShowUnknownAddresses = true }; var sample = new StackSourceSample(stackSource); eventSource.Clr.ExceptionStart += data => { sample.Metric = 1; sample.TimeRelativeMSec = data.TimeStampRelativeMSec; // Create a call stack that ends with the 'throw' var nodeName = "Throw(" + data.ExceptionType + ") " + data.ExceptionMessage; var nodeIndex = stackSource.Interner.FrameIntern(nodeName); sample.StackIndex = stackSource.Interner.CallStackIntern(nodeIndex, stackSource.GetCallStack(data.CallStackIndex(), data)); stackSource.AddSample(sample); }; eventSource.Kernel.MemoryAccessViolation += data => { sample.Metric = 1; sample.TimeRelativeMSec = data.TimeStampRelativeMSec; // Create a call stack that ends with the 'throw' var nodeName = "AccessViolation(ADDR=" + data.VirtualAddress.ToString("x") + ")"; var nodeIndex = stackSource.Interner.FrameIntern(nodeName); sample.StackIndex = stackSource.Interner.CallStackIntern(nodeIndex, stackSource.GetCallStack(data.CallStackIndex(), data)); stackSource.AddSample(sample); }; eventSource.Process(); stackSource.DoneAddingSamples(); return(stackSource); }
private void RuntimeGCEnd(TraceProcess traceProcess, Microsoft.Diagnostics.Tracing.Analysis.GC.TraceGC gc) { if (traceProcess.ProcessID == _currentProcessId) { if (!_isMetricAlreadyCaptured) { lock (_lock) _isMetricAlreadyCaptured = true; } _gcTimeInTicks = (long)gc.DurationMSec * 10_000; _gcCount = (uint)gc.Number; } }
public List <AutomatedAnalysisIssue> this[TraceProcess process] { get { List <AutomatedAnalysisIssue> issues; if (!_issues.TryGetValue(process, out issues)) { issues = new List <AutomatedAnalysisIssue>(); _issues.Add(process, issues); } return(issues); } }
// Keep this for now because GLAD depends on it. public List <AnalyzerIssue> this[TraceProcess process] { get { AnalyzerTraceProcess traceProcess = new AnalyzerTraceProcess((int)process.ProcessIndex, process.ProcessID, process.CommandLine, process.ManagedProcess()); List <AnalyzerIssue> issues; if (!_issues.TryGetValue(traceProcess, out issues)) { issues = new List <AnalyzerIssue>(); _issues.Add(traceProcess, issues); } return(issues); } }
private static int Compare(TraceProcess process1, int depth1, TraceProcess process2, int depth2) { if (process1 == process2) { return(0); } int ret; if (depth1 > depth2) { ret = Compare(process1.Parent, depth1 - 1, process2, depth2); if (ret == 0) { ret = 1; } return(ret); } if (depth2 > depth1) { ret = Compare(process1, depth1, process2.Parent, depth2 - 1); if (ret == 0) { ret = -1; } return(ret); } if (depth1 > 0) { ret = Compare(process1.Parent, depth1 - 1, process2.Parent, depth2 - 1); if (ret != 0) { return(ret); } } // If parents are the same, we sort by time. youngest first ret = -process1.StartTime100ns.CompareTo(process2.StartTime100ns); if (ret != 0) { return(ret); } // If times are the same, sort by process ID (decending) return(-process1.ProcessID.CompareTo(process2.ProcessID)); }
private void ProcessEventsFromAutoLoggerFirst() { if (myUnprocessedEvents != null && myUnprocessedEvents.Count > 0) { // since the AutogLogger session has no kernel session attached we only get raw process ids // To work around that we fill in the process names from still running processes from the realtime session foreach (WMIStart wmiStartEvent in myUnprocessedEvents) { TraceProcess process = mySource?.TraceLog.Processes.Where(p => p.ProcessID == wmiStartEvent.ClientProcessId).FirstOrDefault(); if (process != null) { wmiStartEvent.ClientProcess = process.CommandLine; } OnWMIOperationStart?.Invoke(wmiStartEvent); } myUnprocessedEvents.Clear(); } }
public static StackSource CPUStacks(this TraceLog eventLog, TraceProcess process = null, Predicate <TraceEvent> predicate = null) { TraceEvents events; if (process == null) { events = eventLog.Events.Filter((x) => ((predicate == null) || predicate(x)) && x is SampledProfileTraceData && x.ProcessID != 0); } else { events = process.EventsInProcess.Filter((x) => ((predicate == null) || predicate(x)) && x is SampledProfileTraceData); } var traceStackSource = new TraceEventStackSource(events); // We clone the samples so that we don't have to go back to the ETL file from here on. return(CopyStackSource.Clone(traceStackSource)); }
public static void ToHtml(TextWriter writer, TraceProcess stats, Etlx.TraceLog traceLog) { Etlx.TraceProcess traceProcess = traceLog.Processes.GetProcess(stats.ProcessID, stats.StartTimeRelativeMsec + 1); if (traceProcess == null) { return; } writer.WriteLine("<H3><A Name=\"Stats_{0}\"><font color=\"blue\">File Version Information for for Process {1,5}: {2}</font><A></H3>", stats.ProcessID, stats.ProcessID, stats.Name); writer.WriteLine("<UL>"); { writer.WriteLine("<LI>CommandLine: {0}</LI>", traceProcess.CommandLine); } writer.WriteLine("</UL>"); writer.WriteLine("<H4><A Name=\"Events_{0}\">Individual Loaded Modules for Process {1,5}: {2}<A></H4>", stats.ProcessID, stats.ProcessID, stats.Name); writer.WriteLine("<Center>"); writer.WriteLine("<Table Border=\"1\">"); writer.Write( "<TR>" + "<TH>File Path</TH>" + "<TH>Version</TH>" + "</TR>"); List <Etlx.TraceLoadedModule> modules = traceProcess.LoadedModules.ToList(); modules.Sort((Etlx.TraceLoadedModule t1, Etlx.TraceLoadedModule t2) => { return(string.Compare(t1.Name, t2.Name)); }); foreach (Etlx.TraceLoadedModule module in modules) { Etlx.TraceModuleFile moduleFile = module.ModuleFile; writer.Write( "<TR>" + "<TD Align=\"Left\">{0}</TD>" + "<TD Align=\"Center\">{1}</TD>" + "</TR>", moduleFile.FilePath, moduleFile.FileVersion); } writer.WriteLine("</Table>"); writer.WriteLine("</Center>"); writer.WriteLine("<HR/><HR/><BR/><BR/>"); }
private TraceProcess CheckIfParentIsW3wp(TraceProcess p) { int counter = 0; TraceProcess parent = null; while (p != null && p.ProcessID != 0 && counter < MAX_PARENT_PROCESS_LEVELS_TO_CHECK) { counter++; if (p.Name == "w3wp") { parent = p; break; } if (p.ParentID == 0) { break; } } return(parent); }
internal void StartScan(StreamscanrequestStartArgs_V1TraceData data) { // Get the requesting user process based on the PID logged inside the engine. TraceProcess process = _traceLog.Processes.GetProcess(data.PID, data.TimeStampRelativeMSec); ProcessIndex processIndex = process.ProcessIndex; if (processIndex == ProcessIndex.Invalid) { return; } // Get the file scan operation. Dictionary <ThreadIndex, FileScanOperation> processContainer = GetOrCreateProcessContainer(processIndex); FileScanOperation operation = processContainer.Values.Where(s => s.File.Equals(data.Path, System.StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); if (operation != null) { operation.StartTimeRelativeMSec = data.TimeStampRelativeMSec; _engineThreadToScanMap[(int)data.Thread().ThreadIndex] = operation; } }
public static StackSource CreateStackSourceFromTraceProcess(TraceProcess process) { var events = process.EventsInProcess; var start = Math.Max(events.StartTimeRelativeMSec, process.StartTimeRelativeMsec); var end = Math.Min(events.EndTimeRelativeMSec, process.EndTimeRelativeMsec); events = events.FilterByTime(start, end); events = events.Filter(x => x is SampledProfileTraceData && x.ProcessID == process.ProcessID); using var symbolReader = new SymbolReader(new StringWriter(), @"SRV*https://msdl.microsoft.com/download/symbols"); symbolReader.SecurityCheck = path => true; var traceLog = process.Log; foreach (var module in process.LoadedModules) { traceLog.CodeAddresses.LookupSymbolsForModule(symbolReader, module.ModuleFile); } return(new TraceEventStackSource(events)); }
public static StackSource AnyStacks(this TraceEvents events, TraceProcess process = null, Predicate <TraceEvent> predicate = null) { // optimization only if (process != null) { var start = Math.Max(events.StartTimeRelativeMSec, process.StartTimeRelativeMsec); var end = Math.Min(events.EndTimeRelativeMSec, process.EndTimeRelativeMsec); events = events.FilterByTime(start, end); events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID == process.ProcessID); } else { events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID != 0); // TODO: Is it really correc that x.ProcessID != 0 should be there? What if we want see these? } var stackSource = new MutableTraceEventStackSource(events.Log) { ShowUnknownAddresses = true }; var sample = new StackSourceSample(stackSource); var eventSource = events.GetSource(); eventSource.AllEvents += data => { var callStackIdx = data.CallStackIndex(); StackSourceCallStackIndex stackIndex = callStackIdx != CallStackIndex.Invalid ? stackSource.GetCallStack(callStackIdx, data) : StackSourceCallStackIndex.Invalid; var eventNodeName = "Event " + data.ProviderName + "/" + data.EventName; stackIndex = stackSource.Interner.CallStackIntern(stackSource.Interner.FrameIntern(eventNodeName), stackIndex); sample.StackIndex = stackIndex; sample.TimeRelativeMSec = data.TimeStampRelativeMSec; sample.Metric = 1; stackSource.AddSample(sample); }; eventSource.Process(); stackSource.DoneAddingSamples(); return(stackSource); }
public static StackSource SingleEventTypeStack(this TraceEvents events, TraceProcess process = null, Predicate <TraceEvent> predicate = null) { // optimization only if (process != null) { var start = Math.Max(events.StartTimeRelativeMSec, process.StartTimeRelativeMsec); var end = Math.Min(events.EndTimeRelativeMSec, process.EndTimeRelativeMsec); events = events.FilterByTime(start, end); events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID == process.ProcessID); } else { events = events.Filter(x => (predicate == null || predicate(x)) && x.ProcessID != 0); // TODO: Is it really correc that x.ProcessID != 0 should be there? What if we want see these? } var traceStackSource = new TraceEventStackSource(events) { ShowUnknownAddresses = true }; return(CopyStackSource.Clone(traceStackSource)); }
/// <summary> /// Constructs a new processor for the provided data files. /// </summary> /// <param name="preprocessor">The preprocessor to use (copies everything)</param> public EventProcessor(EventProcessor preprocessor) { // Copy stuff we already calculated this.TraceLog = preprocessor.TraceLog; this.Counters = preprocessor.Counters; this.Start = preprocessor.Start; this.End = preprocessor.End; this.Duration = preprocessor.Duration; this.Interval = preprocessor.Interval; this.Count = preprocessor.Count; this.CoreCount = preprocessor.CoreCount; this.Process = preprocessor.Process; this.Threads = preprocessor.Threads; this.Frames = preprocessor.Frames; this.Faults = preprocessor.Faults; this.Switches = preprocessor.Switches; this.Lifetimes = preprocessor.Lifetimes; this.LockAcquisitions = preprocessor.LockAcquisitions; // A last switch per core for (int i = 0; i < this.CoreCount; ++i) this.LookupLastSwitch.Add(i, null); }
/// <summary> /// Gets the sampling frames. This is used to analyze what the threads were doing /// and splits the data into workable fixed intervals. /// </summary> /// <param name="processName">The process to analyze.</param> /// <param name="interval">The interval (in milliseconds) of a frame.</param> /// <returns></returns> private EventFrame[] GetFrames(string processName, ushort interval) { // Get the pid only var pid = this.TraceLog.Processes .Where(p => p.Name.StartsWith(processName)) .FirstOrDefault() .ProcessID; // Mark of the start inside the process var benchmarkBegin = DateTime.MinValue; { var evt = TraceLog.Events .Where(e => e.ProcessID == pid) .Where(e => e.EventName.Contains("BenchmarkBegin")) .FirstOrDefault(); if(evt != null) benchmarkBegin = evt.TimeStamp; } // Mark of the end inside the process var benchmarkEnd = DateTime.MinValue; { var evt = TraceLog.Events .Where(e => e.ProcessID == pid) .Where(e => e.EventName.Contains("BenchmarkEnd")) .FirstOrDefault(); if (evt != null) benchmarkEnd = evt.TimeStamp; } // Look the process info this.Process = this.TraceLog.Processes .Where(p => p.Name.StartsWith(processName)) .FirstOrDefault(); // Get the threads this.Threads = this.Process.Threads .ToArray(); // Define the timeframe of the experiment this.Start = benchmarkBegin == DateTime.MinValue ? new DateTime(Math.Max(this.Process.StartTime.Ticks, this.Counters.First().Time.Ticks)) : benchmarkBegin; this.End = benchmarkEnd == DateTime.MinValue ? new DateTime(Math.Min(this.Process.EndTime.Ticks, this.Counters.Last().Time.Ticks)) : benchmarkEnd; this.Duration = this.End - this.Start; this.Interval = TimeSpan.FromMilliseconds(interval); this.Count = (int)Math.Ceiling(this.Duration.TotalMilliseconds / this.Interval.TotalMilliseconds); Console.WriteLine("Analysis: Analyzing {0} process with {1} threads.", this.Process.Name, this.Threads.Length); Console.WriteLine("Analysis: duration = {0}", this.Duration); Console.WriteLine("Analysis: #cores = {0}", CoreCount); Console.WriteLine("Analysis: Creating #{0} frames for {1}ms. interval...", this.Count, this.Interval.TotalMilliseconds); // Get all context switches var safeWindow = TimeSpan.FromSeconds(1); this.Switches = this.TraceLog.Events .Where(e => e.EventName.StartsWith("Thread/CSwitch")) .Where(e => e.TimeStamp > this.Start - safeWindow) .Where(e => e.TimeStamp < this.End + safeWindow) .Select(sw => new ContextSwitch(sw)) .OrderBy(sw => sw.TimeStamp100ns) .ToArray(); // Get all lifetimes this.Lifetimes = this.TraceLog.Events .Where(e => e.EventName.StartsWith("Thread/Start") || e.EventName.StartsWith("Thread/End")) .Where(e => e.TimeStamp > this.Start - safeWindow) .Where(e => e.TimeStamp < this.End + safeWindow) .Select(e => new ThreadLifetime(e, e.EventName.StartsWith("Thread/Start") ? ThreadLifetimeType.Start : ThreadLifetimeType.End)) .OrderBy(sw => sw.TimeStamp100ns) .ToArray(); // Gets all page faults this.Faults = this.TraceLog.Events .Where(e => e.EventName.StartsWith("PageFault")) .Select(e => new PageFault(e)) .ToArray(); // Gets all lock acquisition events this.LockAcquisitions = this.TraceLog.Events .Where(e => e.EventName.EndsWith("LockSuccess") || e.EventName.EndsWith("LockFailure")) .Where(e => e.TimeStamp > this.Start - safeWindow) .Where(e => e.TimeStamp < this.End + safeWindow) .Select(e => new LockAcquisition(e, e.EventName.EndsWith("LockSuccess") ? LockAcquisitionType.Success : LockAcquisitionType.Failure)) .OrderBy(sw => sw.TimeStamp100ns) .ToArray(); // The list for our results var result = new List<EventFrame>(); // Build a by-thread lookup cache for (int i = 0; i < this.Switches.Length;++i) { var sw = this.Switches[i]; if (!this.LookupSwitchByThread.ContainsKey(sw.OldThreadId)) this.LookupSwitchByThread[sw.OldThreadId] = new List<ContextSwitch>(); this.LookupSwitchByThread[sw.OldThreadId].Add(sw); } // Upsample at the specified interval var elapsed = 0d; for (int i = 0; i < this.Count; ++i) { // Current time var t = (int)this.Interval.TotalMilliseconds * i; // The interval starting time var timeFrom = this.Start + TimeSpan.FromMilliseconds(t); var timeTo = this.Start + TimeSpan.FromMilliseconds(t) + this.Interval; // For each core for (int core = 0; core < this.CoreCount; ++core) { // Print out status var begin = DateTime.Now; var fid = (i * this.CoreCount + core + 1); var fmx = (this.Count * this.CoreCount); var eta = (elapsed / fid ) * (fmx - fid); Console.WriteLine("[{0}] Progress: {1}/{2} ETA: {3}", this.Process.Name, fid, fmx, TimeSpan.FromMilliseconds(eta).ToString()); // Get corresponding context switches that happened on that particular core in the specified time frame var cs = this.Switches .Where(e => e.TimeStamp >= timeFrom && e.TimeStamp <= timeTo) .Where(e => e.ProcessorNumber == core) .OrderBy(e => e.TimeStamp100ns); // Console.WriteLine("Analysis: t = {0}, core = {1}, #hw = {2}, #cs = {3}", t, core, hw.Count(), cs.Count()); // Get an individual frame var frame = GetFrame(timeFrom, core, cs); //Console.WriteLine(frame.ToTable()); result.Add(frame); // Calculate time spent analysing this frame elapsed += (DateTime.Now - begin).TotalMilliseconds; } } // Return the resulting frames return result.ToArray(); }