Ejemplo n.º 1
0
        private void Start(DiagnoserActionParameters parameters)
        {
            var counters = benchmarkToCounters[parameters.BenchmarkCase] = parameters.Config
                                                                           .GetHardwareCounters()
                                                                           .Select(counter => HardwareCounters.FromCounter(counter, config.IntervalSelectors.TryGetValue(counter, out var selector) ? selector : GetInterval))
                                                                           .ToArray();

            if (counters.Any()) // we need to enable the counters before starting the kernel session
            {
                HardwareCounters.Enable(counters);
            }

            try
            {
                kernelSession = new KernelSession(parameters, config, CreationTime).EnableProviders();
                if (config.CreateHeapSession)
                {
                    heapSession = new HeapSession(parameters, config, CreationTime).EnableProviders();
                }
                userSession = new UserSession(parameters, config, CreationTime).EnableProviders();
            }
            catch (Exception)
            {
                userSession?.Dispose();
                heapSession?.Dispose();
                kernelSession?.Dispose();

                throw;
            }
        }
Ejemplo n.º 2
0
        protected void Start(DiagnoserActionParameters parameters)
        {
            Clear();

            BenchmarkToProcess.Add(parameters.BenchmarkCase, parameters.Process.Id);
            StatsPerProcess.TryAdd(parameters.Process.Id, GetInitializedStats(parameters));

            // Important: Must wire-up clean-up events prior to acquiring IDisposable instance (Session property)
            // This is in effect the inverted sequence of actions in the Stop() method.
            Console.CancelKeyPress += OnConsoleCancelKeyPress;
            AppDomain.CurrentDomain.ProcessExit += OnProcessExit;

            Session = CreateSession(parameters.BenchmarkCase);

            EnableProvider();

            AttachToEvents(Session, parameters.BenchmarkCase);

            // The ETW collection thread starts receiving events immediately, but we only
            // start aggregating them after ProcessStarted is called and we know which process
            // (or processes) we should be monitoring. Communication between the benchmark thread
            // and the ETW collection thread is through the statsPerProcess concurrent dictionary
            // and through the TraceEventSession class, which is thread-safe.
            var task = Task.Factory.StartNew((Action)(() => Session.Source.Process()), TaskCreationOptions.LongRunning);

            // wait until the processing has started, block by then so we don't loose any
            // information (very important for jit-related things)
            WaitUntilStarted(task);
        }
Ejemplo n.º 3
0
        private void Stop(DiagnoserActionParameters parameters)
        {
            WaitForDelayedEvents();
            string userSessionFile;

            try
            {
                kernelSession.Stop();
                heapSession?.Stop();
                userSession.Stop();

                userSessionFile = userSession.FilePath;
            }
            finally
            {
                kernelSession.Dispose();
                heapSession?.Dispose();
                userSession.Dispose();
            }

            // Merge the 'primary' etl file X.etl (userSession) with any files that match .clr*.etl .user*.etl. and .kernel.etl.
            TraceEventSession.MergeInPlace(userSessionFile, TextWriter.Null);

            benchmarkToEtlFile[parameters.BenchmarkCase] = userSessionFile;
        }
Ejemplo n.º 4
0
        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);
                }
            }
        }
Ejemplo n.º 5
0
        protected void Start(DiagnoserActionParameters parameters)
        {
            Clear();

            BenchmarkToProcess.Add(parameters.BenchmarkCase, parameters.Process.Id);
            StatsPerProcess.TryAdd(parameters.Process.Id, GetInitializedStats(parameters));

            Session = CreateSession(parameters.BenchmarkCase);

            Console.CancelKeyPress += OnConsoleCancelKeyPress;

            NativeWindowsConsoleHelper.OnExit += OnConsoleCancelKeyPress;

            EnableProvider();

            AttachToEvents(Session, parameters.BenchmarkCase);

            // The ETW collection thread starts receiving events immediately, but we only
            // start aggregating them after ProcessStarted is called and we know which process
            // (or processes) we should be monitoring. Communication between the benchmark thread
            // and the ETW collection thread is through the statsPerProcess concurrent dictionary
            // and through the TraceEventSession class, which is thread-safe.
            var task = Task.Factory.StartNew((Action)(() => Session.Source.Process()), TaskCreationOptions.LongRunning);

            // wait until the processing has started, block by then so we don't loose any
            // information (very important for jit-related things)
            WaitUntilStarted(task);
        }
