Skip to content

Performance regression when deserializing compressed binary XML streams using data contract serializers #75437

@dev991301

Description

@dev991301

Description

When compared to .NET Framework 4.8, the output from BenchmarkDotNet shows execution time has greatly increased in .NET6/7 when deserializing from compressed binary XML streams using data contract serializers for large collections of objects (>1000). For example, using my configuration, deserializing 10,000 objects is around 200 times slower in .NET6/7 when compared to .NET Framework 4.8.

Data Contract Code
[DataContract(IsReference = true)]
public class Person
{
    [DataMember]
    public Person Parent { get; set; }
    
    [DataMember]
    public List<Person> Children { get; set; }
}
Benchmark Code
[SimpleJob(RuntimeMoniker.Net48, baseline: true)]
[SimpleJob(RuntimeMoniker.Net60)]
[SimpleJob(RuntimeMoniker.Net70)]
public class Benchmark
{
    [Params(10, 100, 1000, 10000)]
    public int N { get; set; }

    private byte[] _serialized;
    private readonly DataContractSerializer _serializer = new (typeof(Person));

    [GlobalSetup]
    public void Serialize()
    {
        var person = new Person();
        person.Children = Enumerable.Range(0, N-1).Select(_ => new Person {Parent = person}).ToList();

        using var compressed = new MemoryStream();
        using var compressor = new DeflateStream(compressed, CompressionMode.Compress);
        
        using var writer = XmlDictionaryWriter.CreateBinaryWriter(compressor);
        _serializer.WriteObject(writer, person);
        writer.Close();
        
        _serialized =  compressed.ToArray();
    }
    
    [Benchmark]
    public object Deserialize()
    {
        using var compressed = new MemoryStream(_serialized);
        using var decompressor = new DeflateStream(compressed, CompressionMode.Decompress);
        
        using var reader = XmlDictionaryReader.CreateBinaryReader(decompressor, XmlDictionaryReaderQuotas.Max);
        
        return _serializer.ReadObject(reader);
    }
}

Configuration

BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22000.856/21H2)
11th Gen Intel Core i7-11800H 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=7.0.100-preview.7.22377.5
  [Host]             : .NET 7.0.0 (7.0.22.37506), X64 RyuJIT AVX2
  .NET 6.0           : .NET 6.0.8 (6.0.822.36306), X64 RyuJIT AVX2
  .NET 7.0           : .NET 7.0.0 (7.0.22.37506), X64 RyuJIT AVX2
  .NET Framework 4.8 : .NET Framework 4.8 (4.8.4510.0), X64 RyuJIT VectorSize=256

Data

Method Job Runtime N Mean Error StdDev Ratio RatioSD
Deserialize .NET 6.0 .NET 6.0 10 29.06us 0.256us 0.227us 0.82 0.01
Deserialize .NET 7.0 .NET 7.0 10 28.99us 0.318us 0.297us 0.82 0.01
Deserialize .NET Framework 4.8 .NET Framework 4.8 10 35.42us 0.253us 0.211us 1.00 0.00
Deserialize .NET 6.0 .NET 6.0 100 323.17us 2.265us 2.008us 1.19 0.01
Deserialize .NET 7.0 .NET 7.0 100 319.55us 2.648us 2.348us 1.17 0.01
Deserialize .NET Framework 4.8 .NET Framework 4.8 100 272.22us 2.486us 2.204us 1.00 0.00
Deserialize .NET 6.0 .NET 6.0 1000 310,428.48us 914.629us 810.795us 116.82 0.81
Deserialize .NET 7.0 .NET 7.0 1000 312,653.03us 2,976.487us 2,638.578us 117.73 1.04
Deserialize .NET Framework 4.8 .NET Framework 4.8 1000 2,657.57us 18.909us 15.790us 1.00 0.00
Deserialize .NET 6.0 .NET 6.0 10000 6,167,079.07us 28,492.478us 26,651.882us 214.41 2.02
Deserialize .NET 7.0 .NET 7.0 10000 6,140,992.62us 13,397.507us 11,187.525us 213.47 2.17
Deserialize .NET Framework 4.8 .NET Framework 4.8 10000 28,765.16us 293.030us 274.100us 1.00 0.00

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.IOdocumentationDocumentation bug or enhancement, does not impact product or test codeneeds-further-triageIssue has been initially triaged, but needs deeper consideration or reconsiderationtenet-performancePerformance related issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions