Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 32 additions & 15 deletions src/HdrHistogram.Benchmarking/Recording/Recording32BitBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,39 @@ public class Recording32BitBenchmark

public Recording32BitBenchmark()
{
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
const int lowestTrackableValue = 1;
var highestTrackableValue = TimeStamp.Minutes(10);
_testValues = Enumerable.Range(0, 32)
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 long[] TestValues(long highestTrackableValue)
{
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
// 32 bit values are the 89 values
// 1,2,3,4,5,7,8,9,15,16,17,31,32,33,63,64,65,127,128,129,255,256,257,511,512,513,1023,1024,1025,2047,2048,2049,4095,4096,4097,8191,8192,8193,
// 16383,16384,16385,32767,32768,32769,65535,65536,65537,131071,131072,131073,262143,262144,262145,524287,524288,524289,1048575,1048576,1048577,
// 2097151,2097152,2097153,4194303,4194304,4194305,8388607,8388608,8388609,16777215,16777216,16777217,33554431,33554432,33554433,
// 67108863,67108864,67108865,134217727,134217728,134217729,268435455,268435456,268435457,536870911,536870912,536870913,1073741823,1073741824,1073741825
//These value are choosen as they are the edge case values of where our bucket boundaries lie. i.e.
// a power of 2
// 1 less than a power of 2
// 1 more than a power of 2
return Enumerable.Range(0, 32)
.Select(exp => new { Value = 1L << exp, LZC = 63 - exp })
.SelectMany(x => new[]
{
Expand All @@ -34,19 +64,6 @@ public Recording32BitBenchmark()
.Where(x => x < highestTrackableValue)
.Distinct()
.ToArray();

_longHistogram = new LongHistogram(highestTrackableValue, 3);
_intHistogram = new IntHistogram(highestTrackableValue, 3);
_shortHistogram = new ShortHistogram(highestTrackableValue, 3);

_longConcurrentHistogram = new LongConcurrentHistogram(1, highestTrackableValue, 3);
_intConcurrentHistogram = new IntConcurrentHistogram(1, highestTrackableValue, 3);

_longRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new LongHistogram(id, low, hi, sf));
_longConcurrentRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new LongConcurrentHistogram(id, low, hi, sf));
_intRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new IntHistogram(id, low, hi, sf));
_intConcurrentRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new IntConcurrentHistogram(id, low, hi, sf));
_shortRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new ShortHistogram(id, low, hi, sf));
}

[Benchmark(Baseline = true)]
Expand Down
1 change: 1 addition & 0 deletions src/HdrHistogram.Examples/HdrHistogram.Examples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RecorderExample.cs" />
<Compile Include="SimpleHistogramExample.cs" />
<Compile Include="SocketTester.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
Expand Down
5 changes: 4 additions & 1 deletion src/HdrHistogram.Examples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ class Program
static void Main(string[] args)
{
//SimpleHistogramExample.Run();
RecorderExample.Run();
using (var example = new RecorderExample())
{
example.Run();
}
}
}
}
99 changes: 59 additions & 40 deletions src/HdrHistogram.Examples/RecorderExample.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace HdrHistogram.Examples
Expand All @@ -12,82 +10,103 @@ namespace HdrHistogram.Examples
/// time it takes to perform a simple Datagram Socket create/close operation,
/// and report a histogram of the times at the end.
/// </summary>
static class RecorderExample
internal sealed class RecorderExample : IDisposable
{
private static readonly Recorder Recorder = new Recorder(1, TimeStamp.Hours(1), 3, (id, low, high, sf) => new LongHistogram(id, low, high, sf));
private static readonly Lazy<AddressFamily> AddressFamily = new Lazy<AddressFamily>(() => GetAddressFamily("google.com"));
private const string LogPath = "DatagramSocket.histogram.log";
private static readonly TimeSpan RunPeriod = TimeSpan.FromSeconds(10);
private static readonly LongHistogram AccumulatingHistogram = new LongHistogram(TimeStamp.Hours(1), 3);
private const string LogPath = "DatagramSocket.histogram.log";
private static HistogramLogWriter _logWriter;
private static FileStream _outputStream;
private static int _isCompleted = 0;

public static void Run()
{
Console.WriteLine($"Running for {RunPeriod.TotalSeconds}sec.");

private readonly HistogramLogWriter _logWriter;
private readonly FileStream _outputStream;
private int _isCompleted = -1;

public RecorderExample()
{
_outputStream = File.Create(LogPath);
_logWriter = new HistogramLogWriter(_outputStream);
}

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);

var outputThread = new Thread(ts => WriteToDisk());
outputThread.Start();
RecordMeasurements();
//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();
}

private bool HasRunBeenCalled()
{
var currentValue = Interlocked.CompareExchange(ref _isCompleted, 0, -1);
return currentValue != -1;
}