Ejemplo n.º 6
0
        protected override PmcStats GetInitializedStats(DiagnoserActionParameters parameters)
        {
            var stats = new PmcStats(
                parameters.Config.GetHardwareCounters().ToArray(),
                counter => HardwareCounters.FromCounter(counter, info => info.MinInterval));  // for this diagnoser we want the smallest interval to have best possible precision

            HardwareCounters.Enable(stats.Counters.Values);

            return(stats);
        }
Ejemplo n.º 7
0
        /// <inheritdoc />
        public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
        {
            switch (signal)
            {
            case HostSignal.BeforeMainRun:
                try
                {
                    var startInfo = new ProcessStartInfo(
                        @"C:\Users\chris\AppData\Local\JetBrains\Installations\dotTrace11\ConsoleProfiler.exe",
                        $"attach {parameters.Process.Id} --save-to={_saveLocation} --profiling-type=Sampling")
                    {
                        RedirectStandardError  = true,
                        RedirectStandardOutput = true,
                        WindowStyle            = ProcessWindowStyle.Normal,
                        UseShellExecute        = false,
                    };
                    Console.WriteLine(startInfo.FileName);
                    Console.WriteLine(startInfo.Arguments);
                    _process = new Process
                    {
                        StartInfo = startInfo
                    };
                    _process.ErrorDataReceived  += (sender, eventArgs) => Console.Error.WriteLine(eventArgs.Data);
                    _process.OutputDataReceived += (sender, eventArgs) => Console.WriteLine(eventArgs.Data);
                    _process.Start();
                    _process.BeginErrorReadLine();
                    _process.BeginOutputReadLine();
                    _process.Exited += (sender, args) =>
                    {
                        _process.Dispose();
                    };
                }
                catch (Exception e)
                {
                    Console.Error.WriteLine(e.StackTrace);
                    throw;
                }
                break;

            case HostSignal.AfterMainRun:
                break;

            case HostSignal.BeforeAnythingElse:
                break;

            case HostSignal.AfterAll:
                break;

            case HostSignal.SeparateLogic:
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(signal), signal, null);
            }
        }
Ejemplo n.º 8
0
 public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
 {
     if (signal == HostSignal.BeforeAnythingElse)
     {
         Start(parameters);
     }
     else if (signal == HostSignal.AfterAll)
     {
         Stop();
     }
 }
Ejemplo n.º 9
0
 public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
 {
     if (signal == HostSignal.AfterProcessExit)
     {
         System.IO.File.Delete(MarkerFileName);
     }
     else if (signal == HostSignal.BeforeProcessStart)
     {
         System.IO.File.CreateText(MarkerFileName).Dispose();
     }
 }
Ejemplo n.º 10
0
 public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
 {
     if (signal == HostSignal.BeforeGeneralRun)
     {
         Start(parameters);
     }
     else if (signal == HostSignal.AfterGeneralRun)
     {
         Stop();
     }
 }
Ejemplo n.º 11
0
        public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
        {
            switch (signal)
            {
            case HostSignal.AfterActualRun:
                this.TotalMemory = GC.GetTotalMemory(true);
                break;

            default:
                break;
            }
        }
Ejemplo n.º 12
0
        protected override PmcStats GetInitializedStats(DiagnoserActionParameters parameters)
        {
            var stats = new PmcStats(parameters.Config.GetHardwareCounters().ToArray());

            var counters = stats.Counters.Values;

            TraceEventProfileSources.Set( // it's a must have to get the events enabled!!
                counters.Select(counter => counter.ProfileSourceId).ToArray(),
                counters.Select(counter => counter.Interval).ToArray());

            return(stats);
        }
