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 System.Collections.Generic;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Engines;
|
||||
using BenchmarkDotNet.Environments;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Validators;
|
||||
|
||||
|
|
@ -13,17 +9,23 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public CoreConfig(Job job)
|
||||
{
|
||||
Add(DefaultConfig.Instance);
|
||||
Add(MemoryDiagnoser.Default);
|
||||
Add(StatisticColumn.OperationsPerSecond);
|
||||
|
||||
Add(Job.Default
|
||||
.With(BenchmarkDotNet.Environments.Runtime.Core)
|
||||
Add(job
|
||||
.With(RunStrategy.Throughput)
|
||||
.WithRemoveOutliers(false)
|
||||
.With(new GcMode() { Server = true })
|
||||
.With(RunStrategy.Throughput)
|
||||
.WithLaunchCount(3)
|
||||
.WithWarmupCount(5)
|
||||
.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
|
||||
{
|
||||
[Config(typeof(CoreConfig))]
|
||||
[ParameterizedJobConfig(typeof(CoreConfig))]
|
||||
public class MessageParserBenchmark
|
||||
{
|
||||
private static readonly Random Random = new Random();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<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.Sockets\Microsoft.AspNetCore.Sockets.csproj" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
|
||||
<PackageReference Include="System.Threading.Channels" Version="$(SystemThreadingChannelsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</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 Label="Package Versions">
|
||||
<BenchmarkDotNetPackageVersion>0.10.9</BenchmarkDotNetPackageVersion>
|
||||
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview1-27579</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
||||
<BuildBundlerMinifierPackageVersion>2.4.337</BuildBundlerMinifierPackageVersion>
|
||||
<GoogleProtobufPackageVersion>3.1.0</GoogleProtobufPackageVersion>
|
||||
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview1-15549</InternalAspNetCoreSdkPackageVersion>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<EnableBenchmarkValidation>true</EnableBenchmarkValidation>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectsToPack Include="$(RepositoryRoot)client-ts\Microsoft.AspNetCore.SignalR.Client.TS\*.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ click('connect', function(event) {
|
|||
connectButton.disabled = true;
|
||||
disconnectButton.disabled = false;
|
||||
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) {
|
||||
addLine('message-list', msg);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -69,7 +69,13 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
|
||||
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);
|
||||
|
||||
// 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 CancelInvocationMessage("xyz") } },
|
||||
|
||||
|
||||
new object[] { new[] { PingMessage.Instance } },
|
||||
|
||||
new object[]
|
||||
|
|
|
|||
Loading…
Reference in New Issue