dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.6k stars 10.06k forks source link

perf: default registered DataProtection works slower on linux compared to windows #59287

Open DeagleGross opened 1 day ago

DeagleGross commented 1 day ago

I ran the sample benchmark, where I get the DataProtector via IServiceProvider and ran multiple Protect() and Unprotect() on sample string:

// getting the data protector
var services = new ServiceCollection()
    .AddDataProtection()
    .Services.BuildServiceProvider();
_dataProtector = services.GetDataProtector("SamplePurpose");

// running the protect/unprotect
for (var i = 0; i < 1000; i++)
{
    _ = _dataProtector.Protect(LoremIpsumData);
}

The results are showing a big difference on windows against linux machines (results below). I was launching benchmarks using crank config and perf machines. I.e. crank --config https://raw.githubusercontent.com/DeagleGross/Baraholka/refs/heads/main/Benchmarks/Benchmarks/crank/data-protector.yml --scenario dataprotector --profile aspnet-perf-lin --application.framework net10.0

Frameworks infra:

Machine:

BenchmarkDotNet v0.14.0, Windows 10 (10.0.20348.2461) Intel Xeon E-2336 CPU 2.90GHz, 1 CPU, 12 logical and 6 physical cores .NET SDK 5.0.404 [C:\Program Files\dotnet\sdk] [Host] : .NET 10.0.0 (10.0.24.57009), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

Benchmark run:

Toolchain=InProcessEmitToolchain MaxIterationCount=12 MinIterationCount=9 WarmupCount=1

Linux:

crank --config https://raw.githubusercontent.com/DeagleGross/Baraholka/refs/heads/main/Benchmarks/Benchmarks/crank/data-protector.yml --scenario dataprotector --profile aspnet-perf-lin --application.framework net10.0

Method Mean Error StdDev Gen0 Allocated
Protect 11.19 ms 0.027 ms 0.014 ms 156.2500 4.85 MB
Unprotect 10.03 ms 0.026 ms 0.015 ms 125.0000 3.64 MB

Windows:

crank --config https://raw.githubusercontent.com/DeagleGross/Baraholka/refs/heads/main/Benchmarks/Benchmarks/crank/data-protector.yml --scenario dataprotector --profile aspnet-perf-win --application.framework net10.0

Method Mean Error StdDev Gen0 Gen1 Gen2 Allocated
Protect 3.284 ms 0.0035 ms 0.0021 ms 66.4063 3.9063 3.9063 -
Unprotect 3.273 ms 0.0109 ms 0.0057 ms 74.2188 3.9063 3.9063 -
sebastienros commented 1 day ago

I would suggest some changes on the benchmark.

sebastienros commented 1 day ago

Also, to prevent dead code elimination, return the encrypted/decrypted value instead of void.

DeagleGross commented 1 day ago

thanks for the suggestions, @sebastienros ! I changed the benchmark, here are new results:

BenchmarkDotNet v0.14.0, Debian GNU/Linux 12 (bookworm) (container) Intel Xeon E-2336 CPU 2.90GHz, 1 CPU, 12 logical and 6 physical cores .NET SDK 8.0.404 [/usr/share/dotnet/sdk] [Host] : .NET 10.0.0 (10.0.24.57009), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI

Toolchain=InProcessEmitToolchain WarmupCount=5

Linux:

Method Mean Error StdDev Gen0 Allocated
Protect 10.792 µs 0.0149 µs 0.0139 µs 0.1221 3.91 KB
Unprotect 9.882 µs 0.0139 µs 0.0116 µs 0.1068 3.34 KB

Windows:

Method Mean Error StdDev Gen0 Allocated
Protect 3.125 µs 0.0027 µs 0.0024 µs 0.0381 1.19 KB
Unprotect 3.145 µs 0.0036 µs 0.0033 µs 0.0343 1.03 KB
DeagleGross commented 1 day ago

Here are the traces for the first run (unchanged benchmark code) traces-with-allocs.zip