More micro benchmarks (#1158)
- Hub Protocol benchmark - Broadcast benchmark - Run benchmarks validation during builds
This commit is contained in:
parent
887e22ec07
commit
531c7cfba1
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||||
|
using Microsoft.AspNetCore.Sockets;
|
||||||
|
using Microsoft.AspNetCore.Sockets.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
||||||
|
{
|
||||||
|
[ParameterizedJobConfig(typeof(CoreConfig))]
|
||||||
|
public class BroadcastBenchmark
|
||||||
|
{
|
||||||
|
private DefaultHubLifetimeManager<Hub> _hubLifetimeManager;
|
||||||
|
private HubContext<Hub> _hubContext;
|
||||||
|
|
||||||
|
[Params(1, 10, 1000)]
|
||||||
|
public int Connections;
|
||||||
|
|
||||||
|
[GlobalSetup]
|
||||||
|
public void GlobalSetup()
|
||||||
|
{
|
||||||
|
_hubLifetimeManager = new DefaultHubLifetimeManager<Hub>();
|
||||||
|
var options = new UnboundedChannelOptions { AllowSynchronousContinuations = true };
|
||||||
|
|
||||||
|
for (var i = 0; i < Connections; ++i)
|
||||||
|
{
|
||||||
|
var transportToApplication = Channel.CreateUnbounded<byte[]>(options);
|
||||||
|
var applicationToTransport = Channel.CreateUnbounded<byte[]>(options);
|
||||||
|
|
||||||
|
var application = ChannelConnection.Create<byte[]>(input: applicationToTransport, output: transportToApplication);
|
||||||
|
var transport = ChannelConnection.Create<byte[]>(input: transportToApplication, output: applicationToTransport);
|
||||||
|
var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), transport, application);
|
||||||
|
|
||||||
|
_hubLifetimeManager.OnConnectedAsync(new HubConnectionContext(Channel.CreateUnbounded<HubMessage>(), connection)).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
_hubContext = new HubContext<Hub>(_hubLifetimeManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Task InvokeAsyncAll()
|
||||||
|
{
|
||||||
|
return _hubContext.All.InvokeAsync("Method");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
using System;
|
using BenchmarkDotNet.Columns;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using BenchmarkDotNet.Columns;
|
|
||||||
using BenchmarkDotNet.Configs;
|
using BenchmarkDotNet.Configs;
|
||||||
using BenchmarkDotNet.Diagnosers;
|
using BenchmarkDotNet.Diagnosers;
|
||||||
using BenchmarkDotNet.Engines;
|
using BenchmarkDotNet.Engines;
|
||||||
using BenchmarkDotNet.Environments;
|
|
||||||
using BenchmarkDotNet.Jobs;
|
using BenchmarkDotNet.Jobs;
|
||||||
using BenchmarkDotNet.Validators;
|
using BenchmarkDotNet.Validators;
|
||||||
|
|
||||||
|
|
@ -13,17 +9,23 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
||||||
{
|
{
|
||||||
public class CoreConfig : ManualConfig
|
public class CoreConfig : ManualConfig
|
||||||
{
|
{
|
||||||
public CoreConfig()
|
public CoreConfig() : this(Job.Core)
|
||||||
{
|
{
|
||||||
|
// Here because build.cmd calls the other constructor
|
||||||
|
// and this setting will complain about non-release builds
|
||||||
Add(JitOptimizationsValidator.FailOnError);
|
Add(JitOptimizationsValidator.FailOnError);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CoreConfig(Job job)
|
||||||
|
{
|
||||||
|
Add(DefaultConfig.Instance);
|
||||||
Add(MemoryDiagnoser.Default);
|
Add(MemoryDiagnoser.Default);
|
||||||
Add(StatisticColumn.OperationsPerSecond);
|
Add(StatisticColumn.OperationsPerSecond);
|
||||||
|
|
||||||
Add(Job.Default
|
Add(job
|
||||||
.With(BenchmarkDotNet.Environments.Runtime.Core)
|
.With(RunStrategy.Throughput)
|
||||||
.WithRemoveOutliers(false)
|
.WithRemoveOutliers(false)
|
||||||
.With(new GcMode() { Server = true })
|
.With(new GcMode() { Server = true })
|
||||||
.With(RunStrategy.Throughput)
|
|
||||||
.WithLaunchCount(3)
|
.WithLaunchCount(3)
|
||||||
.WithWarmupCount(5)
|
.WithWarmupCount(5)
|
||||||
.WithTargetCount(10));
|
.WithTargetCount(10));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal.Encoders;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
||||||
|
{
|
||||||
|
[ParameterizedJobConfig(typeof(CoreConfig))]
|
||||||
|
public class HubProtocolBenchmark
|
||||||
|
{
|
||||||
|
private HubProtocolReaderWriter _hubProtocolReaderWriter;
|
||||||
|
private byte[] _binaryInput;
|
||||||
|
private TestBinder _binder;
|
||||||
|
private HubMessage _hubMessage;
|
||||||
|
|
||||||
|
[Params(Message.NoArguments, Message.FewArguments, Message.ManyArguments, Message.LargeArguments)]
|
||||||
|
public Message Input { get; set; }
|
||||||
|
|
||||||
|
[Params(Protocol.MsgPack, Protocol.Json)]
|
||||||
|
public Protocol HubProtocol { get; set; }
|
||||||
|
|
||||||
|
[GlobalSetup]
|
||||||
|
public void GlobalSetup()
|
||||||
|
{
|
||||||
|
switch (HubProtocol)
|
||||||
|
{
|
||||||
|
case Protocol.MsgPack:
|
||||||
|
_hubProtocolReaderWriter = new HubProtocolReaderWriter(new MessagePackHubProtocol(), new PassThroughEncoder());
|
||||||
|
break;
|
||||||
|
case Protocol.Json:
|
||||||
|
_hubProtocolReaderWriter = new HubProtocolReaderWriter(new JsonHubProtocol(), new PassThroughEncoder());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Input)
|
||||||
|
{
|
||||||
|
case Message.NoArguments:
|
||||||
|
_hubMessage = new InvocationMessage("123", true, "Target", null);
|
||||||
|
break;
|
||||||
|
case Message.FewArguments:
|
||||||
|
_hubMessage = new InvocationMessage("123", true, "Target", null, 1, "Foo", 2.0f);
|
||||||
|
break;
|
||||||
|
case Message.ManyArguments:
|
||||||
|
_hubMessage = new InvocationMessage("123", true, "Target", null, 1, "string", 2.0f, true, (byte)9, new byte[] { 5, 4, 3, 2, 1 }, 'c', 123456789101112L);
|
||||||
|
break;
|
||||||
|
case Message.LargeArguments:
|
||||||
|
_hubMessage = new InvocationMessage("123", true, "Target", null, new string('F', 10240), new byte[10240]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_binaryInput = GetBytes(_hubMessage);
|
||||||
|
_binder = new TestBinder(_hubMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void ReadSingleMessage()
|
||||||
|
{
|
||||||
|
if (!_hubProtocolReaderWriter.ReadMessages(_binaryInput, _binder, out var _))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Failed to read message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void WriteSingleMessage()
|
||||||
|
{
|
||||||
|
if (_hubProtocolReaderWriter.WriteMessage(_hubMessage).Length != _binaryInput.Length)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Failed to write message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Protocol
|
||||||
|
{
|
||||||
|
MsgPack = 0,
|
||||||
|
Json = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Message
|
||||||
|
{
|
||||||
|
NoArguments = 0,
|
||||||
|
FewArguments = 1,
|
||||||
|
ManyArguments = 2,
|
||||||
|
LargeArguments = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GetBytes(HubMessage hubMessage)
|
||||||
|
{
|
||||||
|
return _hubProtocolReaderWriter.WriteMessage(_hubMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ using Microsoft.AspNetCore.SignalR.Internal.Formatters;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
||||||
{
|
{
|
||||||
[Config(typeof(CoreConfig))]
|
[ParameterizedJobConfig(typeof(CoreConfig))]
|
||||||
public class MessageParserBenchmark
|
public class MessageParserBenchmark
|
||||||
{
|
{
|
||||||
private static readonly Random Random = new Random();
|
private static readonly Random Random = new Random();
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Core\Microsoft.AspNetCore.SignalR.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Sockets\Microsoft.AspNetCore.Sockets.csproj" />
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
|
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
|
||||||
|
<PackageReference Include="System.Threading.Channels" Version="$(SystemThreadingChannelsPackageVersion)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
using System.Reflection;
|
|
||||||
using BenchmarkDotNet.Running;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
|
||||||
{
|
|
||||||
class Program
|
|
||||||
{
|
|
||||||
static void Main(string[] args)
|
|
||||||
{
|
|
||||||
BenchmarkSwitcher.FromAssembly(typeof(Program).GetTypeInfo().Assembly).Run(args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 System;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
||||||
|
{
|
||||||
|
public class TestBinder : IInvocationBinder
|
||||||
|
{
|
||||||
|
private readonly Type[] _paramTypes;
|
||||||
|
private readonly Type _returnType;
|
||||||
|
|
||||||
|
public TestBinder(HubMessage expectedMessage)
|
||||||
|
{
|
||||||
|
switch (expectedMessage)
|
||||||
|
{
|
||||||
|
case StreamInvocationMessage i:
|
||||||
|
_paramTypes = i.Arguments?.Select(a => a?.GetType() ?? typeof(object))?.ToArray();
|
||||||
|
break;
|
||||||
|
case InvocationMessage i:
|
||||||
|
_paramTypes = i.Arguments?.Select(a => a?.GetType() ?? typeof(object))?.ToArray();
|
||||||
|
break;
|
||||||
|
case StreamItemMessage s:
|
||||||
|
_returnType = s.Item?.GetType() ?? typeof(object);
|
||||||
|
break;
|
||||||
|
case CompletionMessage c:
|
||||||
|
_returnType = c.Result?.GetType() ?? typeof(object);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestBinder() : this(null, null) { }
|
||||||
|
public TestBinder(Type[] paramTypes) : this(paramTypes, null) { }
|
||||||
|
public TestBinder(Type returnType) : this(null, returnType) { }
|
||||||
|
public TestBinder(Type[] paramTypes, Type returnType)
|
||||||
|
{
|
||||||
|
_paramTypes = paramTypes;
|
||||||
|
_returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type[] GetParameterTypes(string methodName)
|
||||||
|
{
|
||||||
|
if (_paramTypes != null)
|
||||||
|
{
|
||||||
|
return _paramTypes;
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Unexpected binder call");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type GetReturnType(string invocationId)
|
||||||
|
{
|
||||||
|
if (_returnType != null)
|
||||||
|
{
|
||||||
|
return _returnType;
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("Unexpected binder call");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Label="Package Versions">
|
<PropertyGroup Label="Package Versions">
|
||||||
<BenchmarkDotNetPackageVersion>0.10.9</BenchmarkDotNetPackageVersion>
|
<BenchmarkDotNetPackageVersion>0.10.9</BenchmarkDotNetPackageVersion>
|
||||||
|
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
||||||
<BuildBundlerMinifierPackageVersion>2.4.337</BuildBundlerMinifierPackageVersion>
|
<BuildBundlerMinifierPackageVersion>2.4.337</BuildBundlerMinifierPackageVersion>
|
||||||
<GoogleProtobufPackageVersion>3.1.0</GoogleProtobufPackageVersion>
|
<GoogleProtobufPackageVersion>3.1.0</GoogleProtobufPackageVersion>
|
||||||
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15549</InternalAspNetCoreSdkPackageVersion>
|
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15549</InternalAspNetCoreSdkPackageVersion>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<EnableBenchmarkValidation>true</EnableBenchmarkValidation>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectsToPack Include="$(RepositoryRoot)client-ts\Microsoft.AspNetCore.SignalR.Client.TS\*.csproj" />
|
<ProjectsToPack Include="$(RepositoryRoot)client-ts\Microsoft.AspNetCore.SignalR.Client.TS\*.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ click('connect', function(event) {
|
||||||
connectButton.disabled = true;
|
connectButton.disabled = true;
|
||||||
disconnectButton.disabled = false;
|
disconnectButton.disabled = false;
|
||||||
console.log('http://' + document.location.host + '/' + hubRoute);
|
console.log('http://' + document.location.host + '/' + hubRoute);
|
||||||
connection = new signalR.HubConnection(hubRoute, logger, { transport: transportType, logger: logger });
|
connection = new signalR.HubConnection(hubRoute, { transport: transportType, logging: logger });
|
||||||
connection.on('Send', function(msg) {
|
connection.on('Send', function(msg) {
|
||||||
addLine('message-list', msg);
|
addLine('message-list', msg);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,13 @@ namespace Microsoft.AspNetCore.SignalR
|
||||||
|
|
||||||
private Task InvokeAllWhere(string methodName, object[] args, Func<HubConnectionContext, bool> include)
|
private Task InvokeAllWhere(string methodName, object[] args, Func<HubConnectionContext, bool> include)
|
||||||
{
|
{
|
||||||
var tasks = new List<Task>(_connections.Count);
|
var count = _connections.Count;
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks = new List<Task>(count);
|
||||||
var message = CreateInvocationMessage(methodName, args);
|
var message = CreateInvocationMessage(methodName, args);
|
||||||
|
|
||||||
// TODO: serialize once per format by providing a different stream?
|
// TODO: serialize once per format by providing a different stream?
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
||||||
new object[] { new[] { new StreamInvocationMessage("xyz", "method", null, new[] { new CustomObject(), new CustomObject() }) } },
|
new object[] { new[] { new StreamInvocationMessage("xyz", "method", null, new[] { new CustomObject(), new CustomObject() }) } },
|
||||||
|
|
||||||
new object[] { new[] { new CancelInvocationMessage("xyz") } },
|
new object[] { new[] { new CancelInvocationMessage("xyz") } },
|
||||||
|
|
||||||
new object[] { new[] { PingMessage.Instance } },
|
new object[] { new[] { PingMessage.Instance } },
|
||||||
|
|
||||||
new object[]
|
new object[]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue