Skip to content

Commit

Permalink
Improved benchmark and overhead calculation.
Browse files Browse the repository at this point in the history
  • Loading branch information
CptMoore committed Jan 9, 2025
1 parent ed465d7 commit a38cdf7
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 40 deletions.
6 changes: 3 additions & 3 deletions ModTek/Features/Logging/FastBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ internal void Append(byte[] value)
// TODO once we know that its always above some value, we can just set it and remove the benchmark
private static int FindMemCpyThreshold()
{
const int MaxSize = 2 * 1024;
const int MaxSize = 4 * 1024;
var srcA = new byte[MaxSize];
var dstA = new byte[MaxSize];
var dst = stackalloc byte[MaxSize];
Expand All @@ -98,7 +98,7 @@ private static int FindMemCpyThreshold()
for (var w = 0; w < WarmupCount + 1; w++)
{
var shouldMeasure = w == WarmupCount;
const int StepSize = 128;
const int StepSize = 256;
const int ThresholdMin = 256;
for (var size=ThresholdMin+StepSize; size<=MaxSize; size+=StepSize) {
for (var run = 0; run < TestRunsPerSize; run++)
Expand All @@ -124,7 +124,7 @@ private static int FindMemCpyThreshold()
}
if (shouldMeasure)
{
if (MTStopwatch.FastestTicksSum(memCpyTicks) > MTStopwatch.FastestTicksSum(byteBufferTicks))
if (MTStopwatch.TicksMin(memCpyTicks) > MTStopwatch.TicksMin(byteBufferTicks))
{
return size - StepSize;
}
Expand Down
66 changes: 41 additions & 25 deletions ModTek/Util/Stopwatch/MTStopwatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,32 @@ internal class MTStopwatch
protected long _count;
protected long _ticks;

internal double _overheadInMeasurement = s_timestampOverheadInMeasurement;
internal double _overheadInMeasurement = s_timestampOverhead;

internal byte TimestampCountPerMeasurement { get; init; } = 2;
protected double OverheadPerMeasurement => s_timestampOverheadInAndAfterMeasurement * TimestampCountPerMeasurement;
internal static double OverheadPerTimestampInNanoseconds => s_timestampOverheadInAndAfterMeasurement * TicksToNsMultiplier;
protected double OverheadPerMeasurement => s_timestampOverhead * TimestampCountPerMeasurement;
internal static double OverheadPerTimestampInNanoseconds => s_timestampOverhead * TicksToNsMultiplier;

protected static readonly double s_timestampOverheadInMeasurement; // 22.47ns
private static readonly double s_timestampOverheadInAndAfterMeasurement; // 23.216ns
protected static readonly double s_timestampOverhead;
static MTStopwatch()
{
const int Count = 100_000;
const int WarmupCount = Count/2;
const double ActualCount = Count - WarmupCount;
var smSum = 0L;
var seSum = 0L;
for (var i = 0; i < Count; i++)
{
var start = GetTimestamp();
// no operation in here, so mid-start should contain captured measurement overhead
var mid = GetTimestamp();
// we still want the actual total overhead too, so lets measure after the mid again
var end = GetTimestamp();
if (i >= WarmupCount)
s_timestampOverhead = GetTimestampOverhead();
}

private static double GetTimestampOverhead()
{
var overhead = 0d;
for (var r = 0; r < 100; r++) {
var start = System.Diagnostics.Stopwatch.GetTimestamp();
const int Count = 1000;
for (var l = 0; l < Count; l++)
{
smSum += mid - start;
seSum += end - start;
System.Diagnostics.Stopwatch.GetTimestamp();
}
var end = System.Diagnostics.Stopwatch.GetTimestamp();
overhead = (end - start) / (double)Count;
}
s_timestampOverheadInMeasurement = smSum / ActualCount;
s_timestampOverheadInAndAfterMeasurement = ( seSum - smSum ) / ActualCount;
return overhead;
}

internal void Reset()
Expand Down Expand Up @@ -68,15 +64,35 @@ protected virtual void AddMeasurement(long elapsedTicks, long delta)

internal MTStopwatchStats GetStats() => new(this, Volatile.Read(ref _count), Volatile.Read(ref _ticks));

internal static long FastestTicksSum(long[] ticks, double onlyIncludeFastest = 0.5)
internal static long TicksMin(long[] ticks)
{
var minTick = long.MaxValue;
for (var i = 0; i < ticks.Length; i++)
{
var tick = ticks[i];
if (tick == 0)
{
return 0;
}

if (tick < minTick)
{
minTick = tick;
}
}
return minTick;
}
internal static double TicksAvg(long[] ticks, double ignoreLower, double ignoreUpper)
{
Array.Sort(ticks);
var sum = 0L;
for (var i = 0; i < ticks.Length * onlyIncludeFastest; i++)
var start = (int)(ticks.Length * ignoreLower);
var end = (int)(ticks.Length * (1 - ignoreUpper));
for (var i = start; i < end; i++)
{
sum += ticks[i];
}
return sum;
return sum / (double)(end - start);
}

internal static TimeSpan TimeSpanFromTicks(long elapsedTicks)
Expand Down
20 changes: 8 additions & 12 deletions ModTek/Util/Stopwatch/MTStopwatchWithSampling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,24 @@ internal MTStopwatchWithSampling(uint samplingInterval)
internal double OverheadPerMeasurementWithSampling => OverheadPerMeasurement/_samplingInterval + s_samplingCheckOverhead;
internal double OverheadPerMeasurementWithoutSampling => OverheadPerMeasurement;

private static readonly double s_samplingCheckOverhead; // 1.554ns
private static readonly double s_samplingCheckOverhead;
internal static readonly bool DontOptimize;
static MTStopwatchWithSampling()
{
var ws = new MTStopwatchWithSampling(100);
const int Count = 100_000;
const int WarmupCount = Count/2;
const double ActualCount = Count - WarmupCount;
var sum = 0L;
var dontOptimize = false;
for (var i = 0; i < Count; i++)
for (var r = 0; r < 100; r++)
{
var start = GetTimestamp();
dontOptimize = ws.ShouldMeasure();
var end = GetTimestamp();
if (i >= WarmupCount)
const int Count = 1000;
for (var i = 0; i < Count; i++)
{
sum += end - start;
dontOptimize = ws.ShouldMeasure();
}
var end = GetTimestamp();
s_samplingCheckOverhead = (end - start)/(double)Count - s_timestampOverhead;
DontOptimize = dontOptimize;
}
s_samplingCheckOverhead = (sum - s_timestampOverheadInMeasurement * ActualCount) / ActualCount;
DontOptimize = dontOptimize;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down

0 comments on commit a38cdf7

Please sign in to comment.