public void Run() { if (HasRunBeenCalled()) { throw new InvalidOperationException("Can only call run once."); } Console.WriteLine($"Running for {RunPeriod.TotalSeconds}sec."); //Write the headers, but no histograms (as we don't have any yet). _logWriter.Write(DateTime.Now); //ThreadSafe-writes require a Concurrent implementation of a Histogram //ThreadSafe-reads require a recorder var recorder = HistogramFactory .With64BitBucketSize() //LongHistogram .WithValuesFrom(1) //Default value .WithValuesUpTo(TimeStamp.Minutes(10)) //Default value .WithPrecisionOf(3) //Default value .WithThreadSafeWrites() //Switches internal imp to concurrent version i.e. LongConcurrentHistogram .WithThreadSafeReads() //returns a Recorder that wraps the LongConcurrentHistogram .Create(); var outputThread = new Thread(ts => WriteToDisk((Recorder)ts)); outputThread.Start(recorder); RecordMeasurements(recorder); //Wait for the output thread to complete writing. outputThread.Join(); }
public static LongHistogram Bench(Action action, int count) { var histogram = new LongHistogram(TimeStamp.Minutes(1), 5); for (var i = 0; i < count; i++) { histogram.Record(() => action()); } return(histogram); }
public void TimeStamp_values_are_accurate() { var delay = TimeSpan.FromSeconds(1); var expected = TimeStamp.Seconds(delay.Seconds); var start = Stopwatch.GetTimestamp(); Thread.Sleep(delay); var end = Stopwatch.GetTimestamp(); var actual = end - start; Assert.AreEqual(expected, actual, expected * 0.05); Assert.AreEqual(TimeStamp.Seconds(60), TimeStamp.Minutes(1)); Assert.AreEqual(TimeStamp.Minutes(60), TimeStamp.Hours(1)); }
public void TimeStamp_values_are_accurate() { var delay = TimeSpan.FromSeconds(1); var expected = TimeStamp.Seconds(delay.Seconds); long minAccepted = (long)(expected * 0.95); long maxAccepted = (long)(expected * 1.05); var start = Stopwatch.GetTimestamp(); Spin.Wait(delay); var end = Stopwatch.GetTimestamp(); var actual = end - start; actual.Should().BeInRange(minAccepted, maxAccepted); Assert.Equal(TimeStamp.Seconds(60), TimeStamp.Minutes(1)); Assert.Equal(TimeStamp.Minutes(60), TimeStamp.Hours(1)); }
public Recording32BitBenchmark() { const int lowestTrackableValue = 1; var highestTrackableValue = TimeStamp.Minutes(10); const int numberOfSignificantValueDigits = 3; _testValues = TestValues(highestTrackableValue); _longHistogram = new LongHistogram(highestTrackableValue, numberOfSignificantValueDigits); _intHistogram = new IntHistogram(highestTrackableValue, numberOfSignificantValueDigits); _shortHistogram = new ShortHistogram(highestTrackableValue, numberOfSignificantValueDigits); _longConcurrentHistogram = new LongConcurrentHistogram(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits); _intConcurrentHistogram = new IntConcurrentHistogram(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits); _longRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new LongHistogram(id, low, hi, sf)); _longConcurrentRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new LongConcurrentHistogram(id, low, hi, sf)); _intRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new IntHistogram(id, low, hi, sf)); _intConcurrentRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new IntConcurrentHistogram(id, low, hi, sf)); _shortRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new ShortHistogram(id, low, hi, sf)); }
private static LongConcurrentHistogram RunTest(RunInfo run) { var config = run.Configuration; var pool = new RoundRobinPool(config.PoolSize, config.ProjectId); var histogram = new LongConcurrentHistogram(1L, TimeStamp.Minutes(10), 4); long documentCounter = 0; var data = new byte[config.DataSize]; RandomNumberGenerator.Create().GetBytes(data); // Warm the pool up with no throttling SemaphoreSlim qpsThrottle = new SemaphoreSlim(config.PoolSize); for (int i = 0; i < config.PoolSize; i++) { WriteBatchAsync().GetAwaiter().GetResult(); } // Discard the warm-up results histogram.Reset(); long batchesLeft = config.Batches; long completed = 0; var tasks = Enumerable .Range(0, config.TaskCount) .Select(_ => Task.Run(WriteBatchesAsync)) .ToArray(); // Start tasks that we don't need to wait for at the end. (They will complete, // but possibly not immediately, and that's fine.) Task.Run(PrintDiagnosticsAsync); Task.Run(ReleaseThrottleAsync); Task.WaitAll(tasks); Interlocked.Increment(ref completed); return(histogram); async Task WriteBatchesAsync() { while (Interlocked.Decrement(ref batchesLeft) >= 0) { await WriteBatchAsync(); } } async Task WriteBatchAsync() { var db = pool.GetFirestoreDb(); var batch = db.StartBatch(); for (int i = 0; i < config.BatchSize; i++) { var documentRef = db.Collection(run.Collection).Document(); var document = new SampleDocument { Id = Interlocked.Increment(ref documentCounter), Data = data }; batch.Create(documentRef, document); } await qpsThrottle.WaitAsync(); long start = Stopwatch.GetTimestamp(); await batch.CommitAsync(); long end = Stopwatch.GetTimestamp(); histogram.RecordValue(Math.Max(1L, end - start)); } async Task ReleaseThrottleAsync() { Stopwatch stopwatch = Stopwatch.StartNew(); long released = 0; // Every ~50ms, see how many more batches we should release while (Interlocked.Read(ref completed) == 0) { await Task.Delay(50); long targetRelease = (stopwatch.ElapsedTicks * config.TargetQps) / Stopwatch.Frequency; qpsThrottle.Release((int)(targetRelease - released)); released = targetRelease; } } async Task PrintDiagnosticsAsync() { while (Interlocked.Read(ref completed) == 0) { Log($"Batches left to start: {Interlocked.Read(ref batchesLeft)}"); await Task.Delay(1000); } } }
public MetricPublisherXEventHandler() { _latencyHistogram = new LongHistogram(TimeStamp.Minutes(1), 3); _conflactionHistogram = new IntHistogram(10000, 1); }