示例#1
0
        /// <summary>
        /// Validate arguments.
        /// </summary>
        private void ValidateArguments()
        {
            if (ValidateArgumentsEx())
            {
                if (Threads <= 0)
                {
                    throw new Exception("Threads must be positive: " + Threads);
                }

                if (Warmup < 0)
                {
                    throw new Exception("Warmup cannot be negative: " + Warmup);
                }

                if (Duration < 0)
                {
                    throw new Exception("Duration cannot be negative: " + Duration);
                }

                if (BatchSize <= 0)
                {
                    throw new Exception("BatchSize must be positive: " + BatchSize);
                }

                if (MaxErrors < 0)
                {
                    throw new Exception("MaxErrors cannot be negative: " + MaxErrors);
                }

                if (ResultWriter == null || !ResultWriter.ToLower().Equals(ResultWriterConsole) &&
                    !ResultWriter.ToLower().Equals(ResultWriterFile))
                {
                    throw new Exception("Invalid ResultWriter: " + ResultWriter);
                }

                if (ResultWriter.ToLower().Equals(ResultWriterFile) && ResultFolder == null)
                {
                    throw new Exception("ResultFolder must be set for file result writer.");
                }

                if (ResultBucketCount <= 0)
                {
                    throw new Exception("ResultBucketCount must be positive: " + ResultBucketCount);
                }

                if (ResultBucketInterval <= 0)
                {
                    throw new Exception("ResultBucketInterval must be positive: " + ResultBucketInterval);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Run the benchmark.
        /// </summary>
        public void Run()
        {
            PrintDebug("Started benchmark: " + this);

            ValidateArguments();

            if (ResultWriter.ToLower().Equals(ResultWriterConsole))
            {
                _writer = new BenchmarkConsoleResultWriter();
            }
            else
            {
                _writer = new BenchmarkFileResultWriter();
            }

            OnStarted();

            PrintDebug("Benchmark setup finished.");

            try
            {
                _descs = new List <BenchmarkOperationDescriptor>();

                GetDescriptors(_descs);

                if (_descs.Count == 0)
                {
                    throw new Exception("No tasks provided for benchmark.");
                }

                // Initialize writer.
                var opNames = new List <string>(_descs.Select(desc => desc.Name));

                PrintDebug(() =>
                {
                    var sb = new StringBuilder("Operations: ");

                    foreach (var opName in opNames)
                    {
                        sb.Append(opName).Append(" ");
                    }

                    return(sb.ToString());
                });

                _writer.Initialize(this, opNames);

                PrintDebug("Initialized result writer.");

                // Start worker threads.
                _tasks = new List <BenchmarkTask>(Threads);

                PrintDebug("Starting worker threads: " + Threads);

                for (var i = 0; i < Threads; i++)
                {
                    var task = new BenchmarkTask(this, _descs);

                    _tasks.Add(task);

                    new Thread(task.Run).Start();
                }

                PrintDebug("Waiting worker threads to start: " + Threads);

                // Await for all threads to start in spin loop.
                while (Thread.VolatileRead(ref _readyThreads) < Threads)
                {
                    Thread.Sleep(10);
                }

                PrintDebug("Worker threads started: " + Threads);

                // Start throughput writer thread.
                var writerThread = new Thread(new ThroughputTask(this).Run)
                {
                    IsBackground = true
                };

                writerThread.Start();

                PrintDebug("Started throughput writer thread.");

                // Start warmup thread if needed.
                if (Warmup > 0)
                {
                    var thread = new Thread(new WarmupTask(this, Warmup).Run)
                    {
                        IsBackground = true
                    };

                    thread.Start();

                    PrintDebug("Started warmup timeout thread: " + Warmup);
                }
                else
                {
                    _warmup = false;
                }

                _barrier = new Barrier(Threads, b =>
                {
                    Console.WriteLine("Warmup finished.");

                    _totalWatch.Start();
                });

                // Start timeout thread if needed.
                if (Duration > 0)
                {
                    if (Operations > 0)
                    {
                        PrintDebug("Duration argument is ignored because operations number is set: " +
                                   Operations);
                    }
                    else
                    {
                        var thread = new Thread(new TimeoutTask(this, Warmup + Duration).Run)
                        {
                            IsBackground = true
                        };

                        thread.Start();

                        PrintDebug("Started duration timeout thread: " + Duration);
                    }
                }

                // Let workers start execution.
                _start = true;

                // Await workers completion.
                PrintDebug("Awaiting worker threads completion.");

                Monitor.Enter(this);

                try
                {
                    while (_finishedThreads < Threads)
                    {
                        Monitor.Wait(this);
                    }
                }
                finally
                {
                    Monitor.Exit(this);
                }

                PrintDebug("Worker threads completed.");
            }
            finally
            {
                OnFinished();

                _totalWatch.Stop();

                PrintDebug("Tear down invoked.");

                if (PrintThroughputInfo())
                {
                    var avgThroughput = _totalWatch.ElapsedMilliseconds == 0
                        ? 0
                        : _curOps * 1000 / _totalWatch.ElapsedMilliseconds;

                    var avgLatency = _curOps == 0
                        ? 0
                        : (double)_totalWatch.ElapsedMilliseconds * Threads / _curOps;

                    Console.WriteLine("Finishing benchmark [name=" + GetType().Name +
                                      ", time=" + _totalWatch.ElapsedMilliseconds +
                                      "ms, ops=" + _curOps +
                                      ", threads=" + Threads +
                                      ", avgThroughput=" + avgThroughput +
                                      ", avgLatency=" + string.Format("{0:0.000}ms", avgLatency) + ']');
                }
                else
                {
                    Console.WriteLine("Finishing benchmark [name=" + GetType().Name +
                                      ", time=" + _totalWatch.ElapsedMilliseconds +
                                      "ms, ops=" + Operations +
                                      ", threads=" + Threads + ']');
                }
            }

            _percentiles = new Dictionary <string, long[]>(_descs.Count);

            foreach (var desc in _descs)
            {
                _percentiles[desc.Name] = new long[ResultBucketCount];
            }

            foreach (var task in _tasks)
            {
                task.CollectPercentiles(_percentiles);
            }

            foreach (var percentile in _percentiles)
            {
                _writer.WritePercentiles(percentile.Key, ResultBucketInterval, percentile.Value);
            }

            _writer.Commit();

            PrintDebug("Results committed to output writer.");
        }