Skip to content

Commit

Permalink
Removing bounds checks when serializing commands/frames.
Browse files Browse the repository at this point in the history
Splitting WireFormatting into separate files for clarity.
  • Loading branch information
Stefán J. Sigurðarson committed Mar 19, 2021
1 parent d46b426 commit 846e590
Show file tree
Hide file tree
Showing 81 changed files with 1,207 additions and 1,259 deletions.
2 changes: 1 addition & 1 deletion projects/Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public Config()
{
AddJob(Job.Default.WithRuntime(CoreRuntime.Core31));
AddJob(Job.Default.WithRuntime(ClrRuntime.Net48));
AddExporter(DefaultExporters.Markdown, DefaultExporters.Csv);
AddExporter(DefaultExporters.Markdown, DefaultExporters.JsonFull).KeepBenchmarkFiles(true).DontOverwriteResults(true);
AddDiagnoser(new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig()), MemoryDiagnoser.Default);
}
}
Expand Down
54 changes: 26 additions & 28 deletions projects/Benchmarks/WireFormatting/DataTypeSerialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ public class DataTypeFieldSerialization : DataTypeSerialization
public override void SetUp()
{
_fieldNullBuffer = new byte[WireFormatting.GetFieldValueByteCount(null)];
WireFormatting.WriteFieldValue(_fieldNullBuffer.Span, null);
WireFormatting.WriteFieldValue(ref _fieldNullBuffer.Span.GetStart(), null, _fieldNullBuffer.Length);
_fieldIntBuffer = new byte[WireFormatting.GetFieldValueByteCount(_intObject)];
WireFormatting.WriteFieldValue(_fieldIntBuffer.Span, _intObject);
WireFormatting.WriteFieldValue(ref _fieldIntBuffer.Span.GetStart(), _intObject, _fieldIntBuffer.Length);
_fieldStringBuffer = new byte[WireFormatting.GetFieldValueByteCount(_shortString)];
WireFormatting.WriteFieldValue(_fieldStringBuffer.Span, _shortString);
WireFormatting.WriteFieldValue(ref _fieldStringBuffer.Span.GetStart(), _shortString, _fieldStringBuffer.Length);
_fieldArrayBuffer = new byte[WireFormatting.GetFieldValueByteCount(_byteArray)];
WireFormatting.WriteFieldValue(_fieldArrayBuffer.Span, _byteArray);
WireFormatting.WriteFieldValue(ref _fieldArrayBuffer.Span.GetStart(), _byteArray, _fieldArrayBuffer.Length);
_fieldDictBuffer = new byte[WireFormatting.GetFieldValueByteCount(_emptyDictionary)];
WireFormatting.WriteFieldValue(_fieldDictBuffer.Span, _emptyDictionary);
WireFormatting.WriteFieldValue(ref _fieldDictBuffer.Span.GetStart(), _emptyDictionary, _fieldDictBuffer.Length);
_fieldBinaryTableValueBuffer = new byte[WireFormatting.GetFieldValueByteCount(_binaryTableValue)];
WireFormatting.WriteFieldValue(_fieldBinaryTableValueBuffer.Span, _binaryTableValue);
WireFormatting.WriteFieldValue(ref _fieldBinaryTableValueBuffer.Span.GetStart(), _binaryTableValue, _fieldBinaryTableValueBuffer.Length);
}

[Benchmark]
Expand All @@ -64,20 +64,18 @@ public override void SetUp()
public object DictRead() => WireFormatting.ReadFieldValue(_fieldDictBuffer.Span, out int _);
[Benchmark]
public object BinaryTableValueRead() => WireFormatting.ReadFieldValue(_fieldBinaryTableValueBuffer.Span, out int _);

[Benchmark]
public int NullWrite() => WireFormatting.WriteFieldValue(_buffer.Span,null);
public int NullWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), null, _buffer.Length);
[Benchmark]
public int IntWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _intObject);
public int IntWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _intObject, _buffer.Length);
[Benchmark]
public int StringWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _shortString);
public int StringWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _shortString, _buffer.Length);
[Benchmark]
public int ArrayWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _byteArray);
public int ArrayWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _byteArray, _buffer.Length);
[Benchmark]
public int DictWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _emptyDictionary);
public int DictWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _emptyDictionary, _buffer.Length);
[Benchmark]
public int BinaryTableValueWrite() => WireFormatting.WriteFieldValue(_buffer.Span, _binaryTableValue);

