Skip to content

Cleaning up and adding more benchmarks. #983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion projects/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<OutputType>Exe</OutputType>
<AssemblyOriginatorKeyFile>../rabbit.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFrameworks>netcoreapp3.1;net48</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand All @@ -13,6 +13,7 @@

<ItemGroup>
<ProjectReference Include="..\RabbitMQ.Client\RabbitMQ.Client.csproj" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

</Project>
20 changes: 18 additions & 2 deletions projects/Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

namespace Benchmarks
namespace RabbitMQ.Benchmarks
{
public static class Program
{
Expand All @@ -9,4 +14,15 @@ public static void Main(string[] args)
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}

class Config : ManualConfig
{
public Config()
{
AddJob(Job.Default.WithRuntime(CoreRuntime.Core31));
AddJob(Job.Default.WithRuntime(ClrRuntime.Net48));
AddExporter(DefaultExporters.Markdown, DefaultExporters.Csv);
AddDiagnoser(new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig()), MemoryDiagnoser.Default);
}
}
}
145 changes: 145 additions & 0 deletions projects/Benchmarks/WireFormatting/DataTypeSerialization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using BenchmarkDotNet.Attributes;

using RabbitMQ.Client;
using RabbitMQ.Client.Impl;

namespace RabbitMQ.Benchmarks
{
[Config(typeof(Config))]
[BenchmarkCategory("DataTypes")]
public class DataTypeSerialization
{
protected readonly Memory<byte> _buffer = new Memory<byte>(new byte[16384]);
protected readonly AmqpTimestamp _timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());

[GlobalSetup]
public virtual void SetUp() { }
}

public class DateTypeArraySerialization : DataTypeSerialization
{
readonly List<object> _emptyArray = new List<object>();
Memory<byte> _emptyArrayBuffer;
Memory<byte> _populatedArrayBuffer;
List<object> _array;

public override void SetUp()
{
_array = new List<object> { "longstring", 1234, 12.34m, _timestamp };
_emptyArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_emptyArray)];
WireFormatting.WriteArray(_emptyArrayBuffer.Span, _emptyArray);

_populatedArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_array)];
WireFormatting.WriteArray(_populatedArrayBuffer.Span, _array);
}

[Benchmark]
public IList ArrayReadEmpty() => WireFormatting.ReadArray(_emptyArrayBuffer.Span, out _);

[Benchmark]
public IList ArrayReadPopulated() => WireFormatting.ReadArray(_populatedArrayBuffer.Span, out _);

[Benchmark]
public int ArrayWriteEmpty() => WireFormatting.WriteArray(_buffer.Span, _emptyArray);

[Benchmark]
public int ArrayWritePopulated() => WireFormatting.WriteArray(_buffer.Span, _array);
}

public class DataTypeTableSerialization : DataTypeSerialization
{
IDictionary<string, object> _emptyDict = new Dictionary<string, object>();
IDictionary<string, object> _populatedDict;
Memory<byte> _emptyDictionaryBuffer;
Memory<byte> _populatedDictionaryBuffer;

public override void SetUp()
{
_populatedDict = new Dictionary<string, object>
{
{ "string", "Hello" },
{ "int", 1234 },
{ "uint", 1234u },
{ "decimal", 12.34m },
{ "timestamp", _timestamp },
{ "fieldtable", new Dictionary<string, object>(){ { "test", "test" } } },
{ "fieldarray", new List<object> { "longstring", 1234, 12.34m, _timestamp } }
};

_emptyDictionaryBuffer = new byte[WireFormatting.GetTableByteCount(_emptyDict)];
WireFormatting.WriteTable(_emptyDictionaryBuffer.Span, _emptyDict);

_populatedDictionaryBuffer = new byte[WireFormatting.GetTableByteCount(_populatedDict)];
WireFormatting.WriteTable(_populatedDictionaryBuffer.Span, _populatedDict);
}

[Benchmark]
public int TableReadEmpty() => WireFormatting.ReadDictionary(_emptyDictionaryBuffer.Span, out _);

[Benchmark]
public int TableReadPopulated() => WireFormatting.ReadDictionary(_populatedDictionaryBuffer.Span, out _);

[Benchmark]
public int TableWriteEmpty() => WireFormatting.WriteTable(_buffer.Span, _emptyDict);

[Benchmark]
public int TableWritePopulated() => WireFormatting.WriteTable(_buffer.Span, _populatedDict);
}

