File: Http2\HPackDecoderBenchmark.cs
Web Access
Project: src\src\Servers\Kestrel\perf\Microbenchmarks\Microsoft.AspNetCore.Server.Kestrel.Microbenchmarks.csproj (Microsoft.AspNetCore.Server.Kestrel.Microbenchmarks)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Net.Http;
using System.Net.Http.HPack;
using System.Text;
using BenchmarkDotNet.Attributes;
 
namespace Microsoft.AspNetCore.Server.Kestrel.Microbenchmarks;
 
public class HPackDecoderBenchmark
{
    // Indexed Header Field Representation - Dynamic Table - Index 62 (first index in dynamic table)
    private static readonly byte[] _indexedHeaderDynamic = new byte[] { 0xbe };
 
    private static readonly byte[] _literalHeaderFieldWithoutIndexingNewName = new byte[] { 0x00 };
 
    private const string _headerNameString = "new-header";
 
    private static readonly byte[] _headerNameBytes = Encoding.ASCII.GetBytes(_headerNameString);
 
    private static readonly byte[] _headerName = new byte[] { (byte)_headerNameBytes.Length }
        .Concat(_headerNameBytes)
        .ToArray();
 
    private const string _headerValueString = "value";
 
    private static readonly byte[] _headerValueBytes = Encoding.ASCII.GetBytes(_headerValueString);
 
    private static readonly byte[] _headerValue = new byte[] { (byte)_headerValueBytes.Length }
        .Concat(_headerValueBytes)
        .ToArray();
 
    private static readonly byte[] _literalHeaderFieldNeverIndexed_NewName = _literalHeaderFieldWithoutIndexingNewName
            .Concat(_headerName)
            .Concat(_headerValue)
            .ToArray();
 
    private static readonly byte[] _literalHeaderFieldNeverIndexed_NewName_Large;
    private static readonly byte[] _literalHeaderFieldNeverIndexed_NewName_Multiple;
    private static readonly byte[] _indexedHeaderDynamic_Multiple;
 
    static HPackDecoderBenchmark()
    {
        string string8193 = new string('a', 8193);
 
        _literalHeaderFieldNeverIndexed_NewName_Large = _literalHeaderFieldWithoutIndexingNewName
            .Concat(new byte[] { 0x7f, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix, no Huffman encoding
            .Concat(Encoding.ASCII.GetBytes(string8193))
            .Concat(new byte[] { 0x7f, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix, no Huffman encoding
            .Concat(Encoding.ASCII.GetBytes(string8193))
            .ToArray();
 
        _literalHeaderFieldNeverIndexed_NewName_Multiple = _literalHeaderFieldNeverIndexed_NewName
            .Concat(_literalHeaderFieldNeverIndexed_NewName)
            .Concat(_literalHeaderFieldNeverIndexed_NewName)
            .Concat(_literalHeaderFieldNeverIndexed_NewName)
            .Concat(_literalHeaderFieldNeverIndexed_NewName)
            .ToArray();
 
        _indexedHeaderDynamic_Multiple = _indexedHeaderDynamic
            .Concat(_indexedHeaderDynamic)
            .Concat(_indexedHeaderDynamic)
            .Concat(_indexedHeaderDynamic)
            .Concat(_indexedHeaderDynamic)
            .ToArray();
    }
 
    private HPackDecoder _decoder;
    private TestHeadersHandler _testHeadersHandler;
    private DynamicTable _dynamicTable;
 
    [GlobalSetup]
    public void GlobalSetup()
    {
        _dynamicTable = new DynamicTable(maxSize: 4096);
        _dynamicTable.Insert(_headerNameBytes, _headerValueBytes);
        _decoder = new HPackDecoder(maxDynamicTableSize: 4096, maxHeadersLength: 65536, _dynamicTable);
        _testHeadersHandler = new TestHeadersHandler();
    }
 
    [Benchmark]
    public void DecodesLiteralHeaderFieldNeverIndexed_NewName()
    {
        _decoder.Decode(_literalHeaderFieldNeverIndexed_NewName, endHeaders: true, handler: _testHeadersHandler);
    }
 
    [Benchmark]
    public void DecodesLiteralHeaderFieldNeverIndexed_NewName_Large()
    {
        _decoder.Decode(_literalHeaderFieldNeverIndexed_NewName_Large, endHeaders: true, handler: _testHeadersHandler);
    }
 
    [Benchmark]
    public void DecodesLiteralHeaderFieldNeverIndexed_NewName_Multiple()
    {
        _decoder.Decode(_literalHeaderFieldNeverIndexed_NewName_Multiple, endHeaders: true, handler: _testHeadersHandler);
    }
 
    [Benchmark]
    public void DecodesIndexedHeaderField_DynamicTable()
    {
        _decoder.Decode(_indexedHeaderDynamic, endHeaders: true, handler: _testHeadersHandler);
    }
 
    [Benchmark]
    public void DecodesIndexedHeaderField_DynamicTable_Multiple()
    {
        _decoder.Decode(_indexedHeaderDynamic_Multiple, endHeaders: true, handler: _testHeadersHandler);
    }
 
    private sealed class TestHeadersHandler : IHttpStreamHeadersHandler
    {
        public void OnDynamicIndexedHeader(int? index, ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
        {
        }
 
        public void OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
        {
        }
 
        public void OnHeadersComplete(bool endStream)
        {
        }
 
        public void OnStaticIndexedHeader(int index)
        {
        }
 
        public void OnStaticIndexedHeader(int index, ReadOnlySpan<byte> value)
        {
        }
    }
}