static ScenarioExecutionResult Run(ScenarioTestConfiguration configuration, ScenarioTest scenarioTest)
        {
            var hasStarted = scenarioTest.Process.Start();
            var startTime  = DateTime.UtcNow;

            if (!hasStarted)
            {
                throw new Exception($"Failed to start {scenarioTest.Process.ProcessName}");
            }

            if (scenarioTest.Process.StartInfo.RedirectStandardError)
            {
                scenarioTest.Process.BeginErrorReadLine();
            }
            if (scenarioTest.Process.StartInfo.RedirectStandardInput)
            {
                throw new NotSupportedException($"RedirectStandardInput is not currently supported.");
            }
            if (scenarioTest.Process.StartInfo.RedirectStandardOutput)
            {
                scenarioTest.Process.BeginOutputReadLine();
            }

            var hasExited = scenarioTest.Process.WaitForExit(
                (int)(configuration.TimeoutPerIteration.TotalMilliseconds));
            var exitTime = DateTime.UtcNow;

            if (!hasExited)
            {
                // TODO: scenarioOutput.Process.Kill[All|Tree]();
                scenarioTest.Process.Kill();
                throw new TimeoutException("Running benchmark scenario has timed out.");
            }

            // Check for the exit code.
            if (!configuration.SuccessExitCodes.Contains(scenarioTest.Process.ExitCode))
            {
                throw new Exception($"'{scenarioTest.Process.StartInfo.FileName}' exited with an invalid exit code: {scenarioTest.Process.ExitCode}");
            }

            return(new ScenarioExecutionResult(scenarioTest.Process, startTime, exitTime, configuration));
        }
Exemple #2
0
        /// <summary>
        /// Executes the benchmark scenario specified by the parameter
        /// containing the process start information.<br/>
        /// The process component will wait, for the benchmark scenario to exit,
        /// the time specified on the configuration argument.<br/>
        /// If the benchmark scenario has not exited, then it will immediately
        /// stop the associated process, and a TimeoutException will be thrown.
        /// </summary>
        /// <param name="configuration">ScenarioConfiguration object that defined the scenario execution.</param>
        /// <param name="teardownDelegate">The action that will be executed after running all benchmark scenario iterations.</param>
        public void RunScenario(ScenarioTestConfiguration configuration, Action <ScenarioBenchmark> teardownDelegate)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }
            if (teardownDelegate == null)
            {
                throw new ArgumentNullException(nameof(teardownDelegate));
            }

            string testName;

            if (configuration.TestName == null)
            {
                testName = Path.GetFileNameWithoutExtension(configuration.StartInfo.FileName);
                if (configuration.Scenario == null)
                {
                    configuration.Scenario = new ScenarioBenchmark(testName);
                }
            }
            else
            {
                if (configuration.Scenario == null)
                {
                    testName = configuration.TestName;
                    configuration.Scenario = new ScenarioBenchmark(testName);
                }
                else
                {
                    testName = $"{configuration.Scenario.Name}-{configuration.TestName}";
                }
            }

            var scenarioFileName         = $"{Configuration.RunId}-{testName}";
            var fileNameWithoutExtension = Path.Combine(OutputDirectory, $"{scenarioFileName}");

            for (int i = 0; i < configuration.Iterations; ++i)
            {
                using (var scenarioTest = new ScenarioTest(configuration))
                {
                    ScenarioExecutionResult scenarioExecutionResult;

                    configuration.PreIterationDelegate?.Invoke(scenarioTest);

                    WriteInfoLine($"Iteration ({i})");
                    WriteInfoLine($"  Working Directory: \"{scenarioTest.Process.StartInfo.WorkingDirectory}\"");
                    WriteInfoLine($"  Command: \"{scenarioTest.Process.StartInfo.FileName}\" {scenarioTest.Process.StartInfo.Arguments}");

                    if (IsWindowsPlatform && _requireEtw)
                    {
                        var sessionName = $"Performance-Api-Session-{Configuration.RunId}";

                        string tracesFolder = Path.Combine(OutputDirectory, $"{fileNameWithoutExtension}-traces");
                        if (!Directory.Exists(tracesFolder))
                        {
                            Directory.CreateDirectory(tracesFolder);
                        }

                        var etlFileName = Path.Combine(tracesFolder, $"{scenarioFileName}({i}).etl");

                        var userSpecifiedMetrics = _metricCollectionFactory.GetMetrics();
                        var kernelProviders      = userSpecifiedMetrics
                                                   .SelectMany(pmi => pmi.ProviderInfo)
                                                   .OfType <KernelProviderInfo>()
                                                   .Select(kernelProviderInfo => new KernelProvider {
                            Flags        = (KernelTraceEventParser.Keywords)kernelProviderInfo.Keywords,
                            StackCapture = (KernelTraceEventParser.Keywords)kernelProviderInfo.StackKeywords
                        });
                        var profileSourceInfos = userSpecifiedMetrics
                                                 .SelectMany(pmi => pmi.ProviderInfo)
                                                 .OfType <CpuCounterInfo>()
                                                 .Where(cpuCounterInfo => Helper.AvailablePreciseMachineCounters.Keys.Contains(cpuCounterInfo.CounterName))
                                                 .Select(cpuCounterInfo => {
                            var profileSourceInfo = Helper.AvailablePreciseMachineCounters[cpuCounterInfo.CounterName];
                            return(new ProfileSourceInfo {
                                ID = profileSourceInfo.ID,
                                Interval = cpuCounterInfo.Interval,
                                MaxInterval = profileSourceInfo.MaxInterval,
                                MinInterval = profileSourceInfo.MinInterval,
                                Name = profileSourceInfo.Name,
                            });
                        });

                        Helper.SetPreciseMachineCounters(profileSourceInfos.ToList());

                        var listener = new Listener <ScenarioExecutionResult>(
                            new SessionData(sessionName, etlFileName)
                        {
                            BufferSizeMB = 256
                        },
                            UserProvider.Defaults,
                            kernelProviders.ToList());

                        scenarioExecutionResult = listener.Record(() => { return(Run(configuration, scenarioTest)); });

                        scenarioExecutionResult.EventLogFileName           = etlFileName;
                        scenarioExecutionResult.PerformanceMonitorCounters = userSpecifiedMetrics
                                                                             .Where(m => Helper.AvailablePreciseMachineCounters.Keys.Contains(m.Id))
                                                                             .Select(m => {
                            var psi = Helper.AvailablePreciseMachineCounters[m.Id];
                            return(new PerformanceMonitorCounter(m.DisplayName, psi.Name, m.Unit, psi.ID));
                        })
                                                                             .ToHashSet();

                        LogFileSaved(etlFileName);
                    }
                    else
                    {
                        scenarioExecutionResult = Run(configuration, scenarioTest);
                    }

                    configuration.PostIterationDelegate?.Invoke(scenarioExecutionResult);
                }
            }

            teardownDelegate(configuration.Scenario);

            if (configuration.SaveResults)
            {
                WriteResults(configuration.Scenario, fileNameWithoutExtension);
            }
        }