diff --git a/README.md b/README.md index 431b3aa8..4ecccc76 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,20 @@ The main idea behind AngleSharp.Css is to expose the CSSOM as it would be in the - Calculated values (i.e., `calc(20px + 50%)`) - Window-based declaration calculations, see `window.GetComputedStyle` +## Benchmarks + +The `AngleSharp.Performance.Css` project uses [BenchmarkDotNet](https://benchmarkdotnet.org/) to compare CSS parsing performance across libraries. Run the benchmarks in Release mode: + +```bash +dotnet run --project src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj -c Release --framework net10.0 +``` + +To run a quick smoke test instead of a full benchmark: + +```bash +dotnet run --project src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj -c Release --framework net10.0 -- --job short +``` + ## Participating Participation in the project is highly welcome. For this project the same rules as for the AngleSharp core project may be applied. diff --git a/src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj b/src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj index e48c8dde..0891ee5c 100644 --- a/src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj +++ b/src/AngleSharp.Performance.Css/AngleSharp.Performance.Css.csproj @@ -1,14 +1,8 @@ - net10.0 - + net472;net10.0 Exe - - false - default - - - AnyCPU + 9 @@ -18,16 +12,18 @@ - - netstandard2.0 - - + + + + + + - \ No newline at end of file + diff --git a/src/AngleSharp.Performance.Css/AngleSharpParser.cs b/src/AngleSharp.Performance.Css/AngleSharpParser.cs deleted file mode 100644 index b1b30ded..00000000 --- a/src/AngleSharp.Performance.Css/AngleSharpParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace AngleSharp.Performance.Css -{ - using AngleSharp; - using AngleSharp.Css.Parser; - using System; - - class AngleSharpParser : ITestee - { - private static readonly CssParserOptions options = new CssParserOptions - { - IsIncludingUnknownDeclarations = true, - IsIncludingUnknownRules = true, - IsToleratingInvalidSelectors = true, - }; - private static readonly CssParser parser = new CssParser(options); - - public String Name => "AngleSharp"; - - public Type Library => typeof(BrowsingContext); - - public void Run(String source) - { - parser.ParseStyleSheet(source); - } - } -} diff --git a/src/AngleSharp.Performance.Css/CsCssParser.cs b/src/AngleSharp.Performance.Css/CsCssParser.cs deleted file mode 100644 index 915051e0..00000000 --- a/src/AngleSharp.Performance.Css/CsCssParser.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace AngleSharp.Performance.Css -{ - using Alba.CsCss.Style; - using System; - - class CsCssParser : ITestee - { - public String Name => "CsCss"; - - public Type Library => typeof(CssLoader); - - public void Run(String source) - { - var parser = new CssLoader { Compatibility = Alba.CsCss.BrowserCompatibility.FullStandards }; - - try - { - parser.ParseSheet(source, new Uri("http://localhost/foo.css"), new Uri("http://localhost")); - } - catch - { - // May crash otherwise if invalid input detected ... - } - } - } -} diff --git a/src/AngleSharp.Performance.Css/CssParserBenchmarks.cs b/src/AngleSharp.Performance.Css/CssParserBenchmarks.cs new file mode 100644 index 00000000..771cb0a4 --- /dev/null +++ b/src/AngleSharp.Performance.Css/CssParserBenchmarks.cs @@ -0,0 +1,77 @@ +namespace AngleSharp.Performance.Css +{ + using AngleSharp.Css.Parser; + using BenchmarkDotNet.Attributes; + using ExCSS; + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + + [MemoryDiagnoser] + public class CssParserBenchmarks + { + private static readonly CssParserOptions AngleSharpOptions = new CssParserOptions + { + IsIncludingUnknownDeclarations = true, + IsIncludingUnknownRules = true, + IsToleratingInvalidSelectors = true, + }; + + private static readonly CssParser AngleSharpParser = new CssParser(AngleSharpOptions); + + private string _source = null!; + + [ParamsSource(nameof(CssFileNames))] + public string CssFileName { get; set; } = null!; + + public static IEnumerable CssFileNames() + { + var dir = Path.Combine(AppContext.BaseDirectory, "Samples"); + + return Directory.GetFiles(dir, "*.css") + .OrderBy(f => f) + .Select(f => Path.GetFileNameWithoutExtension(f)); + } + + [GlobalSetup] + public void Setup() + { + var path = Path.Combine(AppContext.BaseDirectory, "Samples", CssFileName + ".css"); + _source = File.ReadAllText(path); + } + + [Benchmark(Baseline = true)] + public object AngleSharp() + { + return AngleSharpParser.ParseStyleSheet(_source); + } + + [Benchmark] + public object ExCss() + { + var parser = new StylesheetParser(); + return parser.Parse(_source); + } + +#if NET472 + [Benchmark] + public object CsCss() + { + var parser = new Alba.CsCss.Style.CssLoader + { + Compatibility = Alba.CsCss.BrowserCompatibility.FullStandards + }; + + try + { + return parser.ParseSheet(_source, new Uri("http://localhost/foo.css"), new Uri("http://localhost")); + } + catch + { + return null!; + } + } +#endif + } +} diff --git a/src/AngleSharp.Performance.Css/ExCssParser.cs b/src/AngleSharp.Performance.Css/ExCssParser.cs deleted file mode 100644 index e389aa8c..00000000 --- a/src/AngleSharp.Performance.Css/ExCssParser.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace AngleSharp.Performance.Css -{ - using System; - using ExCSS; - - class ExCssParser : ITestee - { - public String Name => "ExCSS"; - - public Type Library => typeof(Parser); - - public void Run(String source) - { - var parser = new Parser(); - parser.Parse(source); - } - } -} diff --git a/src/AngleSharp.Performance.Css/Program.cs b/src/AngleSharp.Performance.Css/Program.cs index 27571603..7dde577c 100644 --- a/src/AngleSharp.Performance.Css/Program.cs +++ b/src/AngleSharp.Performance.Css/Program.cs @@ -1,31 +1,12 @@ namespace AngleSharp.Performance.Css { - using System; - using System.Collections.Generic; - using System.IO; + using BenchmarkDotNet.Running; class Program { - static void Main(String[] args) + static void Main(string[] args) { - var samplesDir = Path.Combine(AppContext.BaseDirectory, "Samples"); - var stylesheets = new FileTests() - .IncludeFromDirectory(samplesDir); - - var parsers = new List - { - new AngleSharpParser(), - new ExCssParser(), - new CsCssParser(), - }; - - var testsuite = new TestSuite(parsers, stylesheets.Tests, new Output(), new Warmup()) - { - NumberOfRepeats = 5, - NumberOfReRuns = 1, - }; - - testsuite.Run(); + BenchmarkRunner.Run(args: args); } } }