public class DataTypeLongStringSerialization : DataTypeSerialization
{
readonly string _longString = new string('X', 4096);
readonly Memory<byte> _emptyLongStringBuffer = GenerateLongStringBuffer(string.Empty);
readonly Memory<byte> _populatedLongStringBuffer = GenerateLongStringBuffer(new string('X', 4096));

[Benchmark]
public int LongstrReadEmpty() => WireFormatting.ReadLongstr(_emptyLongStringBuffer.Span, out _);

[Benchmark]
public int LongstrReadPopulated() => WireFormatting.ReadLongstr(_populatedLongStringBuffer.Span, out _);

[Benchmark]
public int LongstrWriteEmpty() => WireFormatting.WriteLongstr(_buffer.Span, string.Empty);

[Benchmark]
public int LongstrWritePopulated() => WireFormatting.WriteLongstr(_buffer.Span, _longString);

private static byte[] GenerateLongStringBuffer(string val)
{
byte[] _buffer = new byte[5 + Encoding.UTF8.GetByteCount(val)];
WireFormatting.WriteLongstr(_buffer, val);
return _buffer;
}
}

public class DataTypeShortStringSerialization : DataTypeSerialization
{
readonly string _shortString = new string('X', 255);
readonly Memory<byte> _emptyShortStringBuffer = GenerateStringBuffer(string.Empty);
readonly Memory<byte> _populatedShortStringBuffer = GenerateStringBuffer(new string('X', 255));

[Benchmark]
public int ShortstrReadEmpty() => WireFormatting.ReadShortstr(_emptyShortStringBuffer.Span, out _);

[Benchmark]
public int ShortstrReadPopulated() => WireFormatting.ReadShortstr(_populatedShortStringBuffer.Span, out _);

[Benchmark]
public int ShortstrWriteEmpty() => WireFormatting.WriteShortstr(_buffer.Span, string.Empty);

[Benchmark]
public int ShortstrWritePopulated() => WireFormatting.WriteShortstr(_buffer.Span, _shortString);

private static byte[] GenerateStringBuffer(string val)
{
byte[] _buffer = new byte[2 + Encoding.UTF8.GetByteCount(val)];
WireFormatting.WriteShortstr(_buffer, val);
return _buffer;
}
}
}
68 changes: 68 additions & 0 deletions projects/Benchmarks/WireFormatting/MethodSerialization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;

using BenchmarkDotNet.Attributes;

using RabbitMQ.Client.Framing;
using RabbitMQ.Client.Framing.Impl;

