-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use instance methods for SerializeHandler in source gen #61448
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json Issue DetailsS.T.Json source generator generates Invoking delegate to a static method is slower than invoking a delegate to an instance methods in .NET. Invocation of delegates to instance methods have comparable perf characteristics to a virtual call. Invocation of delegate to static methods goes through a shuffle thunk that deals with calling convention incompatibilities at the callsite (that assumes instance method) vs target (static method). I ran the source generator, captured the outputs in *.cs files and changed this method: private static void JsonMessage2SerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::JsonMessage2 value)
{
writer.WriteStartObject();
writer.WriteString(PropName_message, value.message);
writer.WriteEndObject();
} To not be static but be instance instead. Here's the difference when serializing a simple struct with a string field (the scenario used in TechEmpower benchmarks): BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1348 (21H1/May2021Update)
Intel Core i7-4870HQ CPU 2.50GHz (Haswell), 1 CPU, 8 logical and 4 physical cores
.NET SDK=6.0.100-rc.2.21505.57
[Host] : .NET 6.0.0 (6.0.21.48005), X64 RyuJIT
.NET 6.0 : .NET 6.0.0 (6.0.21.48005), X64 RyuJIT
Job=.NET 6.0 Runtime=.NET 6.0
I think the change needs to be done here, but I don't know how to test the source generators to ensure it's generating what I think it's generating, so I'm just filing an issue. runtime/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs Lines 1046 to 1050 in 784687f
|
It seems like a doable refactoring, I'd initially assumed that the Would it be possible to share your full benchmark code? The performance gains don't seem particularly impressive for what appears to be a very small POCO, so I don't know if performance gains provide sufficient motivation for us to go ahead with this refactoring. Note that delegate invocation is only used for the root-level object, the generated fast-path serialization methods generally compose using regular method calls: private static void FooSerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::Foo? value)
{
if (value == null)
{
writer.WriteNullValue();
return;
}
writer.WriteStartObject();
writer.WritePropertyName(PropName_Bar);
BarSerializeHandler(writer, value.Bar!);
writer.WriteEndObject();
} cc @layomia |
Here's the benchmark: BdnJson.zip. The only difference between JsonMessage1 and JsonMessage2 is that one of them has an instance method as the handler.
FWIW, the POCO in use is the same one that is in use in TechEmpower benchmarks and we tend to be interested in the perf of those. |
For completeness I'd like to first add a new variant of the |
For additional background on shuffle thunk see #45232 (comment) I believe for every additional parameter over the count of 1 there will be a slight improvement. |
S.T.Json source generator generates
static void *SerializeHandler(...)
methods that perform serialization. These are invoked through a theSerializeHandler
delegate onJsonObjectInfoValues<T>
.Invoking delegate to a static method is slower than invoking a delegate to an instance methods in .NET. Invocation of delegates to instance methods have comparable perf characteristics to a virtual call. Invocation of delegate to static methods goes through a shuffle thunk that deals with calling convention incompatibilities at the callsite (that assumes instance method) vs target (static method).
I ran the source generator, captured the outputs in *.cs files and changed this method:
To not be static but be instance instead. Here's the difference when serializing a simple struct with a string field (the scenario used in TechEmpower benchmarks):
I think the change needs to be done here, but I don't know how to test the source generators to ensure it's generating what I think it's generating, so I'm just filing an issue.
runtime/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
Lines 1046 to 1050 in 784687f
The text was updated successfully, but these errors were encountered: