-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Investigate writing large string values in 4 KB chunks within Utf8JsonWriter instead all at once #29293
Comments
I've had a crack at this with the following benchmarks: using System;
using System.Buffers;
using System.IO;
using System.Text;
using System.Text.Json2;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
namespace Utf8JsonWriter4KChunking
{
[MemoryDiagnoser]
public class Benchmarks
{
private char[] _string;
[Params(100, 1_000, 2_000, 4_000, 8_000, 16_000)]
public int N;
[GlobalSetup]
public void Setup()
{
_string = GetString(N);
}
public static char[] GetString(int length)
{
var sb = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
sb.Append("A");
}
return sb.ToString().ToCharArray();
}
[Benchmark]
public void WriteStringMinimized()
{
using (var writer = new Utf8JsonWriter(new ArrayBufferWriter<byte>()))
{
writer.WriteStringMinimized(_string.AsSpan());
}
}
[Benchmark]
public void WriteStringMinimizedChunked()
{
using (var writer = new Utf8JsonWriter(new ArrayBufferWriter<byte>()))
{
writer.WriteStringMinimizedChunked(_string.AsSpan());
}
}
}
} which produces:
|
I realised there was already a benchmark for this in dotnet/performance, so I have gone ahead and run the changes against that: BenchmarkDotNet=v0.12.1, OS=macOS Mojave 10.14.6 (18G2022) [Darwin 18.7.0]
Intel Core i5-6360U CPU 2.00GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
.NET Core SDK=5.0.100-preview.4.20214.21
[Host] : .NET Core 5.0.0 (CoreCLR 5.0.20.21403, CoreFX 5.0.20.21403), X64 RyuJIT
Job-JUSUMR : .NET Core 5.0 (CoreCLR 42.42.42.42424, CoreFX 42.42.42.42424), X64 RyuJIT
Job-FYQBCX : .NET Core 5.0 (CoreCLR 42.42.42.42424, CoreFX 42.42.42.42424), X64 RyuJIT
PowerPlanMode=00000000-0000-0000-0000-000000000000 Arguments=/p:DebugType=portable IterationTime=250.0000 ms
MaxIterationCount=20 MinIterationCount=15 WarmupCount=1
|
Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process. This process is part of the experimental issue cleanup initiative we are currently trialing in a limited number of areas. Please share any feedback you might have in the linked issue. |
This issue will now be closed since it had been marked |
Regardless of the mode (IBufferWriter or stream), consider writing JSON string values (whether UTF-16 or UTF-8) in chunks of fixed size (for example
4_096
). Currently, the writer pessimistically asks for as much space as could be required in the worst case, and tries to write the whole string in one shot. It would reduce allocation/GC pressure if we wrote in smaller chunks.For the stream mode, we should also consider putting a size cap ~ 64k to avoid the LOH.
Note: This only applies to JSON string values. Property names and other tokens (like numbers, literals, datetime/etc.) all tend to generally be small enough to not benefit from this optimization.
For example, something like the following, where we enter the "slow/loop" path for strings larger than 4K:
See related PR: dotnet/corefx#36961
The text was updated successfully, but these errors were encountered: