Files
ParadoxSaveParser/ParadoxSaveParser.Benchmarks/BenchData.cs
T
2026-09-14 23:09:25 +02:00

78 lines
2.9 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using ParadoxSaveParser.Lib;
namespace ParadoxSaveParser.Benchmarks;
/// <summary>
/// Locates and lazily loads the benchmark corpus:
/// a real EU4 <c>gamestate</c> file and its compact JSON twin (for jq).
/// Override the directory with the PSP_BENCH_DATA environment variable.
/// </summary>
public static class BenchData
{
public const string PdxQuery = "countries.*.technology";
/// <summary>jq program extracting the same data as <see cref="PdxQuery" />.</summary>
public const string JqQuery = ".countries | map_values(.technology)";
public static string Dir { get; } =
Environment.GetEnvironmentVariable("PSP_BENCH_DATA")
?? Path.Combine(FindRepoRoot(), "ParadoxSaveParser.CLI", "bin", "Debug", "net10.0");
public static string PdxPath => Path.Combine(Dir, "gamestate");
public static string JsonPath => Path.Combine(Dir, "gamestate.min.json");
private static byte[]? _pdxBytes;
private static string? _pdxText;
/// <summary>Raw bytes of the save, kept in memory so benchmarks don't measure disk I/O.</summary>
public static byte[] PdxBytes => _pdxBytes ??= File.ReadAllBytes(PdxPath);
/// <summary>
/// The save decoded as text for the regex engines.
/// Latin1 is used because EU4 saves contain non-UTF8 bytes inside dynasty names,
/// and it maps every byte to exactly one char.
/// </summary>
public static string PdxText => _pdxText ??= Encoding.Latin1.GetString(PdxBytes);
private static string FindRepoRoot()
{
var dir = new DirectoryInfo(AppContext.BaseDirectory);
while (dir != null && !File.Exists(Path.Combine(dir.FullName, "ParadoxSaveParser.sln")))
dir = dir.Parent;
return dir?.FullName ?? Directory.GetCurrentDirectory();
}
/// <summary>
/// Produces the compact JSON twin of the save file, which is what jq is given.
/// Compact (not indented) so jq isn't penalized by parsing whitespace.
/// </summary>
public static void PrepareJson()
{
if (File.Exists(JsonPath))
{
Console.WriteLine($"{JsonPath} already exists, skipping");
return;
}
Console.WriteLine($"parsing {PdxPath} ...");
using var input = File.OpenRead(PdxPath);
var root = new SaveParserEU4(input, null).Parse();
Console.WriteLine($"serializing to {JsonPath} ...");
using var output = File.Create(JsonPath);
JsonSerializer.Serialize(output, root, new JsonSerializerOptions
{
WriteIndented = false,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
MaxDepth = 1024,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
});
Console.WriteLine($"done: {new FileInfo(JsonPath).Length / 1024 / 1024} MB");
}
}