Ejemplo n.º 13
0
 public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
 {
     // it's crucial to start the trace before the process starts and stop it after the benchmarked process stops to have all of the necessary events in the trace file!
     if (signal == HostSignal.BeforeProcessStart)
     {
         Start(parameters);
     }
     else if (signal == HostSignal.AfterProcessExit)
     {
         Stop(parameters);
     }
 }
Ejemplo n.º 14
0
 public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
 {
     if (signal == HostSignal.BeforeActualRun)
     {
         userStart = proc.UserProcessorTime.Ticks;
         privStart = proc.PrivilegedProcessorTime.Ticks;
     }
     if (signal == HostSignal.AfterActualRun)
     {
         userEnd = proc.UserProcessorTime.Ticks;
         privEnd = proc.PrivilegedProcessorTime.Ticks;
     }
 }
        private const int CommonSenseLimit    = 1024; // for benchmarks that use args like "new string('a', 200_000)"

        internal static string GetTraceFilePath(DiagnoserActionParameters details, DateTime creationTime, string fileExtension)
        {
            string nameNoLimit = GetFilePathNoLimits(details, creationTime, fileExtension);

            int limit = PathFeatures.AreAllLongPathsAvailable() ? CommonSenseLimit : WindowsOldPathLimit;

            if (nameNoLimit.Length <= limit)
            {
                return(nameNoLimit);
            }

            return(GetLimitedFilePath(details, creationTime, fileExtension, limit));
        }
Ejemplo n.º 16
0
        private static string GetFilePath(string fileName, DiagnoserActionParameters details, DateTime creationTime, string fileExtension)
        {
            // if we run for more than one toolchain, the output file name should contain the name too so we can differ net462 vs netcoreapp2.1 etc
            if (details.Config.GetJobs().Select(job => ToolchainExtensions.GetToolchain(job)).Distinct().Count() > 1)
            {
                fileName += $"-{details.BenchmarkCase.Job.Environment.Runtime?.Name ?? details.BenchmarkCase.GetToolchain()?.Name ?? details.BenchmarkCase.Job.Id}";
            }

            fileName += $"-{creationTime.ToString(BenchmarkRunnerClean.DateTimeFormat)}";

            fileName = FolderNameHelper.ToFolderName(fileName);

            return(Path.Combine(details.Config.ArtifactsPath, $"{fileName}.{fileExtension}"));
        }
Ejemplo n.º 17
0
        protected Session(string sessionName, DiagnoserActionParameters details, EtwProfilerConfig config, DateTime creationTime)
        {
            Details           = details;
            Config            = config;
            FilePath          = ArtifactFileNameHelper.GetTraceFilePath(details, creationTime, FileExtension).EnsureFolderExists();
            TraceEventSession = new TraceEventSession(sessionName, FilePath)
            {
                BufferSizeMB          = config.BufferSizeInMb,
                CpuSampleIntervalMSec = config.CpuSampleIntervalInMilliseconds,
            };

            Console.CancelKeyPress += OnConsoleCancelKeyPress;
            AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
        }
Ejemplo n.º 18
0
        /// <summary>Called after globalSetup, warmup and pilot but before the main run</summary>
        /// <param name="parameters">The diagnoser action parameters</param>
        public void BeforeMainRun(DiagnoserActionParameters parameters)
        {
            var analysis = _diagnoserState[parameters.Config].Analysis;

            if (analysis == null)
            {
                return;
            }

            analysis.IterationGuid = Guid.NewGuid();
            // Ensure delay before analysis start
            Thread.Sleep(100);
            DiagnoserEventSource.Instance.TraceStarted(analysis.RunGuid, analysis.IterationGuid);
        }
Ejemplo n.º 19
0
        /// <summary>Called after run, before global cleanup</summary>
        public void BeforeGlobalCleanup(DiagnoserActionParameters parameters)
        {
            var analysis = _diagnoserState[parameters.Config].Analysis;

            if (analysis == null)
            {
                return;
            }

            DiagnoserEventSource.Instance.TraceStopped(analysis.RunGuid, analysis.IterationGuid);
            // Ensure delay after analysis stop
            Thread.Sleep(100);
            CompleteTraceSession(analysis);
        }