namespace RabbitMQ.Benchmarks
{
[Config(typeof(Config))]
[BenchmarkCategory("Methods")]
public class MethodSerializationBase
{
protected readonly Memory<byte> _buffer = new byte[1024];

[GlobalSetup]
public virtual void SetUp() { }
}

public class MethodBasicAck : MethodSerializationBase
{
private readonly BasicAck _basicAck = new BasicAck(ulong.MaxValue, true);
public override void SetUp() => _basicAck.WriteArgumentsTo(_buffer.Span);

[Benchmark]
public object BasicAckRead() => new BasicAck(_buffer.Span);

[Benchmark]
public int BasicAckWrite() => _basicAck.WriteArgumentsTo(_buffer.Span);
}

public class MethodBasicDeliver : MethodSerializationBase
{
private readonly BasicDeliver _basicDeliver = new BasicDeliver(string.Empty, 0, false, string.Empty, string.Empty);
public override void SetUp() => _basicDeliver.WriteArgumentsTo(_buffer.Span);

[Benchmark]
public object BasicDeliverRead() => new BasicDeliver(_buffer.Span);

[Benchmark]
public int BasicDeliverWrite() => _basicDeliver.WriteArgumentsTo(_buffer.Span);
}

public class MethodChannelClose : MethodSerializationBase
{
private readonly ChannelClose _channelClose = new ChannelClose(333, string.Empty, 0099, 2999);

public override void SetUp() => _channelClose.WriteArgumentsTo(_buffer.Span);

[Benchmark]
public object ChannelCloseRead() => new ChannelClose(_buffer.Span);

[Benchmark]
public int ChannelCloseWrite() => _channelClose.WriteArgumentsTo(_buffer.Span);
}

public class MethodBasicProperties : MethodSerializationBase
{
private readonly BasicProperties _basicProperties = new BasicProperties { Persistent = true, AppId = "AppId", ContentEncoding = "content", };
public override void SetUp() => _basicProperties.WritePropertiesTo(_buffer.Span);

[Benchmark]
public object BasicPropertiesRead() => new BasicProperties(_buffer.Span);

[Benchmark]
public int BasicPropertiesWrite() => _basicProperties.WritePropertiesTo(_buffer.Span);
}
}
76 changes: 76 additions & 0 deletions projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;

using BenchmarkDotNet.Attributes;

using RabbitMQ.Client;
using RabbitMQ.Client.Impl;

namespace RabbitMQ.Benchmarks
{
[Config(typeof(Config))]
[BenchmarkCategory("Primitives")]
public class PrimitivesBase
{
protected Memory<byte> _buffer = new byte[16];

[GlobalSetup]
public virtual void Setup() { }
}

public class PrimitivesDecimal : PrimitivesBase
{
public override void Setup() => WireFormatting.WriteDecimal(_buffer.Span, 123.45m);

[Benchmark]
public decimal DecimalRead() => WireFormatting.ReadDecimal(_buffer.Span);

[Benchmark]
public int DecimalWrite() => WireFormatting.WriteDecimal(_buffer.Span, 123.45m);
}

public class PrimitivesLong : PrimitivesBase
{
public override void Setup() => WireFormatting.WriteLong(_buffer.Span, 12345u);

[Benchmark]
public int LongRead() => WireFormatting.ReadLong(_buffer.Span, out _);

[Benchmark]
public int LongWrite() => WireFormatting.WriteLong(_buffer.Span, 12345u);
}

public class PrimitivesLonglong : PrimitivesBase
{
public override void Setup() => WireFormatting.WriteLonglong(_buffer.Span, 12345ul);

[Benchmark]
public int LonglongRead() => WireFormatting.ReadLonglong(_buffer.Span, out _);

[Benchmark]
public int LonglongWrite() => WireFormatting.WriteLonglong(_buffer.Span, 12345ul);
}

public class PrimitivesShort : PrimitivesBase
{
public override void Setup() => WireFormatting.WriteShort(_buffer.Span, 12345);

[Benchmark]
public int ShortRead() => WireFormatting.ReadShort(_buffer.Span, out _);

[Benchmark]
public int ShortWrite() => WireFormatting.WriteShort(_buffer.Span, 12345);
}

public class PrimitivesTimestamp : PrimitivesBase
{
AmqpTimestamp _timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());

public override void Setup() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp);

[Benchmark]
public int TimestampRead() => WireFormatting.ReadTimestamp(_buffer.Span, out _);

[Benchmark]
public int TimestampWrite() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp);
}
}
24 changes: 0 additions & 24 deletions projects/Benchmarks/WireFormatting/WireFormatting_Read_BasicAck.cs

This file was deleted.

This file was deleted.

Loading