public int BinaryTableValueWrite() => WireFormatting.WriteFieldValue(ref _buffer.Span.GetStart(), _binaryTableValue, _buffer.Length);
[Benchmark]
public int NullGetSize() => WireFormatting.GetFieldValueByteCount(null);
[Benchmark]
Expand All @@ -103,10 +101,10 @@ public override void SetUp()
{
_array = new List<object> { "longstring", 1234, 12.34m, _timestamp };
_emptyArrayBuffer = new byte[WireFormatting.GetArrayByteCount(_emptyArray)];
WireFormatting.WriteArray(_emptyArrayBuffer.Span, _emptyArray);
WireFormatting.WriteArray(ref _emptyArrayBuffer.Span.GetStart(), _emptyArray, _emptyArrayBuffer.Length);

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

[Benchmark]
Expand All @@ -116,10 +114,10 @@ public override void SetUp()
public IList ArrayReadPopulated() => WireFormatting.ReadArray(_populatedArrayBuffer.Span, out _);

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

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

[Benchmark]
public int ArrayGetSizeEmpty() => WireFormatting.GetArrayByteCount(_emptyArray);
Expand Down Expand Up @@ -149,10 +147,10 @@ public override void SetUp()
};

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

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

[Benchmark]
Expand All @@ -162,10 +160,10 @@ public override void SetUp()
public int TableReadPopulated() => WireFormatting.ReadDictionary(_populatedDictionaryBuffer.Span, out _);

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

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

[Benchmark]
public int TableGetSizeEmpty() => WireFormatting.GetTableByteCount(_emptyDict);
Expand All @@ -187,10 +185,10 @@ public class DataTypeLongStringSerialization : DataTypeSerialization
public int LongstrReadPopulated() => WireFormatting.ReadLongstr(_populatedLongStringBuffer.Span, out _);

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

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

[Benchmark]
public int LongstrGetSizeEmpty() => WireFormatting.GetFieldValueByteCount(string.Empty);
Expand All @@ -201,7 +199,7 @@ public class DataTypeLongStringSerialization : DataTypeSerialization
private static byte[] GenerateLongStringBuffer(string val)
{
byte[] _buffer = new byte[5 + Encoding.UTF8.GetByteCount(val)];
WireFormatting.WriteLongstr(_buffer, val);
WireFormatting.WriteLongstr(ref _buffer.GetStart(), val, _buffer.Length);
return _buffer;
}
}
Expand All @@ -219,10 +217,10 @@ public class DataTypeShortStringSerialization : DataTypeSerialization
public int ShortstrReadPopulated() => WireFormatting.ReadShortstr(_populatedShortStringBuffer.Span, out _);

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

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

[Benchmark]
public int ShortstrGetSizeEmpty() => WireFormatting.GetByteCount(string.Empty);
Expand All @@ -233,7 +231,7 @@ public class DataTypeShortStringSerialization : DataTypeSerialization
private static byte[] GenerateStringBuffer(string val)
{
byte[] _buffer = new byte[2 + Encoding.UTF8.GetByteCount(val)];
WireFormatting.WriteShortstr(_buffer, val);
WireFormatting.WriteShortstr(ref _buffer.GetStart(), val, _buffer.Length);
return _buffer;
}
}
Expand Down
12 changes: 7 additions & 5 deletions projects/Benchmarks/WireFormatting/MethodSerialization.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Text;

using BenchmarkDotNet.Attributes;

using RabbitMQ.Client.Framing;
Expand Down Expand Up @@ -37,11 +38,12 @@ public class MethodBasicDeliver : MethodSerializationBase

public override void SetUp()
{
int offset = RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Span, string.Empty);
offset += RabbitMQ.Client.Impl.WireFormatting.WriteLonglong(_buffer.Slice(offset).Span, 0);
offset += RabbitMQ.Client.Impl.WireFormatting.WriteBits(_buffer.Slice(offset).Span, false);
offset += RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Slice(offset).Span, string.Empty);
RabbitMQ.Client.Impl.WireFormatting.WriteShortstr(_buffer.Slice(offset).Span, string.Empty);
int length = _buffer.Length;
int offset = Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetStart(), string.Empty, length);
offset += Client.Impl.WireFormatting.WriteLonglong(ref _buffer.Span.GetOffset(offset), 0);
offset += Client.Impl.WireFormatting.WriteBits(ref _buffer.Span.GetOffset(offset), false);
offset += Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetOffset(offset), string.Empty, length - offset);
Client.Impl.WireFormatting.WriteShortstr(ref _buffer.Span.GetOffset(offset), string.Empty, length - offset);
}

[Benchmark]
Expand Down
26 changes: 13 additions & 13 deletions projects/Benchmarks/WireFormatting/PrimitivesSerialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public virtual void Setup() { }

public class PrimitivesBool : PrimitivesBase
{
public override void Setup() => WireFormatting.WriteBits(_buffer.Span, true, false, true, false, true);
public override void Setup() => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), true, false, true, false, true);