Ejemplo n.º 20
0
        public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
        {
            if (signal == HostSignal.BeforeActualRun)
            {
                // reset counters
                _data = new EventData();
                EnableEvents(_quicEventSource, EventLevel.Verbose);
            }

            if (signal == HostSignal.AfterActualRun)
            {
                DisableEvents(_quicEventSource);
            }
        }
Ejemplo n.º 21
0
        private void Stop(DiagnoserActionParameters parameters)
        {
            try
            {
                kernelSession.Stop();
                userSession.Stop();

                benchmarkToEtlFile[parameters.BenchmarkCase] = userSession.MergeFiles(kernelSession);
            }
            finally
            {
                kernelSession.Dispose();
                userSession.Dispose();
            }
        }
Ejemplo n.º 22
0
        protected Session(string sessionName, DiagnoserActionParameters details, EtwProfilerConfig config, DateTime creationTime)
        {
            Details  = details;
            Config   = config;
            FilePath = EnsureFolderExists(GetFilePath(details, creationTime));

            TraceEventSession = new TraceEventSession(sessionName, FilePath)
            {
                BufferSizeMB          = config.BufferSizeInMb,
                CpuSampleIntervalMSec = config.CpuSampleIntervalInMiliseconds
            };

            Console.CancelKeyPress            += OnConsoleCancelKeyPress;
            NativeWindowsConsoleHelper.OnExit += OnConsoleCancelKeyPress;
        }
Ejemplo n.º 23
0
        private const int CommonSenseLimit    = 1024; // for benchmarks that use args like "new string('a', 200_000)"

        internal static string GetTraceFilePath(DiagnoserActionParameters details, DateTime creationTime, string fileExtension)
        {
            string nameNoLimit = GetFilePathNoLimits(details, creationTime, fileExtension);

            // long paths can be enabled on Windows but it does not mean that ETW is going to work fine..
            // so we always use 260 as limit on Windows
            int limit = RuntimeInformation.IsWindows()
                ? WindowsOldPathLimit - "userheap.etl".Length // the session files get merged, they need to have same name (without extension)
                : CommonSenseLimit;

            if (nameNoLimit.Length <= limit)
            {
                return(nameNoLimit);
            }

            return(GetLimitedFilePath(details, creationTime, fileExtension, limit));
        }
