Skip to content

Commit fc2dd85

Browse files
authored
Merge pull request #32 from LeeCampbell/HistogramFactory
Adding HistogramFactory. Updated RecorderExample
2 parents bbaf0fa + 83c189d commit fc2dd85

28 files changed

+969
-188
lines changed

src/HdrHistogram.Benchmarking/Recording/Recording32BitBenchmark.cs

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,39 @@ public class Recording32BitBenchmark
2020

2121
public Recording32BitBenchmark()
2222
{
23-
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
23+
const int lowestTrackableValue = 1;
2424
var highestTrackableValue = TimeStamp.Minutes(10);
25-
_testValues = Enumerable.Range(0, 32)
25+
const int numberOfSignificantValueDigits = 3;
26+
27+
_testValues = TestValues(highestTrackableValue);
28+
29+
_longHistogram = new LongHistogram(highestTrackableValue, numberOfSignificantValueDigits);
30+
_intHistogram = new IntHistogram(highestTrackableValue, numberOfSignificantValueDigits);
31+
_shortHistogram = new ShortHistogram(highestTrackableValue, numberOfSignificantValueDigits);
32+
33+
_longConcurrentHistogram = new LongConcurrentHistogram(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits);
34+
_intConcurrentHistogram = new IntConcurrentHistogram(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits);
35+
36+
_longRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new LongHistogram(id, low, hi, sf));
37+
_longConcurrentRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new LongConcurrentHistogram(id, low, hi, sf));
38+
_intRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new IntHistogram(id, low, hi, sf));
39+
_intConcurrentRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new IntConcurrentHistogram(id, low, hi, sf));
40+
_shortRecorder = new Recorder(lowestTrackableValue, highestTrackableValue, numberOfSignificantValueDigits, (id, low, hi, sf) => new ShortHistogram(id, low, hi, sf));
41+
}
42+
43+
private static long[] TestValues(long highestTrackableValue)
44+
{
45+
//Create array of +ve numbers in the 'maxBit' bit range (i.e. 32 bit or 64bit)
46+
// 32 bit values are the 89 values
47+
// 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,
48+
// 16383,16384,16385,32767,32768,32769,65535,65536,65537,131071,131072,131073,262143,262144,262145,524287,524288,524289,1048575,1048576,1048577,
49+
// 2097151,2097152,2097153,4194303,4194304,4194305,8388607,8388608,8388609,16777215,16777216,16777217,33554431,33554432,33554433,
50+
// 67108863,67108864,67108865,134217727,134217728,134217729,268435455,268435456,268435457,536870911,536870912,536870913,1073741823,1073741824,1073741825
51+
//These value are choosen as they are the edge case values of where our bucket boundaries lie. i.e.
52+
// a power of 2
53+
// 1 less than a power of 2
54+
// 1 more than a power of 2
55+
return Enumerable.Range(0, 32)
2656
.Select(exp => new { Value = 1L << exp, LZC = 63 - exp })
2757
.SelectMany(x => new[]
2858
{
@@ -34,19 +64,6 @@ public Recording32BitBenchmark()
3464
.Where(x => x < highestTrackableValue)
3565
.Distinct()
3666
.ToArray();
37-
38-
_longHistogram = new LongHistogram(highestTrackableValue, 3);
39-
_intHistogram = new IntHistogram(highestTrackableValue, 3);
40-
_shortHistogram = new ShortHistogram(highestTrackableValue, 3);
41-
42-
_longConcurrentHistogram = new LongConcurrentHistogram(1, highestTrackableValue, 3);
43-
_intConcurrentHistogram = new IntConcurrentHistogram(1, highestTrackableValue, 3);
44-
45-
_longRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new LongHistogram(id, low, hi, sf));
46-
_longConcurrentRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new LongConcurrentHistogram(id, low, hi, sf));
47-
_intRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new IntHistogram(id, low, hi, sf));
48-
_intConcurrentRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new IntConcurrentHistogram(id, low, hi, sf));
49-
_shortRecorder = new Recorder(1, highestTrackableValue, 3, (id, low, hi, sf) => new ShortHistogram(id, low, hi, sf));
5067
}
5168

5269
[Benchmark(Baseline = true)]

src/HdrHistogram.Examples/HdrHistogram.Examples.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<Compile Include="Properties\AssemblyInfo.cs" />
4646
<Compile Include="RecorderExample.cs" />
4747
<Compile Include="SimpleHistogramExample.cs" />
48+
<Compile Include="SocketTester.cs" />
4849
</ItemGroup>
4950
<ItemGroup>
5051
<None Include="app.config" />

src/HdrHistogram.Examples/Program.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ class Program
55
static void Main(string[] args)
66
{
77
//SimpleHistogramExample.Run();
8-
RecorderExample.Run();
8+
using (var example = new RecorderExample())
9+
{
10+
example.Run();
11+
}
912
}
1013
}
1114
}
Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
using System;
22
using System.Diagnostics;
33
using System.IO;
4-
using System.Net;
5-
using System.Net.Sockets;
64
using System.Threading;
75

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

26-
public static void Run()
27-
{
28-
Console.WriteLine($"Running for {RunPeriod.TotalSeconds}sec.");
2918

19+
private readonly HistogramLogWriter _logWriter;
20+
private readonly FileStream _outputStream;
21+
private int _isCompleted = -1;
22+
23+
public RecorderExample()
24+
{
3025
_outputStream = File.Create(LogPath);
3126
_logWriter = new HistogramLogWriter(_outputStream);
27+
}
28+
29+
public void Run()
30+
{
31+
if (HasRunBeenCalled())
32+
throw new InvalidOperationException("Can only call run once.");
33+
34+
Console.WriteLine($"Running for {RunPeriod.TotalSeconds}sec.");
35+
3236
//Write the headers, but no histograms (as we don't have any yet).
3337
_logWriter.Write(DateTime.Now);
3438

35-
var outputThread = new Thread(ts => WriteToDisk());
36-
outputThread.Start();
37-
RecordMeasurements();
39+
//ThreadSafe-writes require a Concurrent implementation of a Histogram
40+
//ThreadSafe-reads require a recorder
41+
var recorder = HistogramFactory
42+
.With64BitBucketSize() //LongHistogram
43+
.WithValuesFrom(1) //Default value
44+
.WithValuesUpTo(TimeStamp.Minutes(10)) //Default value
45+
.WithPrecisionOf(3) //Default value
46+
.WithThreadSafeWrites() //Switches internal imp to concurrent version i.e. LongConcurrentHistogram
47+
.WithThreadSafeReads() //returns a Recorder that wraps the LongConcurrentHistogram
48+
.Create();
49+
50+
var outputThread = new Thread(ts => WriteToDisk((Recorder)ts));
51+
outputThread.Start(recorder);
52+
53+
RecordMeasurements(recorder);
54+
55+
//Wait for the output thread to complete writing.
56+
outputThread.Join();
57+
}
58+
59+
private bool HasRunBeenCalled()
60+
{
61+
var currentValue = Interlocked.CompareExchange(ref _isCompleted, 0, -1);
62+
return currentValue != -1;
3863
}
3964

40-
private static void WriteToDisk()
65+
private void WriteToDisk(Recorder recorder)
4166
{
4267
//Sample every second until flagged as completed.
68+
var accumulatingHistogram = new LongHistogram(TimeStamp.Hours(1), 3);
4369
while (_isCompleted == 0)
4470
{
4571
Thread.Sleep(1000);
4672

47-
var histogram = Recorder.GetIntervalHistogram();
48-
AccumulatingHistogram.Add(histogram);
73+
var histogram = recorder.GetIntervalHistogram();
74+
accumulatingHistogram.Add(histogram);
4975
_logWriter.Append(histogram);
50-
Console.WriteLine($"{DateTime.Now:o} Interval.TotalCount = {histogram.TotalCount,10:G}. Accumulated.TotalCount = {AccumulatingHistogram.TotalCount,10:G}.");
76+
Console.WriteLine($"{DateTime.Now:o} Interval.TotalCount = {histogram.TotalCount,10:G}. Accumulated.TotalCount = {accumulatingHistogram.TotalCount,10:G}.");
5177
}
5278
_logWriter.Dispose();
5379
_outputStream.Dispose();
80+
81+
5482
Console.WriteLine("Log contents");
5583
Console.WriteLine(File.ReadAllText(LogPath));
84+
Console.WriteLine();
85+
Console.WriteLine("Percentile distribution (values reported in milliseconds)");
86+
accumulatingHistogram.OutputPercentileDistribution(Console.Out, outputValueUnitScalingRatio: OutputScalingFactor.TimeStampToMilliseconds);
87+
5688
Console.WriteLine("Output thread finishing.");
5789
}
5890

5991
/// <summary>
6092
/// Shows a sample loop where an action is executed, and the latency of each execution is recorded.
6193
/// </summary>
62-
private static void RecordMeasurements()
94+
private void RecordMeasurements(IRecorder recorder)
6395
{
96+
var sut = new SocketTester("google.com");
97+
Action actionToMeasure = sut.CreateAndCloseDatagramSocket;
6498
var timer = Stopwatch.StartNew();
65-
Action actionToMeasure = CreateAndCloseDatagramSocket;
6699
do
67100
{
68-
Recorder.Record(actionToMeasure);
101+
recorder.Record(actionToMeasure);
69102
} while (timer.Elapsed < RunPeriod);
70103
Interlocked.Increment(ref _isCompleted);
71104
}
72105

73-
private static void CreateAndCloseDatagramSocket()
74-
{
75-
try
76-
{
77-
using (var socket = new Socket(AddressFamily.Value, SocketType.Stream, ProtocolType.Tcp))
78-
{
79-
}
80-
}
81-
catch (SocketException)
82-
{
83-
}
84-
}
85-
86-
private static AddressFamily GetAddressFamily(string url)
106+
public void Dispose()
87107
{
88-
var hostIpAddress = Dns.GetHostEntry(url).AddressList[0];
89-
var hostIpEndPoint = new IPEndPoint(hostIpAddress, 80);
90-
return hostIpEndPoint.AddressFamily;
108+
_logWriter.Dispose();
109+
_outputStream.Dispose();
91110
}
92111
}
93112
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Net;
3+
using System.Net.Sockets;
4+
5+
namespace HdrHistogram.Examples
6+
{
7+
/// <summary>
8+
/// A class used to test opening and closing a TCP socket.
9+
/// </summary>
10+
public class SocketTester
11+
{
12+
private readonly Lazy<AddressFamily> _addressFamily;
13+
public SocketTester(string url)
14+
{
15+
_addressFamily = new Lazy<AddressFamily>(() => GetAddressFamily(url));
16+
}
17+
18+
public void CreateAndCloseDatagramSocket()
19+
{
20+
try
21+
{
22+
using (var socket = new Socket(_addressFamily.Value, SocketType.Stream, ProtocolType.Tcp))
23+
{
24+
}
25+
}
26+
catch (SocketException)
27+
{
28+
}
29+
}
30+
31+
32+
private static AddressFamily GetAddressFamily(string url)
33+
{
34+
var hostIpAddress = Dns.GetHostEntry(url).AddressList[0];
35+
var hostIpEndPoint = new IPEndPoint(hostIpAddress, 80);
36+
return hostIpEndPoint.AddressFamily;
37+
}
38+
}
39+
}

src/HdrHistogram.UnitTests/HdrHistogram.UnitTests.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<ItemGroup>
5252
<Compile Include="ConcurrentHistogramTestBase.cs" />
5353
<Compile Include="HistogramEncodingTestBase.cs" />
54+
<Compile Include="HistogramFactoryTests.cs" />
5455
<Compile Include="IntConcurrentHistogramTests.cs" />
5556
<Compile Include="IntHistogramEncodingTests.cs" />
5657
<Compile Include="LongConcurrentHistogramTests.cs" />
@@ -76,7 +77,7 @@
7677
<Compile Include="Recording\RecorderTestWithIntHistogram.cs" />
7778
<Compile Include="Recording\RecorderTestWithLongConcurrentHistogram.cs" />
7879
<Compile Include="Recording\RecorderTestWithLongHistogram.cs" />
79-
<Compile Include="Recording\RecorderTestWithLShortHistogram.cs" />
80+
<Compile Include="Recording\RecorderTestWithShortHistogram.cs" />
8081
<Compile Include="ShortHistogramEncodingTests.cs" />
8182
<Compile Include="ShortHistogramTests.cs" />
8283
<Compile Include="TimeStampTests.cs" />

0 commit comments

Comments
 (0)