[Benchmark]
public int BoolRead2() => WireFormatting.ReadBits(_buffer.Span, out bool _, out bool _);
Expand All @@ -29,70 +29,70 @@ public class PrimitivesBool : PrimitivesBase

[Benchmark]
[Arguments(true, false)]
public int BoolWrite2(bool param1, bool param2) => WireFormatting.WriteBits(_buffer.Span, param1, param2);
public int BoolWrite2(bool param1, bool param2) => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), param1, param2);

[Benchmark]
[Arguments(true, false)]
public int BoolWrite5(bool param1, bool param2) => WireFormatting.WriteBits(_buffer.Span, param1, param2, param1, param2, param1);
public int BoolWrite5(bool param1, bool param2) => WireFormatting.WriteBits(ref _buffer.Span.GetStart(), param1, param2, param1, param2, param1);
}

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

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

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

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

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

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

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

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

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

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

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

[Benchmark]
[Arguments(12345)]
public int ShortWrite(ushort value) => WireFormatting.WriteShort(_buffer.Span, value);
public int ShortWrite(ushort value) => WireFormatting.WriteShort(ref _buffer.Span.GetStart(), value);
}

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

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

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

[Benchmark]
public int TimestampWrite() => WireFormatting.WriteTimestamp(_buffer.Span, _timestamp);
public int TimestampWrite() => WireFormatting.WriteTimestamp(ref _buffer.Span.GetStart(), _timestamp);
}
}
20 changes: 7 additions & 13 deletions projects/RabbitMQ.Client/client/framing/BasicAck.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
//---------------------------------------------------------------------------

using System;
using System.Runtime.CompilerServices;

using RabbitMQ.Client.client.framing;
using RabbitMQ.Client.Impl;

Expand All @@ -40,16 +42,13 @@ internal sealed class BasicAck : Client.Impl.MethodBase
public ulong _deliveryTag;
public bool _multiple;

public BasicAck()
{
}

public BasicAck(ulong DeliveryTag, bool Multiple)
{
_deliveryTag = DeliveryTag;
_multiple = Multiple;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BasicAck(ReadOnlySpan<byte> span)
{
int offset = WireFormatting.ReadLonglong(span, out _deliveryTag);
Expand All @@ -58,17 +57,12 @@ public BasicAck(ReadOnlySpan<byte> span)

public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicAck;
public override string ProtocolMethodName => "basic.ack";
public override bool HasContent => false;

public override int WriteArgumentsTo(Span<byte> span)
{
int offset = WireFormatting.WriteLonglong(span, _deliveryTag);
return offset + WireFormatting.WriteBits(span.Slice(offset), _multiple);
}

public override int GetRequiredBufferSize()
{
return 8 + 1;
int offset = WireFormatting.WriteLonglong(ref span.GetStart(), _deliveryTag);
offset += WireFormatting.WriteBits(ref span.GetOffset(offset), _multiple);
return offset;
}
public override int GetRequiredBufferSize() => 9;
}
}
7 changes: 3 additions & 4 deletions projects/RabbitMQ.Client/client/framing/BasicCancel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
//---------------------------------------------------------------------------

using System;
using System.Text;

using RabbitMQ.Client.client.framing;
using RabbitMQ.Client.Impl;

Expand Down Expand Up @@ -59,12 +59,11 @@ public BasicCancel(ReadOnlySpan<byte> span)

public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancel;
public override string ProtocolMethodName => "basic.cancel";
public override bool HasContent => false;

public override int WriteArgumentsTo(Span<byte> span)
{
int offset = WireFormatting.WriteShortstr(span, _consumerTag);
return offset + WireFormatting.WriteBits(span.Slice(offset), _nowait);
int offset = WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag, span.Length);
return offset + WireFormatting.WriteBits(ref span.GetOffset(offset), _nowait);
}

public override int GetRequiredBufferSize()
Expand Down
3 changes: 1 addition & 2 deletions projects/RabbitMQ.Client/client/framing/BasicCancelOk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ public BasicCancelOk(ReadOnlySpan<byte> span)

public override ProtocolCommandId ProtocolCommandId => ProtocolCommandId.BasicCancelOk;
public override string ProtocolMethodName => "basic.cancel-ok";
public override bool HasContent => false;

public override int WriteArgumentsTo(Span<byte> span)
{
return WireFormatting.WriteShortstr(span, _consumerTag);
return WireFormatting.WriteShortstr(ref span.GetStart(), _consumerTag, span.Length);
}

public override int GetRequiredBufferSize()
Expand Down
Loading

0 comments on commit 846e590

Please sign in to comment.