Ejemplo n.º 24
0
        /// <summary>Creates a new instance of <see cref="InProcessHost"/>.</summary>
        /// <param name="benchmarkCase">Current benchmark.</param>
        /// <param name="logger">Logger for informational output.</param>
        /// <param name="diagnoser">Diagnosers, if attached.</param>
        /// <param name="config">Current config.</param>
        public InProcessHost(BenchmarkCase benchmarkCase, ILogger logger, IDiagnoser diagnoser, IConfig config)
        {
            if (benchmarkCase == null)
            {
                throw new ArgumentNullException(nameof(benchmarkCase));
            }

            this.logger         = logger ?? throw new ArgumentNullException(nameof(logger));
            this.diagnoser      = diagnoser;
            IsDiagnoserAttached = diagnoser != null;
            Config = config;

            if (diagnoser != null)
            {
                diagnoserActionParameters = new DiagnoserActionParameters(
                    Process.GetCurrentProcess(),
                    benchmarkCase,
Ejemplo n.º 25
0
        public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
        {
            switch (signal)
            {
            case HostSignal.BeforeActualRun:
                this.StartTime          = DateTime.Now;
                this.StartProcessorTime = parameters.Process.TotalProcessorTime;
                break;

            case HostSignal.AfterActualRun:
                this.EndTime          = DateTime.Now;
                this.EndProcessorTime = parameters.Process.TotalProcessorTime;
                break;

            default:
                break;
            }
        }
        public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
        {
            //Only turn on the recording of information at certain points.
            //For example, ignore the warm up, etc.
            switch (signal)
            {
            case HostSignal.BeforeActualRun:
                _uowLogInterceptor.StartReading();
                break;

            case HostSignal.AfterActualRun:
                _uowLogInterceptor.StopReading();
                break;

            default:
                break;
            }
        }
Ejemplo n.º 27
0
        public void OnWindowsWeMustAlwaysUseOldLongPathsLimitForSessionFiles()
        {
            var config = DefaultConfig.Instance
                         .WithArtifactsPath(@"C:\Projects\performance\artifacts\bin\MicroBenchmarks\Release\netcoreapp5.0\BenchmarkDotNet.Artifacts");

            var benchmarkCase = BenchmarkConverter.TypeToBenchmarks(typeof(RentReturnArrayPoolTests <byte>), config).BenchmarksCases.First();

            var parameters = new DiagnoserActionParameters(
                process: null,
                benchmarkCase: benchmarkCase,
                new BenchmarkId(0, benchmarkCase));

            foreach (string fileExtension in new[] { "etl", "kernel.etl", "userheap.etl" })
            {
                var traceFilePath = ArtifactFileNameHelper.GetTraceFilePath(parameters, new System.DateTime(2020, 10, 1), fileExtension);

                Assert.InRange(actual: traceFilePath.Length, low: 0, high: 260);
            }
        }
        public SynchronousProcessOutputLoggerWithDiagnoser(ILogger logger, Process process, IDiagnoser diagnoser, BenchmarkCase benchmarkCase, BenchmarkId benchmarkId, IConfig config)
        {
            if (!process.StartInfo.RedirectStandardOutput)
            {
                throw new NotSupportedException("set RedirectStandardOutput to true first");
            }
            if (!process.StartInfo.RedirectStandardInput)
            {
                throw new NotSupportedException("set RedirectStandardInput to true first");
            }

            this.logger               = logger;
            this.process              = process;
            this.diagnoser            = diagnoser;
            diagnoserActionParameters = new DiagnoserActionParameters(process, benchmarkCase, benchmarkId, config);

            LinesWithResults     = new List <string>();
            LinesWithExtraOutput = new List <string>();
        }
Ejemplo n.º 29
0
        protected override PmcStats GetInitializedStats(DiagnoserActionParameters parameters)
        {
            var stats = new PmcStats(parameters.Config.GetHardwareCounters().ToArray(), FromCounter);

            var counters = stats.Counters.Values;

            try
            {
                TraceEventProfileSources.Set( // it's a must have to get the events enabled!!
                    counters.Select(counter => counter.ProfileSourceId).ToArray(),
                    counters.Select(counter => counter.Interval).ToArray());
            }
            catch (System.Runtime.InteropServices.COMException ex) when(ex.Message.StartsWith("The WMI data block or event notification has already been enabled"))
            {
                // previous run was interrupted by ctrl+c and never stopped
            }

            return(stats);
        }
Ejemplo n.º 30
0
        private static string GetLimitedFilePath(DiagnoserActionParameters details, DateTime creationTime, string fileExtension, int limit)
        {
            string shortTypeName = FolderNameHelper.ToFolderName(details.BenchmarkCase.Descriptor.Type, includeNamespace: false);
            string methodName    = details.BenchmarkCase.Descriptor.WorkloadMethod.Name;
            string parameters    = details.BenchmarkCase.HasParameters
                ? $"-hash{Hashing.HashString(FullNameProvider.GetMethodName(details.BenchmarkCase))}"
                : string.Empty;

            string fileName = $@"{shortTypeName}.{methodName}{parameters}";

            string finalResult = GetFilePath(fileName, details, creationTime, fileExtension);

            if (finalResult.Length > limit)
            {
                throw new NotSupportedException($"The full benchmark name: \"{fileName}\" combined with artifacts path: \"{details.Config.ArtifactsPath}\" is too long. " +
                                                $"Please set the value of {nameof(details.Config)}.{nameof(details.Config.ArtifactsPath)} to shorter path or rename the type or method.");
            }

            return(finalResult);
        }