private void StartTraceSession(DiagnoserActionParameters parameters) { var metricProviders = CompetitionCore.RunState[parameters.Config].Config .GetMetrics() .Select(m => m.ValuesProvider) .OfType <IEtwMetricValueProvider>() .Distinct() .ToArray(); if (metricProviders.Length == 0) { _analysis = null; return; } var analysis = CreateAnalysis(parameters.Benchmark, parameters.Config, metricProviders); EtwHelpers.WorkaroundEnsureNativeDlls(); bool allOk = false; try { BuildTraceSession(analysis); allOk = true; } finally { if (!allOk) { CompleteTraceSession(analysis); DisposeAnalysis(analysis); } } }
private void CompleteTraceSession(EtwDiagnoserAnalysis analysis) { var traceSession = analysis.TraceSession; if (traceSession != null) { traceSession.Flush(); traceSession.Dispose(); } }
private static DiagnoserTraceScopeEvent[] CollectDiagnoserEvents(EtwDiagnoserAnalysis analysis) { // ReSharper disable once ConvertToLocalFunction Func <TraceEvent, bool> currentRunFilter = e => (Guid)e.PayloadByName(DiagnoserEventSource.RunIdPayload) == analysis.RunGuid; var provider = new DiagnoserTimesProvider(); using (var eventSource = new ETWTraceEventSource(analysis.TraceFile.Path)) using (provider.Subscribe(eventSource, analysis.Benchmark, analysis.Config, currentRunFilter)) { eventSource.Process(); } return(provider.GetEvents(analysis.Benchmark, analysis.Config).ToArray()); }
private void DisposeAnalysis(EtwDiagnoserAnalysis analysis) { var config = analysis.Config; analysis.TraceSession?.Dispose(); analysis.TraceFile.Dispose(); var runState = _diagnoserState[config]; Code.BugIf(runState.Analysis != analysis, "runState.Analysis != analysis"); runState.Analysis = null; Code.BugIf(_analysis != analysis, "_analysis != analysis"); _analysis = null; }
private static void ProcessCapturedEvents(EtwDiagnoserAnalysis analysis) { var events = CollectDiagnoserEvents(analysis); var allProcesses = events.Select(e => e.ProcessId).ToHashSet(); var timeRange = events.ToCompositeRange( e => e.Started ?? TimeSpan.MinValue, e => e.Stopped ?? TimeSpan.MaxValue); // ReSharper disable once ConvertToLocalFunction Func <TraceEvent, bool> timeAndProcessFilter = e => { if (!allProcesses.Contains(e.ProcessID)) { return(false); } var t = TimeSpan.FromMilliseconds(e.TimeStampRelativeMSec); return(timeRange.Intersect(t, t).SubRanges.Any(r => r.Key.ProcessId == e.ProcessID)); }; using (var eventSource = new ETWTraceEventSource(analysis.TraceFile.Path)) { if (eventSource.EventsLost > 0) { analysis.WriteWarningMessage( analysis.Benchmark.Target, $"The analysis session contains {eventSource.EventsLost} lost event(s). Metric results may be inaccurate.", "Consider to collect less events or to place the benchmark working directory on drive with least load."); } var allHandlers = new List <IDisposable>(); foreach (var metricProvider in analysis.MetricProviders) { // Already processed if (metricProvider.ProviderGuid == DiagnoserEventSource.SourceGuid) { continue; } var handler = metricProvider.Subscribe(eventSource, analysis.Benchmark, analysis.Config, timeAndProcessFilter); allHandlers.Add(handler); } eventSource.Process(); allHandlers.DisposeAll(); } }
private EtwDiagnoserAnalysis CreateAnalysis(Benchmark benchmark, IConfig config, IEtwMetricValueProvider[] metricProviders) { var diagnoserState = _diagnoserState[config]; Code.BugIf(diagnoserState.Analysis != null, "runState.Analysis != null"); Code.BugIf(_analysis != null, "_analysis != null"); var analysis = new EtwDiagnoserAnalysis(benchmark, config, metricProviders); if (analysis.Config.KeepBenchmarkFiles) { analysis.TraceFile.SuppressDelete(); } diagnoserState.Analysis = analysis; _analysis = analysis; return(analysis); }
private static void BuildTraceSession(EtwDiagnoserAnalysis analysis) { var traceSession = new TraceEventSession(analysis.RunGuid.ToString(), analysis.TraceFile.Path) { StopOnDispose = true }; analysis.TraceSession = traceSession; var metricsByProvider = analysis.MetricProviders.ToLookup(p => p.ProviderGuid); // Kernel etw provider must be the first one. if (metricsByProvider.Contains(KernelTraceEventParser.ProviderGuid)) { var metricValueProviders = metricsByProvider[KernelTraceEventParser.ProviderGuid]; var flags = metricValueProviders .Aggregate(0UL, (value, p) => value | p.ProviderKeywords); try { traceSession.EnableKernelProvider((KernelTraceEventParser.Keywords)flags); } catch (UnauthorizedAccessException) { var kernelMetrics = analysis.Config .GetMetrics() .Where(m => m.ValuesProvider is IEtwMetricValueProvider p && p.IsKernelMetric); analysis.WriteSetupErrorMessage( analysis.Benchmark.Target, $"The config contains kernel metric(s) {kernelMetrics.Select(m => m.DisplayName).Join(", ")} and therefore requires elevated run.", "Run the competition with elevated permissions (as administrator)."); throw; } } traceSession.EnableProvider(DiagnoserEventSource.SourceGuid); // Handle all other providers foreach (var metricsGroup in metricsByProvider) { // Already registered if (metricsGroup.Key == KernelTraceEventParser.ProviderGuid) { continue; } if (metricsGroup.Key == DiagnoserEventSource.SourceGuid) { continue; } var eventLevel = TraceEventLevel.Always; var keywords = 0UL; foreach (var metricValueProvider in metricsGroup) { if (eventLevel < metricValueProvider.EventLevel) { eventLevel = metricValueProvider.EventLevel; } keywords |= metricValueProvider.ProviderKeywords; } traceSession.EnableProvider(metricsGroup.Key, eventLevel, keywords); } }