Update BenchmarkDotNet and add Http2Connection benchmark (#19482)
This commit is contained in:
parent
c507134320
commit
b1a45eb809
|
|
@ -220,7 +220,7 @@
|
||||||
<MicrosoftAspNetCoreAzureAppServicesSiteExtension31PackageVersion>3.1.3</MicrosoftAspNetCoreAzureAppServicesSiteExtension31PackageVersion>
|
<MicrosoftAspNetCoreAzureAppServicesSiteExtension31PackageVersion>3.1.3</MicrosoftAspNetCoreAzureAppServicesSiteExtension31PackageVersion>
|
||||||
<!-- 3rd party dependencies -->
|
<!-- 3rd party dependencies -->
|
||||||
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
|
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
|
||||||
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
|
<BenchmarkDotNetPackageVersion>0.12.0</BenchmarkDotNetPackageVersion>
|
||||||
<CastleCorePackageVersion>4.2.1</CastleCorePackageVersion>
|
<CastleCorePackageVersion>4.2.1</CastleCorePackageVersion>
|
||||||
<FSharpCorePackageVersion>4.2.1</FSharpCorePackageVersion>
|
<FSharpCorePackageVersion>4.2.1</FSharpCorePackageVersion>
|
||||||
<GoogleProtobufPackageVersion>3.8.0</GoogleProtobufPackageVersion>
|
<GoogleProtobufPackageVersion>3.8.0</GoogleProtobufPackageVersion>
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@ namespace BenchmarkDotNet.Attributes
|
||||||
|
|
||||||
Add(JitOptimizationsValidator.FailOnError);
|
Add(JitOptimizationsValidator.FailOnError);
|
||||||
|
|
||||||
Add(Job.Core
|
Add(Job.Default
|
||||||
.With(CsProjCoreToolchain.From(NetCoreAppSettings.NetCoreApp21))
|
.With(CsProjCoreToolchain.From(NetCoreAppSettings.NetCoreApp21))
|
||||||
.With(new GcMode { Server = true })
|
.With(new GcMode { Server = true })
|
||||||
.WithTargetCount(10)
|
.WithIterationCount(10)
|
||||||
.WithInvocationCount(1)
|
.WithInvocationCount(1)
|
||||||
.WithUnrollFactor(1)
|
.WithUnrollFactor(1)
|
||||||
.With(RunStrategy.ColdStart));
|
.With(RunStrategy.ColdStart));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Net.Http.HPack;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
{
|
||||||
|
public class Http2ConnectionBenchmark
|
||||||
|
{
|
||||||
|
private MemoryPool<byte> _memoryPool;
|
||||||
|
private Pipe _pipe;
|
||||||
|
private HttpRequestHeaders _httpRequestHeaders;
|
||||||
|
private Http2Connection _connection;
|
||||||
|
private Http2HeadersEnumerator _requestHeadersEnumerator;
|
||||||
|
private int _currentStreamId;
|
||||||
|
private HPackEncoder _hpackEncoder;
|
||||||
|
private byte[] _headersBuffer;
|
||||||
|
|
||||||
|
[GlobalSetup]
|
||||||
|
public void GlobalSetup()
|
||||||
|
{
|
||||||
|
_memoryPool = SlabMemoryPoolFactory.Create();
|
||||||
|
|
||||||
|
var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
|
||||||
|
_pipe = new Pipe(options);
|
||||||
|
|
||||||
|
_httpRequestHeaders = new HttpRequestHeaders();
|
||||||
|
_httpRequestHeaders.Append(HeaderNames.Method, new StringValues("GET"));
|
||||||
|
_httpRequestHeaders.Append(HeaderNames.Path, new StringValues("/"));
|
||||||
|
_httpRequestHeaders.Append(HeaderNames.Scheme, new StringValues("http"));
|
||||||
|
_httpRequestHeaders.Append(HeaderNames.Authority, new StringValues("localhost:80"));
|
||||||
|
|
||||||
|
_hpackEncoder = new HPackEncoder();
|
||||||
|
_headersBuffer = new byte[1024 * 16];
|
||||||
|
|
||||||
|
var serviceContext = new ServiceContext
|
||||||
|
{
|
||||||
|
DateHeaderValueManager = new DateHeaderValueManager(),
|
||||||
|
ServerOptions = new KestrelServerOptions(),
|
||||||
|
Log = new KestrelTrace(NullLogger.Instance),
|
||||||
|
SystemClock = new MockSystemClock()
|
||||||
|
};
|
||||||
|
serviceContext.ServerOptions.Limits.Http2.MaxStreamsPerConnection = int.MaxValue;
|
||||||
|
serviceContext.DateHeaderValueManager.OnHeartbeat(default);
|
||||||
|
|
||||||
|
_connection = new Http2Connection(new HttpConnectionContext
|
||||||
|
{
|
||||||
|
MemoryPool = _memoryPool,
|
||||||
|
ConnectionId = "TestConnectionId",
|
||||||
|
Protocols = Core.HttpProtocols.Http2,
|
||||||
|
Transport = new MockDuplexPipe(_pipe.Reader, new NullPipeWriter()),
|
||||||
|
ServiceContext = serviceContext,
|
||||||
|
ConnectionFeatures = new FeatureCollection(),
|
||||||
|
TimeoutControl = new MockTimeoutControl(),
|
||||||
|
});
|
||||||
|
|
||||||
|
_requestHeadersEnumerator = new Http2HeadersEnumerator();
|
||||||
|
|
||||||
|
_currentStreamId = 1;
|
||||||
|
|
||||||
|
_ = _connection.ProcessRequestsAsync(new DummyApplication());
|
||||||
|
|
||||||
|
_pipe.Writer.Write(Http2Connection.ClientPreface);
|
||||||
|
PipeWriterHttp2FrameExtensions.WriteSettings(_pipe.Writer, new Http2PeerSettings());
|
||||||
|
_pipe.Writer.FlushAsync().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public async Task EmptyRequest()
|
||||||
|
{
|
||||||
|
_requestHeadersEnumerator.Initialize(_httpRequestHeaders);
|
||||||
|
PipeWriterHttp2FrameExtensions.WriteStartStream(_pipe.Writer, streamId: _currentStreamId, _requestHeadersEnumerator, _hpackEncoder, _headersBuffer, endStream: true);
|
||||||
|
_currentStreamId += 2;
|
||||||
|
await _pipe.Writer.FlushAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[GlobalCleanup]
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_pipe.Writer.Complete();
|
||||||
|
_memoryPool?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="$(KestrelSharedSourceRoot)test\DummyApplication.cs" />
|
||||||
|
<Compile Include="$(KestrelSharedSourceRoot)test\PipeWriterHttp2FrameExtensions.cs" />
|
||||||
<Compile Include="$(RepoRoot)src\Shared\Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" />
|
<Compile Include="$(RepoRoot)src\Shared\Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" />
|
||||||
<Compile Include="$(KestrelSharedSourceRoot)test\TestApplicationErrorLogger.cs" />
|
<Compile Include="$(KestrelSharedSourceRoot)test\TestApplicationErrorLogger.cs" />
|
||||||
<Compile Include="$(KestrelSharedSourceRoot)test\TestHttp1Connection.cs" />
|
<Compile Include="$(KestrelSharedSourceRoot)test\TestHttp1Connection.cs" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
{
|
||||||
|
internal class MockDuplexPipe : IDuplexPipe
|
||||||
|
{
|
||||||
|
public MockDuplexPipe(PipeReader input, PipeWriter output)
|
||||||
|
{
|
||||||
|
Input = input;
|
||||||
|
Output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PipeReader Input { get; }
|
||||||
|
public PipeWriter Output { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
{
|
||||||
|
internal class MockSystemClock : ISystemClock
|
||||||
|
{
|
||||||
|
public DateTimeOffset UtcNow { get; }
|
||||||
|
public long UtcNowTicks { get; }
|
||||||
|
public DateTimeOffset UtcNowUnsynchronized { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2.FlowControl;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
{
|
||||||
|
internal class MockTimeoutControl : ITimeoutControl
|
||||||
|
{
|
||||||
|
public TimeoutReason TimerReason { get; } = TimeoutReason.KeepAlive;
|
||||||
|
|
||||||
|
public void BytesRead(long count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BytesWrittenToBuffer(MinDataRate minRate, long count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelTimeout()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeHttp2(InputFlowControl connectionInputFlowControl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetTimeout(long ticks, TimeoutReason timeoutReason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTimeout(long ticks, TimeoutReason timeoutReason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartRequestBody(MinDataRate minRate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartTimingRead()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartTimingWrite()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopRequestBody()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopTimingRead()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopTimingWrite()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
{
|
{
|
||||||
internal class NullPipeWriter : PipeWriter
|
internal class NullPipeWriter : PipeWriter
|
||||||
{
|
{
|
||||||
private byte[] _buffer = new byte[1024 * 128];
|
// Should be large enough for any content attempting to write to the buffer
|
||||||
|
private readonly byte[] _buffer = new byte[1024 * 128];
|
||||||
|
|
||||||
public override void Advance(int bytes)
|
public override void Advance(int bytes)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Net.Http.HPack;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Testing
|
||||||
|
{
|
||||||
|
internal static class PipeWriterHttp2FrameExtensions
|
||||||
|
{
|
||||||
|
public static void WriteSettings(this PipeWriter writer, Http2PeerSettings clientSettings)
|
||||||
|
{
|
||||||
|
var frame = new Http2Frame();
|
||||||
|
frame.PrepareSettings(Http2SettingsFrameFlags.NONE);
|
||||||
|
var settings = clientSettings.GetNonProtocolDefaults();
|
||||||
|
var payload = new byte[settings.Count * Http2FrameReader.SettingSize];
|
||||||
|
frame.PayloadLength = payload.Length;
|
||||||
|
Http2FrameWriter.WriteSettings(settings, payload);
|
||||||
|
Http2FrameWriter.WriteHeader(frame, writer);
|
||||||
|
writer.Write(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteStartStream(this PipeWriter writer, int streamId, Http2HeadersEnumerator headers, HPackEncoder hpackEncoder, byte[] headerEncodingBuffer, bool endStream)
|
||||||
|
{
|
||||||
|
var frame = new Http2Frame();
|
||||||
|
frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId);
|
||||||
|
|
||||||
|
var buffer = headerEncodingBuffer.AsSpan();
|
||||||
|
var done = hpackEncoder.BeginEncode(headers, buffer, out var length);
|
||||||
|
frame.PayloadLength = length;
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
{
|
||||||
|
frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endStream)
|
||||||
|
{
|
||||||
|
frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
Http2FrameWriter.WriteHeader(frame, writer);
|
||||||
|
writer.Write(buffer.Slice(0, length));
|
||||||
|
|
||||||
|
while (!done)
|
||||||
|
{
|
||||||
|
frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId);
|
||||||
|
|
||||||
|
done = hpackEncoder.Encode(buffer, out length);
|
||||||
|
frame.PayloadLength = length;
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
{
|
||||||
|
frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Http2FrameWriter.WriteHeader(frame, writer);
|
||||||
|
writer.Write(buffer.Slice(0, length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteData(this PipeWriter writer, int streamId, Memory<byte> data, bool endStream)
|
||||||
|
{
|
||||||
|
var frame = new Http2Frame();
|
||||||
|
|
||||||
|
frame.PrepareData(streamId);
|
||||||
|
frame.PayloadLength = data.Length;
|
||||||
|
frame.DataFlags = endStream ? Http2DataFrameFlags.END_STREAM : Http2DataFrameFlags.NONE;
|
||||||
|
|
||||||
|
Http2FrameWriter.WriteHeader(frame, writer);
|
||||||
|
writer.Write(data.Span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -501,56 +501,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
_runningStreams[streamId] = tcs;
|
_runningStreams[streamId] = tcs;
|
||||||
|
|
||||||
var frame = new Http2Frame();
|
PipeWriterHttp2FrameExtensions.WriteStartStream(writableBuffer, streamId, GetHeadersEnumerator(headers), _hpackEncoder, _headerEncodingBuffer, endStream);
|
||||||
frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId);
|
|
||||||
|
|
||||||
var buffer = _headerEncodingBuffer.AsSpan();
|
|
||||||
var done = _hpackEncoder.BeginEncode(GetHeadersEnumerator(headers), buffer, out var length);
|
|
||||||
frame.PayloadLength = length;
|
|
||||||
|
|
||||||
if (done)
|
|
||||||
{
|
|
||||||
frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (endStream)
|
|
||||||
{
|
|
||||||
frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
Http2FrameWriter.WriteHeader(frame, writableBuffer);
|
|
||||||
writableBuffer.Write(buffer.Slice(0, length));
|
|
||||||
|
|
||||||
while (!done)
|
|
||||||
{
|
|
||||||
frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId);
|
|
||||||
|
|
||||||
done = _hpackEncoder.Encode(buffer, out length);
|
|
||||||
frame.PayloadLength = length;
|
|
||||||
|
|
||||||
if (done)
|
|
||||||
{
|
|
||||||
frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
Http2FrameWriter.WriteHeader(frame, writableBuffer);
|
|
||||||
writableBuffer.Write(buffer.Slice(0, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
return FlushAsync(writableBuffer);
|
return FlushAsync(writableBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Http2HeadersEnumerator GetHeadersEnumerator(IEnumerable<KeyValuePair<string, string>> headers)
|
|
||||||
{
|
|
||||||
var groupedHeaders = headers
|
|
||||||
.GroupBy(k => k.Key)
|
|
||||||
.ToDictionary(g => g.Key, g => new StringValues(g.Select(gg => gg.Value).ToArray()));
|
|
||||||
|
|
||||||
var enumerator = new Http2HeadersEnumerator();
|
|
||||||
enumerator.Initialize(groupedHeaders);
|
|
||||||
return enumerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* https://tools.ietf.org/html/rfc7540#section-6.2
|
/* https://tools.ietf.org/html/rfc7540#section-6.2
|
||||||
+---------------+
|
+---------------+
|
||||||
|Pad Length? (8)|
|
|Pad Length? (8)|
|
||||||
|
|
@ -704,15 +658,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
|
||||||
protected async Task SendSettingsAsync()
|
protected async Task SendSettingsAsync()
|
||||||
{
|
{
|
||||||
var writableBuffer = _pair.Application.Output;
|
PipeWriterHttp2FrameExtensions.WriteSettings(_pair.Application.Output, _clientSettings);
|
||||||
var frame = new Http2Frame();
|
await FlushAsync(_pair.Application.Output);
|
||||||
frame.PrepareSettings(Http2SettingsFrameFlags.NONE);
|
|
||||||
var settings = _clientSettings.GetNonProtocolDefaults();
|
|
||||||
var payload = new byte[settings.Count * Http2FrameReader.SettingSize];
|
|
||||||
frame.PayloadLength = payload.Length;
|
|
||||||
Http2FrameWriter.WriteSettings(settings, payload);
|
|
||||||
Http2FrameWriter.WriteHeader(frame, writableBuffer);
|
|
||||||
await SendAsync(payload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task SendSettingsAckWithInvalidLengthAsync(int length)
|
protected async Task SendSettingsAckWithInvalidLengthAsync(int length)
|
||||||
|
|
@ -890,6 +837,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Http2HeadersEnumerator GetHeadersEnumerator(IEnumerable<KeyValuePair<string, string>> headers)
|
||||||
|
{
|
||||||
|
var dictionary = headers
|
||||||
|
.GroupBy(g => g.Key)
|
||||||
|
.ToDictionary(g => g.Key, g => new StringValues(g.Select(values => values.Value).ToArray()));
|
||||||
|
|
||||||
|
var headersEnumerator = new Http2HeadersEnumerator();
|
||||||
|
headersEnumerator.Initialize(dictionary);
|
||||||
|
return headersEnumerator;
|
||||||
|
}
|
||||||
|
|
||||||
internal Task SendEmptyContinuationFrameAsync(int streamId, Http2ContinuationFrameFlags flags)
|
internal Task SendEmptyContinuationFrameAsync(int streamId, Http2ContinuationFrameFlags flags)
|
||||||
{
|
{
|
||||||
var outputWriter = _pair.Application.Output;
|
var outputWriter = _pair.Application.Output;
|
||||||
|
|
@ -923,14 +881,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
protected Task SendDataAsync(int streamId, Memory<byte> data, bool endStream)
|
protected Task SendDataAsync(int streamId, Memory<byte> data, bool endStream)
|
||||||
{
|
{
|
||||||
var outputWriter = _pair.Application.Output;
|
var outputWriter = _pair.Application.Output;
|
||||||
var frame = new Http2Frame();
|
PipeWriterHttp2FrameExtensions.WriteData(outputWriter, streamId, data, endStream);
|
||||||
|
return FlushAsync(outputWriter);
|
||||||
frame.PrepareData(streamId);
|
|
||||||
frame.PayloadLength = data.Length;
|
|
||||||
frame.DataFlags = endStream ? Http2DataFrameFlags.END_STREAM : Http2DataFrameFlags.NONE;
|
|
||||||
|
|
||||||
Http2FrameWriter.WriteHeader(frame, outputWriter);
|
|
||||||
return SendAsync(data.Span);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task SendDataWithPaddingAsync(int streamId, Memory<byte> data, byte padLength, bool endStream)
|
protected async Task SendDataWithPaddingAsync(int streamId, Memory<byte> data, byte padLength, bool endStream)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace BenchmarkDotNet.Attributes
|
||||||
|
|
||||||
Add(JitOptimizationsValidator.FailOnError);
|
Add(JitOptimizationsValidator.FailOnError);
|
||||||
|
|
||||||
Add(Job.Core
|
Add(Job.Default
|
||||||
#if NETCOREAPP2_1
|
#if NETCOREAPP2_1
|
||||||
.With(CsProjCoreToolchain.From(NetCoreAppSettings.NetCoreApp21))
|
.With(CsProjCoreToolchain.From(NetCoreAppSettings.NetCoreApp21))
|
||||||
#elif NETCOREAPP3_0
|
#elif NETCOREAPP3_0
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,7 @@ namespace BenchmarkDotNet.Attributes
|
||||||
Add(MemoryDiagnoser.Default);
|
Add(MemoryDiagnoser.Default);
|
||||||
Add(StatisticColumn.OperationsPerSecond);
|
Add(StatisticColumn.OperationsPerSecond);
|
||||||
Add(new ParamsSummaryColumn());
|
Add(new ParamsSummaryColumn());
|
||||||
Add(DefaultColumnProviders.Statistics, DefaultColumnProviders.Diagnosers, DefaultColumnProviders.Target);
|
Add(DefaultColumnProviders.Statistics, DefaultColumnProviders.Metrics, DefaultColumnProviders.Descriptor);
|
||||||
|
|
||||||
// TODO: When upgrading to BDN 0.11.1, use Add(DefaultColumnProviders.Descriptor);
|
|
||||||
// DefaultColumnProviders.Target is deprecated
|
|
||||||
|
|
||||||
Add(JitOptimizationsValidator.FailOnError);
|
Add(JitOptimizationsValidator.FailOnError);
|
||||||
|
|
||||||
|
|
@ -36,13 +33,7 @@ namespace BenchmarkDotNet.Attributes
|
||||||
|
|
||||||
Add(new CsvExporter(
|
Add(new CsvExporter(
|
||||||
CsvSeparator.Comma,
|
CsvSeparator.Comma,
|
||||||
new Reports.SummaryStyle
|
new Reports.SummaryStyle(printUnitsInHeader: true, printUnitsInContent: false, timeUnit: Horology.TimeUnit.Microsecond, sizeUnit: SizeUnit.KB)));
|
||||||
{
|
|
||||||
PrintUnitsInHeader = true,
|
|
||||||
PrintUnitsInContent = false,
|
|
||||||
TimeUnit = Horology.TimeUnit.Microsecond,
|
|
||||||
SizeUnit = SizeUnit.KB
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
using BenchmarkDotNet.Configs;
|
using BenchmarkDotNet.Configs;
|
||||||
using BenchmarkDotNet.Jobs;
|
using BenchmarkDotNet.Jobs;
|
||||||
using BenchmarkDotNet.Loggers;
|
using BenchmarkDotNet.Loggers;
|
||||||
using BenchmarkDotNet.Toolchains.InProcess;
|
using BenchmarkDotNet.Toolchains.InProcess.NoEmit;
|
||||||
|
|
||||||
namespace BenchmarkDotNet.Attributes
|
namespace BenchmarkDotNet.Attributes
|
||||||
{
|
{
|
||||||
|
|
@ -14,7 +14,7 @@ namespace BenchmarkDotNet.Attributes
|
||||||
{
|
{
|
||||||
Add(ConsoleLogger.Default);
|
Add(ConsoleLogger.Default);
|
||||||
|
|
||||||
Add(Job.Dry.With(InProcessToolchain.Instance));
|
Add(Job.Dry.With(InProcessNoEmitToolchain.Instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ namespace BenchmarkDotNet.Attributes
|
||||||
{
|
{
|
||||||
public string Id => nameof(ParamsSummaryColumn);
|
public string Id => nameof(ParamsSummaryColumn);
|
||||||
public string ColumnName { get; } = "Params";
|
public string ColumnName { get; } = "Params";
|
||||||
public bool IsDefault(Summary summary, Benchmark benchmark) => false;
|
public bool IsDefault(Summary summary, BenchmarkCase benchmark) => false;
|
||||||
public string GetValue(Summary summary, Benchmark benchmark) => benchmark.Parameters.DisplayInfo;
|
public string GetValue(Summary summary, BenchmarkCase benchmark) => benchmark.Parameters.DisplayInfo;
|
||||||
public bool IsAvailable(Summary summary) => true;
|
public bool IsAvailable(Summary summary) => true;
|
||||||
public bool AlwaysShow => true;
|
public bool AlwaysShow => true;
|
||||||
public ColumnCategory Category => ColumnCategory.Params;
|
public ColumnCategory Category => ColumnCategory.Params;
|
||||||
|
|
@ -20,7 +20,7 @@ namespace BenchmarkDotNet.Attributes
|
||||||
public override string ToString() => ColumnName;
|
public override string ToString() => ColumnName;
|
||||||
public bool IsNumeric => false;
|
public bool IsNumeric => false;
|
||||||
public UnitType UnitType => UnitType.Dimensionless;
|
public UnitType UnitType => UnitType.Dimensionless;
|
||||||
public string GetValue(Summary summary, Benchmark benchmark, ISummaryStyle style) => GetValue(summary, benchmark);
|
public string GetValue(Summary summary, BenchmarkCase benchmark, SummaryStyle style) => GetValue(summary, benchmark);
|
||||||
public string Legend => $"Summary of all parameter values";
|
public string Legend => $"Summary of all parameter values";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue