Skip to content

Commit

Permalink
perf: add timer benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
DorielRivalet committed Aug 31, 2023
1 parent 3cc2c24 commit 26c071b
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 27 deletions.
141 changes: 115 additions & 26 deletions MHFZOverlayBenchmark/Comparisons/TimerComparison.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,143 @@ namespace MHFZOverlayBenchmark.Comparisons;
using BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Intrinsics.Arm;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

public enum TimerFormat
{
MinutesSeconds,
MinutesSecondsMilliseconds,
HoursMinutesSeconds,
}

public enum TimerMode
{
TimeLeft,
Elapsed,
}

// TODO optimize
[RPlotExporter]
[MedianColumn, MinColumn, MaxColumn]
[UnicodeConsoleLogger]
[MemoryDiagnoser]
[ExceptionDiagnoser]
public class TimerComparison
{
[Params(0, 216_000)] // 2 hours at 30fps
public int TimeDefInt { get; set; }
public const decimal FramesPerSecond = 30;

[Params(0, 216_000)]
public int TimeInt { get; set; }
public string TimeLeftPercentNumber = " (100%)";

[Params(true, false)] // Arguments can be combined with Params
public bool TimePercentShown;
[Params(120 * 60 * 30)]
public int TimeDefInt;

[Benchmark]
[Arguments(100, 10)]
[Arguments(100, 20)]
[Arguments(200, 10)]
[Arguments(200, 20)]
public void Benchmark(int a, int b)
public string BenchmarkSimpleTimer()
{
if (TimePercentShown)
Thread.Sleep(a + b + 5);
else
Thread.Sleep(a + b);
string s = string.Empty;
for (int i = TimeDefInt; i > 0; i--)
{
s = SimpleTimer(i, TimerFormat.MinutesSecondsMilliseconds, true, TimeDefInt, true, TimeLeftPercentNumber, TimerMode.Elapsed);
};

return s;
}

private const int N = 10000;
private readonly byte[] data;
[Benchmark]
public string BenchmarkTimeSpanTimer()
{
string s = string.Empty;
for (int i = TimeDefInt; i > 0; i--)
{
s = TimeSpanTimer(i, TimerFormat.MinutesSecondsMilliseconds, true, TimeDefInt, true, TimeLeftPercentNumber, TimerMode.Elapsed);
};

private readonly SHA256 sha256 = SHA256.Create();
private readonly MD5 md5 = MD5.Create();
return s;
}

public TimerComparison()
[Benchmark]
public string BenchmarkStringBuilderTimer()
{
data = new byte[N];
new Random(42).NextBytes(data);
string s = string.Empty;
for (int i = TimeDefInt; i > 0; i--)
{
s = StringBuilderTimer(i, TimerFormat.MinutesSecondsMilliseconds, true, TimeDefInt, true, TimeLeftPercentNumber, TimerMode.Elapsed);
};

return s;
}

[Benchmark]
public byte[] Sha256() => sha256.ComputeHash(data);
public string SimpleTimer(decimal timeInt, TimerFormat timerFormat, bool isFrames = true, decimal timeDefInt = 0, bool timeLeftPercentShown = false, string timeLeftPercentNumber = "", TimerMode timerMode = TimerMode.Elapsed)
{
// TODO wrong conditionals for timeint >= timedefint?
decimal time = timerMode == TimerMode.Elapsed && timeInt <= timeDefInt ? time = timeDefInt - timeInt : time = timeInt;
decimal framesPerSecond = isFrames ? FramesPerSecond : 1;
decimal milliseconds = time / framesPerSecond * 1000;
decimal totalMinutes = Math.Floor(milliseconds / 60000);
decimal minutes = totalMinutes >= 60 ? totalMinutes : Math.Floor(milliseconds / 60000);
decimal seconds = Math.Floor((milliseconds - (minutes * 60000)) / 1000);
decimal remainingMilliseconds = milliseconds - (minutes * 60000) - (seconds * 1000);
var timeLeftPercent = timeLeftPercentShown ? timeLeftPercentNumber : string.Empty;

[Benchmark]
public byte[] Md5() => md5.ComputeHash(data);
return timerFormat switch
{
TimerFormat.MinutesSeconds => $"{minutes:00}:{seconds:00}" + timeLeftPercent,
TimerFormat.MinutesSecondsMilliseconds => $"{minutes:00}:{seconds:00}.{remainingMilliseconds:000}" + timeLeftPercent,
_ => $"{minutes:00}:{seconds:00}.{remainingMilliseconds:000}" + timeLeftPercent,
};
}

public string StringBuilderTimer(decimal timeInt, TimerFormat timerFormat, bool isFrames = true, decimal timeDefInt = 0, bool timeLeftPercentShown = false, string timeLeftPercentNumber = "", TimerMode timerMode = TimerMode.Elapsed)
{
decimal time = timerMode == TimerMode.Elapsed && timeInt <= timeDefInt ? time = timeDefInt - timeInt : time = timeInt;
decimal framesPerSecond = isFrames ? FramesPerSecond : 1;
decimal totalSeconds = time / framesPerSecond;
decimal totalMinutes = Math.Floor(totalSeconds / 60);
decimal minutes = totalMinutes >= 60 ? totalMinutes : Math.Floor(totalSeconds / 60);
decimal seconds = Math.Floor(totalSeconds % 60);
decimal milliseconds = Math.Round((time % framesPerSecond) * (1000M / framesPerSecond));
var timeLeftPercent = timeLeftPercentShown ? timeLeftPercentNumber : string.Empty;

StringBuilder sb = new StringBuilder();
switch (timerFormat)
{
default:
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:00}:{1:00}.{2:000}", minutes, seconds, milliseconds);
break;
case TimerFormat.MinutesSeconds:
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:00}:{1:00}", minutes, seconds);
break;
case TimerFormat.MinutesSecondsMilliseconds:
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:00}:{1:00}.{2:000}", minutes, seconds, milliseconds);
break;
}

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

