From 1efcf3327c37ba9be7b6290e2bfb2330c8244f67 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 25 Nov 2019 14:21:09 -0600 Subject: [PATCH] Add SHA-256 benchmark with the option to display cycles per byte --- src/hactoolnet/CliParser.cs | 11 +++++++ src/hactoolnet/Options.cs | 1 + src/hactoolnet/ProcessBench.cs | 53 ++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/hactoolnet/CliParser.cs b/src/hactoolnet/CliParser.cs index 70a927cc..0dc6b6f9 100644 --- a/src/hactoolnet/CliParser.cs +++ b/src/hactoolnet/CliParser.cs @@ -60,6 +60,7 @@ namespace hactoolnet new CliOption("hashedfs", 0, (o, a) => o.BuildHfs = true), new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(a[0])), new CliOption("bench", 1, (o, a) => o.BenchType = a[0]), + new CliOption("cpufreq", 1, (o, a) => o.CpuFrequencyGhz = ParseDouble(a[0])), new CliOption("replacefile", 2, (o, a) => { @@ -172,6 +173,16 @@ namespace hactoolnet return id; } + private static double ParseDouble(string input) + { + if (!double.TryParse(input, out double value)) + { + PrintWithUsage($"Could not parse value \"{input}\""); + } + + return value; + } + private static void PrintWithUsage(string toPrint) { Console.WriteLine(toPrint); diff --git a/src/hactoolnet/Options.cs b/src/hactoolnet/Options.cs index a9280de9..152a3c80 100644 --- a/src/hactoolnet/Options.cs +++ b/src/hactoolnet/Options.cs @@ -53,6 +53,7 @@ namespace hactoolnet public bool BuildHfs; public ulong TitleId; public string BenchType; + public double CpuFrequencyGhz; public IntegrityCheckLevel IntegrityLevel { diff --git a/src/hactoolnet/ProcessBench.cs b/src/hactoolnet/ProcessBench.cs index b62f6dac..9c6d8f99 100644 --- a/src/hactoolnet/ProcessBench.cs +++ b/src/hactoolnet/ProcessBench.cs @@ -24,6 +24,9 @@ namespace hactoolnet private const int BatchCipherBenchSize = 1024 * 1024; // ReSharper disable once UnusedMember.Local private const int SingleBlockCipherBenchSize = 1024 * 128; + private const int ShaBenchSize = 1024 * 128; + + private static double CpuFrequency { get; set; } private static void CopyBenchmark(IStorage src, IStorage dst, int iterations, string label, IProgressReport logger) { @@ -186,7 +189,7 @@ namespace hactoolnet var input = new byte[BatchCipherBenchSize]; var output = new byte[BatchCipherBenchSize]; - Func resultPrinter = time => Util.GetBytesReadable((long)(BatchCipherBenchSize / time)) + "/s"; + Func resultPrinter = time => GetPerformanceString(time, BatchCipherBenchSize); // Skip the first benchmark set if we don't have AES-NI intrinsics for (int i = Aes.IsAesNiSupported() ? 0 : 1; i < 2; i++) @@ -235,7 +238,7 @@ namespace hactoolnet var input = new byte[SingleBlockCipherBenchSize]; var output = new byte[SingleBlockCipherBenchSize]; - Func resultPrinter = time => Util.GetBytesReadable((long)(SingleBlockCipherBenchSize / time)) + "/s"; + Func resultPrinter = time => GetPerformanceString(time, SingleBlockCipherBenchSize); bench.Register("AES single-block encrypt", () => { }, EncryptBlocks, resultPrinter); bench.Register("AES single-block decrypt", () => { }, DecryptBlocks, resultPrinter); @@ -284,6 +287,35 @@ namespace hactoolnet #endif } + private static void RegisterShaBenchmarks(MultiBenchmark bench) + { + var input = new byte[ShaBenchSize]; + var digest = new byte[Sha256.DigestSize]; + + Func resultPrinter = time => GetPerformanceString(time, ShaBenchSize); + + RegisterHash("SHA-256 built-in", () => new Sha256Generator()); + + void RegisterHash(string name, Func hashGenerator) + { + IHash hash = null; + + Action setup = () => + { + hash = hashGenerator(); + hash.Initialize(); + }; + + Action action = () => + { + hash.Update(input); + hash.GetHash(digest); + }; + + bench.Register(name, setup, action, resultPrinter); + } + } + private static void RunCipherBenchmark(Func cipherNet, Func cipherLibHac, CipherTaskSeparate function, bool benchBlocked, string label, IProgressReport logger) { @@ -341,8 +373,24 @@ namespace hactoolnet } } + private static string GetPerformanceString(double seconds, long bytes) + { + string cyclesPerByteString = string.Empty; + double bytesPerSec = bytes / seconds; + + if (CpuFrequency > 0) + { + double cyclesPerByte = CpuFrequency / bytesPerSec; + cyclesPerByteString = $" ({cyclesPerByte:N3}x)"; + } + + return Util.GetBytesReadable((long)bytesPerSec) + "/s" + cyclesPerByteString; + } + public static void Process(Context ctx) { + CpuFrequency = ctx.Options.CpuFrequencyGhz * 1_000_000_000; + switch (ctx.Options.BenchType?.ToLower()) { case "aesctr": @@ -465,6 +513,7 @@ namespace hactoolnet RegisterAesSequentialBenchmarks(bench); RegisterAesSingleBlockBenchmarks(bench); + RegisterShaBenchmarks(bench); bench.Run(); break;