using System.IO; using System.Text.RegularExpressions; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Engines; using ParadoxSaveParser.Lib; using PCRE; namespace ParadoxSaveParser.Benchmarks; /// /// In-process engines, all extracting countries.*.technology from the same 110 MB save. /// Input is preloaded into memory, so disk I/O is not part of any measurement. /// [MemoryDiagnoser] [SimpleJob(RunStrategy.Monitoring, launchCount: 1, warmupCount: 1, iterationCount: 5)] public class ExtractionBenchmarks { private byte[] _pdx = null!; private string _pdxText = null!; private byte[] _json = null!; private ISearchExpression _query = null!; private Regex _flatInterpreted = null!; private Regex _flatCompiled = null!; private Regex _flatSourceGen = null!; private Regex _pathAwareCompiled = null!; private Regex _pathAwareNonBacktracking = null!; private Regex _countriesBlock = null!; private PcreRegex _pcreFlat = null!; private PcreRegex _pcrePathAware = null!; [GlobalSetup] public void Setup() { _pdx = BenchData.PdxBytes; _pdxText = BenchData.PdxText; _json = File.ReadAllBytes(BenchData.JsonPath); _query = SearchExpressionCompiler.Compile(BenchData.PdxQuery); _flatInterpreted = new Regex(Extractors.FlatPattern, RegexOptions.None); _flatCompiled = new Regex(Extractors.FlatPattern, RegexOptions.Compiled); _flatSourceGen = Extractors.FlatSourceGen(); _pathAwareCompiled = new Regex(Extractors.PathAwarePattern, RegexOptions.Compiled); _pathAwareNonBacktracking = new Regex(Extractors.PathAwarePattern, RegexOptions.NonBacktracking); _countriesBlock = new Regex(Extractors.CountriesBlockPattern, RegexOptions.Compiled); _pcreFlat = new PcreRegex(Extractors.FlatPattern, PcreOptions.Compiled); _pcrePathAware = new PcreRegex(Extractors.PathAwarePattern, PcreOptions.Compiled); } [Benchmark(Baseline = true, Description = "SearchExpression (this project)")] public long SearchExpression() => Extractors.SearchExpression(_pdx, _query); [Benchmark(Description = "Full parse, then select")] public long FullParse() => Extractors.FullParseThenSelect(_pdx); [Benchmark(Description = ".NET Regex flat, interpreted")] public long RegexFlatInterpreted() => Extractors.RegexScan(_flatInterpreted, _pdxText); [Benchmark(Description = ".NET Regex flat, compiled")] public long RegexFlatCompiled() => Extractors.RegexScan(_flatCompiled, _pdxText); [Benchmark(Description = ".NET Regex flat, source generated")] public long RegexFlatSourceGen() => Extractors.RegexScan(_flatSourceGen, _pdxText); [Benchmark(Description = ".NET Regex path aware, compiled")] public long RegexPathAwareCompiled() => Extractors.RegexScan(_pathAwareCompiled, _pdxText); [Benchmark(Description = ".NET Regex path aware, NonBacktracking")] public long RegexPathAwareNonBacktracking() => Extractors.RegexScan(_pathAwareNonBacktracking, _pdxText); [Benchmark(Description = ".NET Regex balanced block + flat")] public long RegexBalancedTwoStage() => Extractors.RegexTwoStage(_countriesBlock, _flatCompiled, _pdxText); [Benchmark(Description = "PCRE.NET flat, JIT compiled")] public long PcreFlat() => Extractors.PcreScan(_pcreFlat, _pdxText); [Benchmark(Description = "PCRE.NET path aware, JIT compiled")] public long PcrePathAware() => Extractors.PcreScan(_pcrePathAware, _pdxText); [Benchmark(Description = "Utf8JsonReader over JSON twin")] public long Utf8JsonReader() => Extractors.Utf8JsonReaderScan(_json); [Benchmark(Description = "JsonDocument over JSON twin")] public long JsonDocument() => Extractors.JsonDocumentScan(_json); }