Add crypto benchmarks

This commit is contained in:
Alex Barney 2019-11-23 16:21:03 -06:00
parent ff23a9179c
commit e02e719ea5
2 changed files with 136 additions and 0 deletions

View file

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace hactoolnet
{
internal class MultiBenchmark
{
public int RunsNeeded { get; set; } = 500;
private List<BenchmarkItem> Benchmarks { get; } = new List<BenchmarkItem>();
public void Register(string name, Action setupAction, Action runAction, Func<double, string> resultPrinter)
{
var benchmark = new BenchmarkItem
{
Name = name,
Setup = setupAction,
Run = runAction,
PrintResult = resultPrinter
};
Benchmarks.Add(benchmark);
}
public void Run()
{
foreach (BenchmarkItem item in Benchmarks)
{
RunBenchmark(item);
Console.WriteLine($"{item.Name}: {item.Result}");
}
}
private void RunBenchmark(BenchmarkItem item)
{
double fastestRun = double.MaxValue;
var watch = new Stopwatch();
int runsSinceLastBest = 0;
while (runsSinceLastBest < RunsNeeded)
{
runsSinceLastBest++;
item.Setup();
watch.Restart();
item.Run();
watch.Stop();
if (fastestRun > watch.Elapsed.TotalSeconds)
{
fastestRun = watch.Elapsed.TotalSeconds;
runsSinceLastBest = 0;
}
}
item.Time = fastestRun;
item.Result = item.PrintResult(item.Time);
}
private class BenchmarkItem
{
public string Name { get; set; }
public double Time { get; set; }
public string Result { get; set; }
public Action Setup { get; set; }
public Action Run { get; set; }
public Func<double, string> PrintResult { get; set; }
}
}
}

View file

@ -15,6 +15,8 @@ namespace hactoolnet
private const int BlockSizeBlocked = 0x10; private const int BlockSizeBlocked = 0x10;
private const int BlockSizeSeparate = 0x10; private const int BlockSizeSeparate = 0x10;
private const int BatchCipherBenchSize = 1024 * 1024;
private static void CopyBenchmark(IStorage src, IStorage dst, int iterations, string label, IProgressReport logger) private static void CopyBenchmark(IStorage src, IStorage dst, int iterations, string label, IProgressReport logger)
{ {
// Warmup // Warmup
@ -171,6 +173,53 @@ namespace hactoolnet
logger.LogMessage($"{label}{averageRate}/s, fastest run: {fastestRate}/s, slowest run: {slowestRate}/s"); logger.LogMessage($"{label}{averageRate}/s, fastest run: {fastestRate}/s, slowest run: {slowestRate}/s");
} }
private static void RegisterAllCipherBenchmarks(MultiBenchmark bench)
{
var input = new byte[BatchCipherBenchSize];
var output = new byte[BatchCipherBenchSize];
Func<double, string> resultPrinter = time => Util.GetBytesReadable((long)(BatchCipherBenchSize / time)) + "/s";
// Skip the first benchmark set if we don't have AES-NI intrinsics
for (int i = Aes.IsAesNiSupported() ? 0 : 1; i < 2; i++)
{
// Prefer .NET crypto on the second set
string nameSuffix = i == 1 ? "built-in " : string.Empty;
bool preferDotNetImpl = i == 1;
RegisterCipher($"AES-ECB {nameSuffix}encrypt",
() => Aes.CreateEcbEncryptor(new byte[0x10], preferDotNetImpl));
RegisterCipher($"AES-ECB {nameSuffix}decrypt",
() => Aes.CreateEcbDecryptor(new byte[0x10], preferDotNetImpl));
RegisterCipher($"AES-CBC {nameSuffix}encrypt",
() => Aes.CreateCbcEncryptor(new byte[0x10], new byte[0x10], preferDotNetImpl));
RegisterCipher($"AES-CBC {nameSuffix}decrypt",
() => Aes.CreateCbcDecryptor(new byte[0x10], new byte[0x10], preferDotNetImpl));
RegisterCipher($"AES-CTR {nameSuffix}decrypt",
() => Aes.CreateCtrDecryptor(new byte[0x10], new byte[0x10], preferDotNetImpl));
RegisterCipher($"AES-XTS {nameSuffix}encrypt",
() => Aes.CreateXtsEncryptor(new byte[0x10], new byte[0x10], new byte[0x10], preferDotNetImpl));
RegisterCipher($"AES-XTS {nameSuffix}decrypt",
() => Aes.CreateXtsDecryptor(new byte[0x10], new byte[0x10], new byte[0x10], preferDotNetImpl));
}
void RegisterCipher(string name, Func<ICipher> cipherGenerator)
{
ICipher cipher = null;
Action setup = () => cipher = cipherGenerator();
Action action = () => cipher.Transform(input, output);
bench.Register(name, setup, action, resultPrinter);
}
}
private static void RunCipherBenchmark(Func<ICipher> cipherNet, Func<ICipher> cipherLibHac, private static void RunCipherBenchmark(Func<ICipher> cipherNet, Func<ICipher> cipherLibHac,
CipherTaskSeparate function, bool benchBlocked, string label, IProgressReport logger) CipherTaskSeparate function, bool benchBlocked, string label, IProgressReport logger)
{ {
@ -295,6 +344,7 @@ namespace hactoolnet
break; break;
} }
case "aescbcnew": case "aescbcnew":
{ {
Func<ICipher> encryptorNet = () => Aes.CreateCbcEncryptor(new byte[0x10], new byte[0x10], true); Func<ICipher> encryptorNet = () => Aes.CreateCbcEncryptor(new byte[0x10], new byte[0x10], true);
@ -325,6 +375,7 @@ namespace hactoolnet
break; break;
} }
case "aesxtsnew": case "aesxtsnew":
{ {
Func<ICipher> encryptorNet = () => Aes.CreateXtsEncryptor(new byte[0x10], new byte[0x10], new byte[0x10], true); Func<ICipher> encryptorNet = () => Aes.CreateXtsEncryptor(new byte[0x10], new byte[0x10], new byte[0x10], true);
@ -344,6 +395,16 @@ namespace hactoolnet
break; break;
} }
case "crypto":
{
var bench = new MultiBenchmark();
RegisterAllCipherBenchmarks(bench);
bench.Run();
break;
}
default: default:
ctx.Logger.LogMessage("Unknown benchmark type."); ctx.Logger.LogMessage("Unknown benchmark type.");
return; return;