private void PrintRunSummary(ThreadedRunResult runResult) { var sb = new StringBuilder(); sb.Append(runResult.TestName); if (runResult.Successful) { sb.AppendLine(" (Success) "); sb.Append(runResult.RequestsPerSecond); sb.Append(" RPS total ("); var samplePoints = runResult.IterationCounters.Count; Debug.Assert(samplePoints > 0); sb.Append(samplePoints.ToString(CultureInfo.InvariantCulture)); if (samplePoints > 1) { sb.AppendLine(" samples)"); foreach (var i in new[] { 0.95, 0.99, 0.999 }) { var percentile = (i * 100).ToString(CultureInfo.InvariantCulture); var resultPercentile = GetPercentile(runResult, i, c => ((ThreadedIterationCounter)c).RequestsPerSecond, false); var resultName = string.Format("{0} - {1}th percentile", runResult.TestName, percentile); sb.Append(resultPercentile); sb.Append(" RPS "); sb.Append(percentile); sb.AppendLine("th percentile"); } } else { sb.AppendLine(" iteration)"); } } else { sb.Append(" (Fail) "); sb.Append(runResult.ReportedException.Message); } sb.AppendLine(); Console.WriteLine(sb.ToString()); }
protected ThreadedRunResult Run(ThreadedTestDefinition test) { //localize test settings var threadCount = 8; if (test.ThreadCount.HasValue) { threadCount = test.ThreadCount.Value; } var warmupDuration = 10000; if (test.WarmupDuration.HasValue) { warmupDuration = test.WarmupDuration.Value; } var testDuration = 60000; if (test.TestDuration.HasValue) { testDuration = test.TestDuration.Value; } var testName = test.TestName ?? test.GetType() + "#" + test.GetHashCode(); var setup = test.Setup; var run = test.Run; var cleanup = test.Cleanup; var threadStateFactory = test.ThreadStateFactory; //validate if (run == null) { throw new ArgumentNullException(string.Format("Verify that test {0} has a run action.", testName)); } //setup try { if (setup != null) { setup(); } } catch (Exception e) { return(new ThreadedRunResult(testName, e)); } var iterationSnaps = new List <Tuple <long, long> >(); var iterationCounter = 0L; var testStopSignal = false; Action decoratedRunAction = () => { var state = threadStateFactory(); do { run(state); Interlocked.Increment(ref iterationCounter); }while (!testStopSignal); }; Action rpsCounterAction = () => { do { var current = Interlocked.Read(ref iterationCounter); iterationSnaps.Add(new Tuple <long, long>(current, GC.GetTotalMemory(false))); Thread.Sleep(1000); }while (!testStopSignal); }; var workers = new List <Thread>(); //add worker tasks for (var i = 0; i < threadCount; ++i) { workers.Add(new Thread(new ThreadStart(decoratedRunAction))); } long totalExecutionTime; //run try { var runStopWatch = new Stopwatch(); runStopWatch.Start(); foreach (var worker in workers) { worker.Start(); } // warmup runStopWatch.Restart(); do { Thread.Sleep(1000); }while (runStopWatch.ElapsedMilliseconds < warmupDuration); //add rps counter thread Thread counter = null; workers.Add(counter = new Thread(new ThreadStart(rpsCounterAction))); counter.Start(); //actual run runStopWatch.Restart(); do { Thread.Sleep(1000); }while (runStopWatch.ElapsedMilliseconds < testDuration); testStopSignal = true; runStopWatch.Stop(); totalExecutionTime = runStopWatch.ElapsedMilliseconds / 1000; } catch (Exception e) { return(new ThreadedRunResult(testName, e)); } //summarize iteration counters var prevCummulativeValue = 0L; var iterationCounters = new List <ThreadedIterationCounter>(); foreach (var snap in iterationSnaps) { if (snap.Item1 == 0) { continue; } var iterationRps = snap.Item1 - prevCummulativeValue; iterationCounters.Add(new ThreadedIterationCounter { RequestsPerSecond = iterationRps, WorkingSet = snap.Item2 }); prevCummulativeValue += iterationRps; } var result = new ThreadedRunResult(testName, iterationCounter / totalExecutionTime, GC.GetTotalMemory(false), iterationCounters); //cleanup try { if (cleanup != null) { cleanup(); } } catch (Exception e) { result.ReportedException = e; } //report return(result); }