80 lines
2.6 KiB
C#
80 lines
2.6 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using BenchmarkDotNet.Attributes;
|
|
using BenchmarkDotNet.Engines;
|
|
|
|
namespace ParadoxSaveParser.Benchmarks;
|
|
|
|
/// <summary>
|
|
/// jq runs as an external process on the JSON twin of the save.
|
|
/// Numbers therefore include process start and reading the file from the OS page cache,
|
|
/// which is exactly what you pay when you shell out to jq.
|
|
/// <see cref="JqNoop" /> measures that fixed overhead so it can be subtracted.
|
|
/// </summary>
|
|
[SimpleJob(RunStrategy.Monitoring, launchCount: 1, warmupCount: 1, iterationCount: 5)]
|
|
public class JqBenchmarks
|
|
{
|
|
public static string JqPath { get; set; } = "jq";
|
|
|
|
[GlobalSetup]
|
|
public void Setup() => Run("--version", null);
|
|
|
|
[Benchmark(Description = "jq .countries | map_values(.technology)")]
|
|
public int Jq() => Run("-c", BenchData.JqQuery);
|
|
|
|
[Benchmark(Description = "jq empty (parse only)")]
|
|
public int JqParseOnly() => Run("-c", "empty");
|
|
|
|
[Benchmark(Description = "jq --stream (no DOM)")]
|
|
public int JqStream() => Run("-c --stream", "empty");
|
|
|
|
[Benchmark(Description = "jq process startup only (tiny input)")]
|
|
public int JqNoop()
|
|
{
|
|
var psi = new ProcessStartInfo(JqPath)
|
|
{
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardInput = true,
|
|
UseShellExecute = false,
|
|
};
|
|
psi.ArgumentList.Add("-c");
|
|
psi.ArgumentList.Add("empty");
|
|
using var p = Process.Start(psi)!;
|
|
p.StandardInput.Write("{}");
|
|
p.StandardInput.Close();
|
|
p.StandardOutput.ReadToEnd();
|
|
p.WaitForExit();
|
|
return p.ExitCode;
|
|
}
|
|
|
|
private static int Run(string flags, string? program)
|
|
{
|
|
var psi = new ProcessStartInfo(JqPath)
|
|
{
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
};
|
|
foreach (var f in flags.Split(' ', StringSplitOptions.RemoveEmptyEntries))
|
|
psi.ArgumentList.Add(f);
|
|
if (program != null)
|
|
{
|
|
psi.ArgumentList.Add(program);
|
|
psi.ArgumentList.Add(BenchData.JsonPath);
|
|
}
|
|
|
|
using var p = Process.Start(psi)!;
|
|
// output must be drained, otherwise jq blocks on a full pipe
|
|
long bytes = 0;
|
|
var buf = new char[1 << 16];
|
|
int read;
|
|
while ((read = p.StandardOutput.Read(buf, 0, buf.Length)) > 0)
|
|
bytes += read;
|
|
p.StandardError.ReadToEnd();
|
|
p.WaitForExit();
|
|
if (p.ExitCode != 0)
|
|
throw new Exception($"jq exited with {p.ExitCode}");
|
|
return (int)(bytes & int.MaxValue);
|
|
}
|
|
}
|