aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

Support STJ Polymorphism

Open brunolins16 opened this issue 2 years ago • 5 comments

Overview

Contributes to #44852

This PR change RDF and JsonOutputFormatter to, when a JsonPolymorphismOptions is detected, uses the declared type's JsonTypeInfo to call the serializer.

⚠️ I will create a follow up PR to add STJ Polymorphism support for Http Results. ⚠️ AOT/Linker-friendly support is not cover in this PR

Benchmark results

MapXXX

Summary:

  • Similar or slight better RPS
  • ~ 6% less Total Allocated bytes (when using JsonTypeInfo)
  • JsonDerived faster than runtime type usage.
Fast path

Sample

app.MapGet("/json", () => new { Text = "teste" });

Results

application main PR
CPU Usage (%) 83 83 0.00%
Cores usage (%) 998 997 -0.10%
Working Set (MB) 193 195 +1.04%
Private Memory (MB) 577 595 +3.12%
Start Time (ms) 89 88 -1.12%
Max CPU Usage (%) 83 83 +0.35%
Max Working Set (MB) 202 204 +0.56%
Max GC Heap Size (MB) 96 94 -1.72%
Size of committed memory by the GC (MB) 127 128 +1.18%
Max Number of Gen 0 GCs / sec 2.00 2.00 0.00%
Max Number of Gen 1 GCs / sec 1.00 1.00 0.00%
Max Number of Gen 2 GCs / sec 1.00 1.00 0.00%
Max Time in GC (%) 1.00 0.00
Max Gen 0 Size (B) 584 584 0.00%
Max Gen 1 Size (B) 3,661,672 3,715,352 +1.47%
Max Gen 2 Size (B) 3,667,440 3,729,760 +1.70%
Max LOH Size (B) 321,472 321,472 0.00%
Max POH Size (B) 1,186,016 1,363,176 +14.94%
Total Allocated Bytes 4,411,891,376 4,116,792,736 -6.69%
Max GC Heap Fragmentation 4 4 -4.43%
# of Assemblies Loaded 86 86 0.00%
Max Exceptions (#/s) 298 352 +18.12%
Max Lock Contention (#/s) 26 27 +3.85%
Max ThreadPool Threads Count 23 25 +8.70%
Max ThreadPool Queue Length 152 233 +53.29%
Max ThreadPool Items (#/s) 767,649 772,454 +0.63%
Max Active Timers 1 1 0.00%
IL Jitted (B) 222,856 223,357 +0.22%
Methods Jitted 2,344 2,346 +0.09%
load main PR
CPU Usage (%) 91 91 0.00%
Cores usage (%) 1,097 1,096 -0.09%
Working Set (MB) 119 130 +9.24%
Private Memory (MB) 358 358 0.00%
Start Time (ms) 0 0
First Request (ms) 141 137 -2.84%
Requests/sec 583,933 583,921 -0.00%
Requests 8,814,217 8,815,645 +0.02%
Mean latency (ms) 0.42 0.42 -0.19%
Max latency (ms) 14.94 15.20 +1.74%
Bad responses 0 0
Socket errors 0 0
Read throughput (MB/s) 114.72 114.72 0.00%
Latency 50th (ms) 0.37 0.37 0.00%
Latency 75th (ms) 0.48 0.48 0.00%
Latency 90th (ms) 0.65 0.65 +0.15%
Latency 99th (ms) 1.46 1.46 0.00%
Runtime type check + TypeInfo serializer

Sample

app.MapGet("/json", () => new Message { Text = "teste" });

class Message : BaseMessage { }

class BaseMessage
{
    public string Text { get; set; }
}

Results

application main PR
CPU Usage (%) 83 84 +1.20%
Cores usage (%) 998 1,008 +1.00%
Working Set (MB) 193 195 +1.04%
Private Memory (MB) 585 579 -1.03%
Start Time (ms) 88 88 0.00%
Max CPU Usage (%) 83 84 +0.65%
Max Working Set (MB) 205 204 -0.56%
Max GC Heap Size (MB) 95 94 -0.25%
Size of committed memory by the GC (MB) 130 131 +1.33%
Max Number of Gen 0 GCs / sec 2.00 2.00 0.00%
Max Number of Gen 1 GCs / sec 1.00 1.00 0.00%
Max Number of Gen 2 GCs / sec 1.00 1.00 0.00%
Max Time in GC (%) 0.00 0.00
Max Gen 0 Size (B) 26,712 584 -97.81%
Max Gen 1 Size (B) 3,450,208 3,651,432 +5.83%
Max Gen 2 Size (B) 3,744,864 3,623,080 -3.25%
Max LOH Size (B) 321,472 321,472 0.00%
Max POH Size (B) 1,186,016 1,186,016 0.00%
Total Allocated Bytes 4,398,211,880 4,126,395,960 -6.18%
Max GC Heap Fragmentation 4 4 +1.91%
# of Assemblies Loaded 86 86 0.00%
Max Exceptions (#/s) 348 372 +6.90%
Max Lock Contention (#/s) 22 31 +40.91%
Max ThreadPool Threads Count 24 23 -4.17%
Max ThreadPool Queue Length 181 174 -3.87%
Max ThreadPool Items (#/s) 770,007 784,509 +1.88%
Max Active Timers 1 1 0.00%
IL Jitted (B) 222,571 223,284 +0.32%
Methods Jitted 2,348 2,349 +0.04%
load main PR
CPU Usage (%) 91 92 +1.10%
Cores usage (%) 1,097 1,102 +0.46%
Working Set (MB) 120 119 -0.83%
Private Memory (MB) 358 358 0.00%
Start Time (ms) 0 0
First Request (ms) 138 144 +4.35%
Requests/sec 583,081 584,599 +0.26%
Requests 8,804,383 8,826,007 +0.25%
Mean latency (ms) 0.42 0.42 +0.66%
Max latency (ms) 13.72 14.22 +3.64%
Bad responses 0 0
Socket errors 0 0
Read throughput (MB/s) 114.55 114.85 +0.26%
Latency 50th (ms) 0.37 0.37 -0.81%
Latency 75th (ms) 0.48 0.48 +0.21%
Latency 90th (ms) 0.64 0.66 +2.34%
Latency 99th (ms) 1.41 1.42 +0.71%
Polymorphic

Sample

app.MapGet("/json", BaseMessage () => new Message { Text = "teste" });

class Message : BaseMessage { }

[JsonDerivedType(typeof(Message))]
class BaseMessage
{
    public string Text { get; set; }
}

Results

application main PR
CPU Usage (%) 84 84 0.00%
Cores usage (%) 1,003 1,003 0.00%
Working Set (MB) 193 196 +1.55%
Private Memory (MB) 576 588 +2.08%
Start Time (ms) 89 88 -1.12%
Max CPU Usage (%) 83 84 +0.85%
Max Working Set (MB) 201 205 +2.22%
Max GC Heap Size (MB) 96 93 -2.86%
Size of committed memory by the GC (MB) 128 134 +4.79%
Max Number of Gen 0 GCs / sec 2.00 2.00 0.00%
Max Number of Gen 1 GCs / sec 1.00 1.00 0.00%
Max Number of Gen 2 GCs / sec 1.00 1.00 0.00%
Max Time in GC (%) 0.00 0.00
Max Gen 0 Size (B) 584 584 0.00%
Max Gen 1 Size (B) 3,572,664 3,662,304 +2.51%
Max Gen 2 Size (B) 3,660,960 3,667,616 +0.18%
Max LOH Size (B) 321,472 321,472 0.00%
Max POH Size (B) 1,186,016 1,186,016 0.00%
Total Allocated Bytes 4,381,664,640 4,132,810,160 -5.68%
Max GC Heap Fragmentation 4 4 +0.31%
# of Assemblies Loaded 86 86 0.00%
Max Exceptions (#/s) 275 314 +14.18%
Max Lock Contention (#/s) 24 24 0.00%
Max ThreadPool Threads Count 23 24 +4.35%
Max ThreadPool Queue Length 113 254 +124.78%
Max ThreadPool Items (#/s) 782,049 786,959 +0.63%
Max Active Timers 1 1 0.00%
IL Jitted (B) 222,943 223,189 +0.11%
Methods Jitted 2,350 2,347 -0.13%
load main PR
CPU Usage (%) 92 92 0.00%
Cores usage (%) 1,103 1,099 -0.36%
Working Set (MB) 120 119 -0.83%
Private Memory (MB) 358 358 0.00%
Start Time (ms) 0 0
First Request (ms) 137 144 +5.11%
Requests/sec 583,935 585,208 +0.22%
Requests 8,817,410 8,836,006 +0.21%
Mean latency (ms) 0.42 0.42 +1.02%
Max latency (ms) 13.96 14.25 +2.08%
Bad responses 0 0
Socket errors 0 0
Read throughput (MB/s) 114.72 114.97 +0.22%
Latency 50th (ms) 0.36 0.36 -0.27%
Latency 75th (ms) 0.49 0.49 0.00%
Latency 90th (ms) 0.66 0.67 +0.45%
Latency 99th (ms) 1.40 1.45 +3.57%

Controllers

Summary:

  • Improvements depends on untyped JsonTypeInfo new apis
  • Additional call to GetTypeInfo will happen.
Controllers

Sample

public BaseMessage Json()
{
    return new Message { Text = "Hello, World!" };
}

public class BaseMessage { public string Text { get; set; } }
public class Message : BaseMessage {}

Results

application main PR
CPU Usage (%) 95 93 -2.11%
Cores usage (%) 1,137 1,118 -1.67%
Working Set (MB) 178 173 -2.81%
Private Memory (MB) 166 163 -1.81%
Start Time (ms) 224 228 +1.79%
Max CPU Usage (%) 99 96 -3.63%
Max Working Set (MB) 188 181 -3.86%
Max GC Heap Size (MB) 101 95 -6.32%
Size of committed memory by the GC (MB) 122 115 -5.52%
Max Number of Gen 0 GCs / sec 9.00 9.00 0.00%
Max Number of Gen 1 GCs / sec 7.00 2.00 -71.43%
Max Number of Gen 2 GCs / sec 1.00 1.00 0.00%
Max Time in GC (%) 1.00 1.00 0.00%
Max Gen 0 Size (B) 3,422,168 3,605,624 +5.36%
Max Gen 1 Size (B) 6,647,576 6,570,280 -1.16%
Max Gen 2 Size (B) 4,542,904 5,088,000 +12.00%
Max LOH Size (B) 424,440 424,440 0.00%
Max POH Size (B) 1,251,320 1,251,320 0.00%
Total Allocated Bytes 19,079,922,016 19,006,488,720 -0.38%
Max GC Heap Fragmentation 46 44 -4.13%
# of Assemblies Loaded 111 111 0.00%
Max Exceptions (#/s) 403 370 -8.19%
Max Lock Contention (#/s) 19 9 -52.63%
Max ThreadPool Threads Count 23 23 0.00%
Max ThreadPool Queue Length 204 205 +0.49%
Max ThreadPool Items (#/s) 641,942 631,171 -1.68%
Max Active Timers 0 0
IL Jitted (B) 268,073 267,888 -0.07%
Methods Jitted 3,389 3,387 -0.06%
load main PR
CPU Usage (%) 50 50 0.00%
Cores usage (%) 600 597 -0.50%
Working Set (MB) 119 119 0.00%
Private Memory (MB) 358 358 0.00%
Start Time (ms) 0 0
First Request (ms) 141 141 0.00%
Requests/sec 239,383 237,996 -0.58%
Requests 3,614,549 3,593,534 -0.58%
Mean latency (ms) 1.47 1.43 -2.72%
Max latency (ms) 185.26 195.49 +5.52%
Bad responses 0 0
Socket errors 0 0
Read throughput (MB/s) 41.78 41.54 -0.57%
Latency 50th (ms) 1.02 1.03 +0.98%
Latency 75th (ms) 1.07 1.08 +0.93%
Latency 90th (ms) 1.14 1.14 0.00%
Latency 99th (ms) 14.45 6.97 -51.76%

brunolins16 avatar Dec 01 '22 21:12 brunolins16

/benchmark

brunolins16 avatar Dec 01 '22 22:12 brunolins16

Crank Pull Request Bot

/benchmark <benchmark[,...]> <profile[,...]> <component,[...]> <arguments>

Benchmarks:

  • plaintext: TechEmpower Plaintext Scenario - ASP.NET Platform implementation
  • json: TechEmpower JSON Scenario - ASP.NET Platform implementation
  • fortunes: TechEmpower Fortunes Scenario - ASP.NET Platform implementation
  • yarp: YARP - http-http with 10 bytes
  • mvcjsoninput2k: Sends 2Kb Json Body to an MVC controller

Profiles:

  • aspnet-perf-lin: INTEL/Linux 12 Cores
  • aspnet-perf-win: INTEL/Windows 12 Cores
  • aspnet-citrine-lin: INTEL/Linux 28 Cores
  • aspnet-citrine-win: INTEL/Windows 28 Cores
  • aspnet-citrine-arm: ARM/Linux 32 Cores
  • aspnet-citrine-amd: AMD/Linux 48 Cores

Components:

  • kestrel
  • mvc

Arguments: any additional arguments to pass through to crank, e.g. --variable name=value

pr-benchmarks[bot] avatar Dec 01 '22 22:12 pr-benchmarks[bot]

/benchmark json aspnet-perf-win mvc

brunolins16 avatar Dec 01 '22 22:12 brunolins16

Benchmark started for json on aspnet-perf-win with mvc. Logs: link

pr-benchmarks[bot] avatar Dec 01 '22 22:12 pr-benchmarks[bot]

json - aspnet-perf-win

application json.base json.pr
CPU Usage (%) 77 77 0.00%
Cores usage (%) 928 928 0.00%
Working Set (MB) 70 71 +1.43%
Private Memory (MB) 65 66 +1.54%
Build Time (ms) 1,882 3,660 +94.47%
Start Time (ms) 148 133 -10.14%
Published Size (KB) 96,997 96,997 0.00%
.NET Core SDK Version 8.0.100-alpha.1.22601.15 8.0.100-alpha.1.22601.15
load json.base json.pr
CPU Usage (%) 100 100 0.00%
Cores usage (%) 1,198 1,199 +0.08%
Working Set (MB) 119 119 0.00%
Private Memory (MB) 363 363 0.00%
Start Time (ms) 1 0
First Request (ms) 67 68 +1.49%
Requests/sec 680,412 666,439 -2.05%
Requests 10,272,871 10,060,915 -2.06%
Mean latency (ms) 1.33 1.73 +30.08%
Max latency (ms) 36.49 81.64 +123.73%
Bad responses 0 0
Socket errors 0 0
Read throughput (MB/s) 94.74 92.79 -2.06%
Latency 50th (ms) 0.34 0.32 -5.65%
Latency 75th (ms) 1.55 1.91 +23.23%
Latency 90th (ms) 3.77 5.14 +36.34%
Latency 99th (ms) 10.01 14.46 +44.46%

pr-benchmarks[bot] avatar Dec 01 '22 22:12 pr-benchmarks[bot]

Are we calling a new API that isn't public? The source generator needs to copy this pattern as well.

cc @captainsafia

davidfowl avatar Jan 07 '23 05:01 davidfowl

Are we calling a new API that isn't public? The source generator needs to copy this pattern as well.

cc @captainsafia

I just merged #45593 that makes the APIs public.

brunolins16 avatar Jan 09 '23 17:01 brunolins16

@eiriktsarpalis I believe I covered almost all the feedback. Do you have any additional concern before I merge it?

brunolins16 avatar Jan 09 '23 21:01 brunolins16