public string TimeSpanTimer(decimal timeInt, TimerFormat timerFormat, bool isFrames = true, decimal timeDefInt = 0, bool timeLeftPercentShown = false, string timeLeftPercentNumber = "", TimerMode timerMode = TimerMode.Elapsed)
{
decimal time = timerMode == TimerMode.Elapsed && timeInt <= timeDefInt ? time = timeDefInt - timeInt : time = timeInt;
decimal framesPerSecond = isFrames ? FramesPerSecond : 1;
decimal timeInSeconds = time / framesPerSecond;
TimeSpan timeInSecondsSpan = TimeSpan.FromSeconds((double)timeInSeconds);
int roundedMilliseconds = (int)(Math.Round(timeInSecondsSpan.TotalMilliseconds) % 1000);
var totalMinutes = Math.Floor(timeInSecondsSpan.TotalSeconds / 60);
var minutes = totalMinutes >= 60 ? totalMinutes : timeInSecondsSpan.Minutes;
var timeLeftPercent = timeLeftPercentShown ? timeLeftPercentNumber : string.Empty;

// Format the TimeSpan object as a string
return timerFormat switch
{
TimerFormat.MinutesSeconds => $"{minutes:00}:{timeInSecondsSpan.Seconds:00}" + timeLeftPercent,
TimerFormat.MinutesSecondsMilliseconds => $"{minutes:00}:{timeInSecondsSpan.Seconds:00}.{roundedMilliseconds:000}" + timeLeftPercent,
_ => $"{minutes:00}:{timeInSecondsSpan.Seconds:00}.{roundedMilliseconds:000}" + timeLeftPercent,
};
}
}
10 changes: 9 additions & 1 deletion MHFZOverlayBenchmark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,13 @@
using BenchmarkDotNet.Running;
using System.Management;
using MHFZOverlayBenchmark.Comparisons;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Reports;
using Perfolizer.Horology;
using BenchmarkDotNet.Columns;

var summary = BenchmarkRunner.Run<TimerComparison>();
var summary = BenchmarkRunner.Run<TimerComparison>(
DefaultConfig.Instance.WithSummaryStyle(
SummaryStyle.Default
.WithTimeUnit(TimeUnit.Millisecond)
.WithSizeUnit(SizeUnit.MB)));

0 comments on commit 26c071b

Please sign in to comment.