private static void WriteToDisk()
private void WriteToDisk(Recorder recorder)
{
//Sample every second until flagged as completed.
var accumulatingHistogram = new LongHistogram(TimeStamp.Hours(1), 3);
while (_isCompleted == 0)
{
Thread.Sleep(1000);

var histogram = Recorder.GetIntervalHistogram();
AccumulatingHistogram.Add(histogram);
var histogram = recorder.GetIntervalHistogram();
accumulatingHistogram.Add(histogram);
_logWriter.Append(histogram);
Console.WriteLine($"{DateTime.Now:o} Interval.TotalCount = {histogram.TotalCount,10:G}. Accumulated.TotalCount = {AccumulatingHistogram.TotalCount,10:G}.");
Console.WriteLine($"{DateTime.Now:o} Interval.TotalCount = {histogram.TotalCount,10:G}. Accumulated.TotalCount = {accumulatingHistogram.TotalCount,10:G}.");
}
_logWriter.Dispose();
_outputStream.Dispose();


Console.WriteLine("Log contents");
Console.WriteLine(File.ReadAllText(LogPath));
Console.WriteLine();
Console.WriteLine("Percentile distribution (values reported in milliseconds)");
accumulatingHistogram.OutputPercentileDistribution(Console.Out, outputValueUnitScalingRatio: OutputScalingFactor.TimeStampToMilliseconds);

Console.WriteLine("Output thread finishing.");
}

/// <summary>
/// Shows a sample loop where an action is executed, and the latency of each execution is recorded.
/// </summary>
private static void RecordMeasurements()
private void RecordMeasurements(IRecorder recorder)
{
var sut = new SocketTester("google.com");
Action actionToMeasure = sut.CreateAndCloseDatagramSocket;
var timer = Stopwatch.StartNew();
Action actionToMeasure = CreateAndCloseDatagramSocket;
do
{
Recorder.Record(actionToMeasure);
recorder.Record(actionToMeasure);
} while (timer.Elapsed < RunPeriod);
Interlocked.Increment(ref _isCompleted);
}

private static void CreateAndCloseDatagramSocket()
{
try
{
using (var socket = new Socket(AddressFamily.Value, SocketType.Stream, ProtocolType.Tcp))
{
}
}
catch (SocketException)
{
}
}

private static AddressFamily GetAddressFamily(string url)
public void Dispose()
{
var hostIpAddress = Dns.GetHostEntry(url).AddressList[0];
var hostIpEndPoint = new IPEndPoint(hostIpAddress, 80);
return hostIpEndPoint.AddressFamily;
_logWriter.Dispose();
_outputStream.Dispose();
}
}
}
39 changes: 39 additions & 0 deletions src/HdrHistogram.Examples/SocketTester.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Net;
using System.Net.Sockets;

namespace HdrHistogram.Examples
{
/// <summary>
/// A class used to test opening and closing a TCP socket.
/// </summary>
public class SocketTester
{
private readonly Lazy<AddressFamily> _addressFamily;
public SocketTester(string url)
{
_addressFamily = new Lazy<AddressFamily>(() => GetAddressFamily(url));
}

public void CreateAndCloseDatagramSocket()
{
try
{
using (var socket = new Socket(_addressFamily.Value, SocketType.Stream, ProtocolType.Tcp))
{
}
}
catch (SocketException)
{
}
}


private static AddressFamily GetAddressFamily(string url)
{
var hostIpAddress = Dns.GetHostEntry(url).AddressList[0];
var hostIpEndPoint = new IPEndPoint(hostIpAddress, 80);
return hostIpEndPoint.AddressFamily;
}
}
}
3 changes: 2 additions & 1 deletion src/HdrHistogram.UnitTests/HdrHistogram.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<ItemGroup>
<Compile Include="ConcurrentHistogramTestBase.cs" />
<Compile Include="HistogramEncodingTestBase.cs" />
<Compile Include="HistogramFactoryTests.cs" />
<Compile Include="IntConcurrentHistogramTests.cs" />
<Compile Include="IntHistogramEncodingTests.cs" />
<Compile Include="LongConcurrentHistogramTests.cs" />
Expand All @@ -76,7 +77,7 @@
<Compile Include="Recording\RecorderTestWithIntHistogram.cs" />
<Compile Include="Recording\RecorderTestWithLongConcurrentHistogram.cs" />
<Compile Include="Recording\RecorderTestWithLongHistogram.cs" />
<Compile Include="Recording\RecorderTestWithLShortHistogram.cs" />
<Compile Include="Recording\RecorderTestWithShortHistogram.cs" />
<Compile Include="ShortHistogramEncodingTests.cs" />
<Compile Include="ShortHistogramTests.cs" />
<Compile Include="TimeStampTests.cs" />
Expand Down
Loading