diff --git a/.github/workflows/ci-bdnbenchmark.yml b/.github/workflows/ci-bdnbenchmark.yml index ae86055446..7ca620bc73 100644 --- a/.github/workflows/ci-bdnbenchmark.yml +++ b/.github/workflows/ci-bdnbenchmark.yml @@ -88,6 +88,6 @@ jobs: gh-pages-branch: 'continuousbenchmark' benchmark-data-dir-path: 'website/static/charts' max-items-in-chart: 50 - alert-threshold: '10%' + alert-threshold: '110%' comment-always: true fail-on-alert: false \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Embedded/EmbeddedNetworkHandler.cs b/benchmark/BDN.benchmark/Embedded/EmbeddedNetworkHandler.cs index e4c7ff866c..2d74574fa9 100644 --- a/benchmark/BDN.benchmark/Embedded/EmbeddedNetworkHandler.cs +++ b/benchmark/BDN.benchmark/Embedded/EmbeddedNetworkHandler.cs @@ -24,11 +24,12 @@ public override void Dispose() public override bool TryClose() => throw new NotImplementedException(); - public unsafe void Send(byte[] buffer, byte* bufferPtr, int length) + public unsafe void Send(Request request) { - networkReceiveBuffer = buffer; - networkReceiveBufferPtr = bufferPtr; - OnNetworkReceive(length); + networkReceiveBuffer = request.buffer; + networkReceiveBufferPtr = request.bufferPtr; + + OnNetworkReceive(request.buffer.Length); // We should have consumed the entire buffer Debug.Assert(networkBytesRead == 0); diff --git a/benchmark/BDN.benchmark/Embedded/Request.cs b/benchmark/BDN.benchmark/Embedded/Request.cs new file mode 100644 index 0000000000..267284ad3f --- /dev/null +++ b/benchmark/BDN.benchmark/Embedded/Request.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +namespace Embedded.server +{ + public struct Request + { + public byte[] buffer; + public unsafe byte* bufferPtr; + } +} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Network/BasicOperations.cs b/benchmark/BDN.benchmark/Network/BasicOperations.cs index f2bbd98b5e..e56d78b817 100644 --- a/benchmark/BDN.benchmark/Network/BasicOperations.cs +++ b/benchmark/BDN.benchmark/Network/BasicOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Network { @@ -12,19 +13,18 @@ namespace BDN.benchmark.Network public unsafe class BasicOperations : NetworkBase { static ReadOnlySpan INLINE_PING => "PING\r\n"u8; - byte[] pingRequestBuffer; - byte* pingRequestBufferPointer; + Request ping; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref pingRequestBuffer, ref pingRequestBufferPointer, INLINE_PING); + SetupOperation(ref ping, INLINE_PING); } [Benchmark] public void InlinePing() { - Send(pingRequestBuffer, pingRequestBufferPointer, pingRequestBuffer.Length); + Send(ping); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Network/NetworkBase.cs b/benchmark/BDN.benchmark/Network/NetworkBase.cs index ee0648ec3e..a217988640 100644 --- a/benchmark/BDN.benchmark/Network/NetworkBase.cs +++ b/benchmark/BDN.benchmark/Network/NetworkBase.cs @@ -69,25 +69,24 @@ public virtual void GlobalCleanup() server.Dispose(); } - protected void Send(byte[] requestBuffer, byte* requestBufferPointer, int length) + protected void Send(Request request) { - networkHandler.Send(requestBuffer, requestBufferPointer, length); + networkHandler.Send(request); } - protected void SetupOperation(ref byte[] requestBuffer, ref byte* requestBufferPointer, ReadOnlySpan operation) + protected unsafe void SetupOperation(ref Request request, ReadOnlySpan operation, int batchSize = batchSize) { - requestBuffer = GC.AllocateArray(operation.Length * batchSize, pinned: true); - requestBufferPointer = (byte*)Unsafe.AsPointer(ref requestBuffer[0]); + request.buffer = GC.AllocateArray(operation.Length * batchSize, pinned: true); + request.bufferPtr = (byte*)Unsafe.AsPointer(ref request.buffer[0]); for (int i = 0; i < batchSize; i++) - operation.CopyTo(new Span(requestBuffer).Slice(i * operation.Length)); + operation.CopyTo(new Span(request.buffer).Slice(i * operation.Length)); } protected void SlowConsumeMessage(ReadOnlySpan message) { - var buffer = GC.AllocateArray(message.Length, pinned: true); - var bufferPointer = (byte*)Unsafe.AsPointer(ref buffer[0]); - message.CopyTo(new Span(buffer)); - Send(buffer, bufferPointer, buffer.Length); + Request request = default; + SetupOperation(ref request, message, 1); + Send(request); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Network/RawStringOperations.cs b/benchmark/BDN.benchmark/Network/RawStringOperations.cs index d58173b1de..6c0a6d8910 100644 --- a/benchmark/BDN.benchmark/Network/RawStringOperations.cs +++ b/benchmark/BDN.benchmark/Network/RawStringOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Network { @@ -12,58 +13,48 @@ namespace BDN.benchmark.Network public unsafe class RawStringOperations : NetworkBase { static ReadOnlySpan SET => "*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n"u8; - byte[] setRequestBuffer; - byte* setRequestBufferPointer; + Request set; static ReadOnlySpan SETEX => "*4\r\n$5\r\nSETEX\r\n$1\r\nd\r\n$1\r\n9\r\n$1\r\nd\r\n"u8; - byte[] setexRequestBuffer; - byte* setexRequestBufferPointer; + Request setex; static ReadOnlySpan SETNX => "*4\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n$2\r\nNX\r\n"u8; - byte[] setnxRequestBuffer; - byte* setnxRequestBufferPointer; + Request setnx; static ReadOnlySpan SETXX => "*4\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n$2\r\nXX\r\n"u8; - byte[] setxxRequestBuffer; - byte* setxxRequestBufferPointer; + Request setxx; static ReadOnlySpan GETNF => "*2\r\n$3\r\nGET\r\n$1\r\nb\r\n"u8; - byte[] getnfRequestBuffer; - byte* getnfRequestBufferPointer; + Request getnf; static ReadOnlySpan GETF => "*2\r\n$3\r\nGET\r\n$1\r\na\r\n"u8; - byte[] getfRequestBuffer; - byte* getfRequestBufferPointer; + Request getf; static ReadOnlySpan INCR => "*2\r\n$4\r\nINCR\r\n$1\r\ni\r\n"u8; - byte[] incrRequestBuffer; - byte* incrRequestBufferPointer; + Request incr; static ReadOnlySpan DECR => "*2\r\n$4\r\nDECR\r\n$1\r\nj\r\n"u8; - byte[] decrRequestBuffer; - byte* decrRequestBufferPointer; + Request decr; static ReadOnlySpan INCRBY => "*3\r\n$6\r\nINCRBY\r\n$1\r\nk\r\n$10\r\n1234567890\r\n"u8; - byte[] incrbyRequestBuffer; - byte* incrbyRequestBufferPointer; + Request incrby; static ReadOnlySpan DECRBY => "*3\r\n$6\r\nDECRBY\r\n$1\r\nl\r\n$10\r\n1234567890\r\n"u8; - byte[] decrbyRequestBuffer; - byte* decrbyRequestBufferPointer; + Request decrby; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref setRequestBuffer, ref setRequestBufferPointer, SET); - SetupOperation(ref setexRequestBuffer, ref setexRequestBufferPointer, SETEX); - SetupOperation(ref setnxRequestBuffer, ref setnxRequestBufferPointer, SETNX); - SetupOperation(ref setxxRequestBuffer, ref setxxRequestBufferPointer, SETXX); - SetupOperation(ref getfRequestBuffer, ref getfRequestBufferPointer, GETF); - SetupOperation(ref getnfRequestBuffer, ref getnfRequestBufferPointer, GETNF); - SetupOperation(ref incrRequestBuffer, ref incrRequestBufferPointer, INCR); - SetupOperation(ref decrRequestBuffer, ref decrRequestBufferPointer, DECR); - SetupOperation(ref incrbyRequestBuffer, ref incrbyRequestBufferPointer, INCRBY); - SetupOperation(ref decrbyRequestBuffer, ref decrbyRequestBufferPointer, DECRBY); + SetupOperation(ref set, SET); + SetupOperation(ref setex, SETEX); + SetupOperation(ref setnx, SETNX); + SetupOperation(ref setxx, SETXX); + SetupOperation(ref getf, GETF); + SetupOperation(ref getnf, GETNF); + SetupOperation(ref incr, INCR); + SetupOperation(ref decr, DECR); + SetupOperation(ref incrby, INCRBY); + SetupOperation(ref decrby, DECRBY); // Pre-populate data SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n"u8); @@ -76,61 +67,61 @@ public override void GlobalSetup() [Benchmark] public void Set() { - Send(setRequestBuffer, setRequestBufferPointer, setRequestBuffer.Length); + Send(set); } [Benchmark] public void SetEx() { - Send(setexRequestBuffer, setexRequestBufferPointer, setexRequestBuffer.Length); + Send(setex); } [Benchmark] public void SetNx() { - Send(setnxRequestBuffer, setnxRequestBufferPointer, setnxRequestBuffer.Length); + Send(setnx); } [Benchmark] public void SetXx() { - Send(setxxRequestBuffer, setxxRequestBufferPointer, setxxRequestBuffer.Length); + Send(setxx); } [Benchmark] public void GetFound() { - Send(getfRequestBuffer, getfRequestBufferPointer, getfRequestBuffer.Length); + Send(getf); } [Benchmark] public void GetNotFound() { - Send(getnfRequestBuffer, getnfRequestBufferPointer, getnfRequestBuffer.Length); + Send(getnf); } [Benchmark] public void Increment() { - Send(incrRequestBuffer, incrRequestBufferPointer, incrRequestBuffer.Length); + Send(incr); } [Benchmark] public void Decrement() { - Send(decrRequestBuffer, decrRequestBufferPointer, decrRequestBuffer.Length); + Send(decr); } [Benchmark] public void IncrementBy() { - Send(incrbyRequestBuffer, incrbyRequestBufferPointer, incrbyRequestBuffer.Length); + Send(incrby); } [Benchmark] public void DecrementBy() { - Send(decrbyRequestBuffer, decrbyRequestBufferPointer, decrbyRequestBuffer.Length); + Send(decrby); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/BasicOperations.cs b/benchmark/BDN.benchmark/Operations/BasicOperations.cs index f49093c22d..e9aed2c8ea 100644 --- a/benchmark/BDN.benchmark/Operations/BasicOperations.cs +++ b/benchmark/BDN.benchmark/Operations/BasicOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Operations { @@ -12,19 +13,18 @@ namespace BDN.benchmark.Operations public unsafe class BasicOperations : OperationsBase { static ReadOnlySpan INLINE_PING => "PING\r\n"u8; - byte[] pingRequestBuffer; - byte* pingRequestBufferPointer; + Request ping; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref pingRequestBuffer, ref pingRequestBufferPointer, INLINE_PING); + SetupOperation(ref ping, INLINE_PING); } [Benchmark] public void InlinePing() { - Send(pingRequestBuffer, pingRequestBufferPointer, pingRequestBuffer.Length); + Send(ping); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/CustomOperations.cs b/benchmark/BDN.benchmark/Operations/CustomOperations.cs index 4d83e9183f..80ca45daf9 100644 --- a/benchmark/BDN.benchmark/Operations/CustomOperations.cs +++ b/benchmark/BDN.benchmark/Operations/CustomOperations.cs @@ -3,6 +3,7 @@ using BDN.benchmark.CustomProcs; using BenchmarkDotNet.Attributes; +using Embedded.server; using Garnet; using Garnet.server; @@ -15,20 +16,16 @@ namespace BDN.benchmark.Operations public unsafe class CustomOperations : OperationsBase { static ReadOnlySpan SETIFPM => "*4\r\n$7\r\nSETIFPM\r\n$1\r\nk\r\n$3\r\nval\r\n$1\r\nv\r\n"u8; - byte[] setIfPmRequestBuffer; - byte* setIfPmRequestBufferPointer; + Request setIfPm; static ReadOnlySpan MYDICTSETGET => "*4\r\n$9\r\nMYDICTSET\r\n$2\r\nck\r\n$1\r\nf\r\n$1\r\nv\r\n*3\r\n$9\r\nMYDICTGET\r\n$2\r\nck\r\n$1\r\nf\r\n"u8; - byte[] myDictSetGetRequestBuffer; - byte* myDictSetGetRequestBufferPointer; + Request myDictSetGet; static ReadOnlySpan CTXNSET => "*9\r\n$7\r\nCTXNSET\r\n$6\r\n{0}000\r\n$6\r\n{0}001\r\n$6\r\n{0}002\r\n$6\r\n{0}003\r\n$6\r\n{0}000\r\n$6\r\n{0}001\r\n$6\r\n{0}002\r\n$6\r\n{0}003\r\n"u8; - byte[] ctxnsetBuffer; - byte* ctxnsetBufferPointer; + Request ctxnset; static ReadOnlySpan CPROCSET => "*9\r\n$8\r\nCPROCSET\r\n$6\r\n{0}000\r\n$6\r\n{0}001\r\n$6\r\n{0}002\r\n$6\r\n{0}003\r\n$6\r\n{0}000\r\n$6\r\n{0}001\r\n$6\r\n{0}002\r\n$6\r\n{0}003\r\n"u8; - byte[] cprocsetBuffer; - byte* cprocsetBufferPointer; + Request cprocset; void CreateExtensions() { @@ -55,39 +52,39 @@ public override void GlobalSetup() base.GlobalSetup(); CreateExtensions(); - SetupOperation(ref setIfPmRequestBuffer, ref setIfPmRequestBufferPointer, SETIFPM); - SetupOperation(ref myDictSetGetRequestBuffer, ref myDictSetGetRequestBufferPointer, MYDICTSETGET); - SetupOperation(ref ctxnsetBuffer, ref ctxnsetBufferPointer, CTXNSET); - SetupOperation(ref cprocsetBuffer, ref cprocsetBufferPointer, CPROCSET); + SetupOperation(ref setIfPm, SETIFPM); + SetupOperation(ref myDictSetGet, MYDICTSETGET); + SetupOperation(ref ctxnset, CTXNSET); + SetupOperation(ref cprocset, CPROCSET); SlowConsumeMessage("*4\r\n$7\r\nSETIFPM\r\n$1\r\nk\r\n$3\r\nval\r\n$1\r\nv\r\n"u8); SlowConsumeMessage("*4\r\n$9\r\nMYDICTSET\r\n$2\r\nck\r\n$1\r\nf\r\n$1\r\nv\r\n"u8); - SlowConsumeMessage(ctxnsetBuffer); - SlowConsumeMessage(cprocsetBuffer); + SlowConsumeMessage(CTXNSET); + SlowConsumeMessage(CPROCSET); } [Benchmark] public void CustomRawStringCommand() { - _ = session.TryConsumeMessages(setIfPmRequestBufferPointer, setIfPmRequestBuffer.Length); + Send(setIfPm); } [Benchmark] public void CustomObjectCommand() { - _ = session.TryConsumeMessages(myDictSetGetRequestBufferPointer, myDictSetGetRequestBuffer.Length); + Send(myDictSetGet); } [Benchmark] public void CustomTransaction() { - _ = session.TryConsumeMessages(ctxnsetBufferPointer, ctxnsetBuffer.Length); + Send(ctxnset); } [Benchmark] public void CustomProcedure() { - _ = session.TryConsumeMessages(cprocsetBufferPointer, cprocsetBuffer.Length); + Send(cprocset); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/HashObjectOperations.cs b/benchmark/BDN.benchmark/Operations/HashObjectOperations.cs index 0045defb8b..a0080806d6 100644 --- a/benchmark/BDN.benchmark/Operations/HashObjectOperations.cs +++ b/benchmark/BDN.benchmark/Operations/HashObjectOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Operations { @@ -12,83 +13,68 @@ namespace BDN.benchmark.Operations public unsafe class HashObjectOperations : OperationsBase { static ReadOnlySpan HSETDEL => "*4\r\n$4\r\nHSET\r\n$1\r\nf\r\n$1\r\na\r\n$1\r\na\r\n*3\r\n$4\r\nHDEL\r\n$1\r\nf\r\n$1\r\na\r\n"u8; - byte[] hSetDelRequestBuffer; - byte* hSetDelRequestBufferPointer; + Request hSetDel; static ReadOnlySpan HEXISTS => "*3\r\n$7\r\nHEXISTS\r\n$1\r\nf\r\n$1\r\na\r\n"u8; - byte[] hExistsRequestBuffer; - byte* hExistsRequestBufferPointer; + Request hExists; static ReadOnlySpan HGET => "*3\r\n$4\r\nHGET\r\n$1\r\nf\r\n$1\r\na\r\n"u8; - byte[] hGetRequestBuffer; - byte* hGetRequestBufferPointer; + Request hGet; static ReadOnlySpan HGETALL => "*2\r\n$7\r\nHGETALL\r\n$1\r\nf\r\n"u8; - byte[] hGetAllRequestBuffer; - byte* hGetAllRequestBufferPointer; + Request hGetAll; static ReadOnlySpan HINCRBY => "*4\r\n$7\r\nHINCRBY\r\n$1\r\nf\r\n$1\r\nc\r\n$1\r\n1\r\n"u8; - byte[] hIncrbyRequestBuffer; - byte* hIncrbyRequestBufferPointer; + Request hIncrby; static ReadOnlySpan HINCRBYFLOAT => "*4\r\n$12\r\nHINCRBYFLOAT\r\n$1\r\nf\r\n$1\r\nd\r\n$3\r\n1.5\r\n"u8; - byte[] hIncrbyFloatRequestBuffer; - byte* hIncrbyFloatRequestBufferPointer; + Request hIncrbyFloat; static ReadOnlySpan HKEYS => "*2\r\n$5\r\nHKEYS\r\n$1\r\nf\r\n"u8; - byte[] hKeysRequestBuffer; - byte* hKeysRequestBufferPointer; + Request hKeys; static ReadOnlySpan HLEN => "*2\r\n$4\r\nHLEN\r\n$1\r\nf\r\n"u8; - byte[] hLenRequestBuffer; - byte* hLenRequestBufferPointer; + Request hLen; static ReadOnlySpan HMGET => "*4\r\n$5\r\nHMGET\r\n$1\r\nf\r\n$1\r\na\r\n$1\r\nb\r\n"u8; - byte[] hMGetRequestBuffer; - byte* hMGetRequestBufferPointer; + Request hMGet; static ReadOnlySpan HMSET => "*6\r\n$5\r\nHMSET\r\n$1\r\nf\r\n$1\r\na\r\n$1\r\n1\r\n$1\r\nb\r\n$1\r\n2\r\n"u8; - byte[] hMSetRequestBuffer; - byte* hMSetRequestBufferPointer; + Request hMSet; static ReadOnlySpan HRANDFIELD => "*2\r\n$10\r\nHRANDFIELD\r\n$1\r\nf\r\n"u8; - byte[] hRandFieldRequestBuffer; - byte* hRandFieldRequestBufferPointer; + Request hRandField; static ReadOnlySpan HSCAN => "*6\r\n$5\r\nHSCAN\r\n$1\r\nf\r\n$1\r\n0\r\n$5\r\nCOUNT\r\n$1\r\n5\r\n"u8; - byte[] hScanRequestBuffer; - byte* hScanRequestBufferPointer; + Request hScan; static ReadOnlySpan HSETNX => "*4\r\n$6\r\nHSETNX\r\n$1\r\nf\r\n$1\r\nx\r\n$1\r\n1\r\n"u8; - byte[] hSetNxRequestBuffer; - byte* hSetNxRequestBufferPointer; + Request hSetNx; static ReadOnlySpan HSTRLEN => "*3\r\n$7\r\nHSTRLEN\r\n$1\r\nf\r\n$1\r\na\r\n"u8; - byte[] hStrLenRequestBuffer; - byte* hStrLenRequestBufferPointer; + Request hStrLen; static ReadOnlySpan HVALS => "*2\r\n$5\r\nHVALS\r\n$1\r\nf\r\n"u8; - byte[] hValsRequestBuffer; - byte* hValsRequestBufferPointer; + Request hVals; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref hSetDelRequestBuffer, ref hSetDelRequestBufferPointer, HSETDEL); - SetupOperation(ref hExistsRequestBuffer, ref hExistsRequestBufferPointer, HEXISTS); - SetupOperation(ref hGetRequestBuffer, ref hGetRequestBufferPointer, HGET); - SetupOperation(ref hGetAllRequestBuffer, ref hGetAllRequestBufferPointer, HGETALL); - SetupOperation(ref hIncrbyRequestBuffer, ref hIncrbyRequestBufferPointer, HINCRBY); - SetupOperation(ref hIncrbyFloatRequestBuffer, ref hIncrbyFloatRequestBufferPointer, HINCRBYFLOAT); - SetupOperation(ref hKeysRequestBuffer, ref hKeysRequestBufferPointer, HKEYS); - SetupOperation(ref hLenRequestBuffer, ref hLenRequestBufferPointer, HLEN); - SetupOperation(ref hMGetRequestBuffer, ref hMGetRequestBufferPointer, HMGET); - SetupOperation(ref hMSetRequestBuffer, ref hMSetRequestBufferPointer, HMSET); - SetupOperation(ref hRandFieldRequestBuffer, ref hRandFieldRequestBufferPointer, HRANDFIELD); - SetupOperation(ref hScanRequestBuffer, ref hScanRequestBufferPointer, HSCAN); - SetupOperation(ref hSetNxRequestBuffer, ref hSetNxRequestBufferPointer, HSETNX); - SetupOperation(ref hStrLenRequestBuffer, ref hStrLenRequestBufferPointer, HSTRLEN); - SetupOperation(ref hValsRequestBuffer, ref hValsRequestBufferPointer, HVALS); + SetupOperation(ref hSetDel, HSETDEL); + SetupOperation(ref hExists, HEXISTS); + SetupOperation(ref hGet, HGET); + SetupOperation(ref hGetAll, HGETALL); + SetupOperation(ref hIncrby, HINCRBY); + SetupOperation(ref hIncrbyFloat, HINCRBYFLOAT); + SetupOperation(ref hKeys, HKEYS); + SetupOperation(ref hLen, HLEN); + SetupOperation(ref hMGet, HMGET); + SetupOperation(ref hMSet, HMSET); + SetupOperation(ref hRandField, HRANDFIELD); + SetupOperation(ref hScan, HSCAN); + SetupOperation(ref hSetNx, HSETNX); + SetupOperation(ref hStrLen, HSTRLEN); + SetupOperation(ref hVals, HVALS); // Pre-populate data SlowConsumeMessage("*3\r\n$4\r\nHSET\r\n$1\r\nf\r\n$1\r\nb\r\n$1\r\nb\r\n"u8); @@ -99,91 +85,91 @@ public override void GlobalSetup() [Benchmark] public void HSetDel() { - _ = session.TryConsumeMessages(hSetDelRequestBufferPointer, hSetDelRequestBuffer.Length); + Send(hSetDel); } [Benchmark] public void HExists() { - _ = session.TryConsumeMessages(hExistsRequestBufferPointer, hExistsRequestBuffer.Length); + Send(hExists); } [Benchmark] public void HGet() { - _ = session.TryConsumeMessages(hGetRequestBufferPointer, hGetRequestBuffer.Length); + Send(hGet); } [Benchmark] public void HGetAll() { - _ = session.TryConsumeMessages(hGetAllRequestBufferPointer, hGetAllRequestBuffer.Length); + Send(hGetAll); } [Benchmark] public void HIncrby() { - _ = session.TryConsumeMessages(hIncrbyRequestBufferPointer, hIncrbyRequestBuffer.Length); + Send(hIncrby); } [Benchmark] public void HIncrbyFloat() { - _ = session.TryConsumeMessages(hIncrbyFloatRequestBufferPointer, hIncrbyFloatRequestBuffer.Length); + Send(hIncrbyFloat); } [Benchmark] public void HKeys() { - _ = session.TryConsumeMessages(hKeysRequestBufferPointer, hKeysRequestBuffer.Length); + Send(hKeys); } [Benchmark] public void HLen() { - _ = session.TryConsumeMessages(hLenRequestBufferPointer, hLenRequestBuffer.Length); + Send(hLen); } [Benchmark] public void HMGet() { - _ = session.TryConsumeMessages(hMGetRequestBufferPointer, hMGetRequestBuffer.Length); + Send(hMGet); } [Benchmark] public void HMSet() { - _ = session.TryConsumeMessages(hMSetRequestBufferPointer, hMSetRequestBuffer.Length); + Send(hMSet); } [Benchmark] public void HRandField() { - _ = session.TryConsumeMessages(hRandFieldRequestBufferPointer, hRandFieldRequestBuffer.Length); + Send(hRandField); } [Benchmark] public void HScan() { - _ = session.TryConsumeMessages(hScanRequestBufferPointer, hScanRequestBuffer.Length); + Send(hScan); } [Benchmark] public void HSetNx() { - _ = session.TryConsumeMessages(hSetNxRequestBufferPointer, hSetNxRequestBuffer.Length); + Send(hSetNx); } [Benchmark] public void HStrLen() { - _ = session.TryConsumeMessages(hStrLenRequestBufferPointer, hStrLenRequestBuffer.Length); + Send(hStrLen); } [Benchmark] public void HVals() { - _ = session.TryConsumeMessages(hValsRequestBufferPointer, hValsRequestBuffer.Length); + Send(hVals); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/ObjectOperations.cs b/benchmark/BDN.benchmark/Operations/ObjectOperations.cs index 68c44e79a5..cbfdcd351a 100644 --- a/benchmark/BDN.benchmark/Operations/ObjectOperations.cs +++ b/benchmark/BDN.benchmark/Operations/ObjectOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Operations { @@ -12,23 +13,21 @@ namespace BDN.benchmark.Operations public unsafe class ObjectOperations : OperationsBase { static ReadOnlySpan ZADDREM => "*4\r\n$4\r\nZADD\r\n$1\r\nc\r\n$1\r\n1\r\n$1\r\nc\r\n*3\r\n$4\r\nZREM\r\n$1\r\nc\r\n$1\r\nc\r\n"u8; - byte[] zAddRemRequestBuffer; - byte* zAddRemRequestBufferPointer; + Request zAddRem; static ReadOnlySpan LPUSHPOP => "*3\r\n$5\r\nLPUSH\r\n$1\r\nd\r\n$1\r\ne\r\n*2\r\n$4\r\nLPOP\r\n$1\r\nd\r\n"u8; - byte[] lPushPopRequestBuffer; - byte* lPushPopRequestBufferPointer; + Request lPushPop; static ReadOnlySpan SADDREM => "*3\r\n$4\r\nSADD\r\n$1\r\ne\r\n$1\r\na\r\n*3\r\n$4\r\nSREM\r\n$1\r\ne\r\n$1\r\na\r\n"u8; - byte[] sAddRemRequestBuffer; - byte* sAddRemRequestBufferPointer; + Request sAddRem; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref zAddRemRequestBuffer, ref zAddRemRequestBufferPointer, ZADDREM); - SetupOperation(ref lPushPopRequestBuffer, ref lPushPopRequestBufferPointer, LPUSHPOP); - SetupOperation(ref sAddRemRequestBuffer, ref sAddRemRequestBufferPointer, SADDREM); + + SetupOperation(ref zAddRem, ZADDREM); + SetupOperation(ref lPushPop, LPUSHPOP); + SetupOperation(ref sAddRem, SADDREM); // Pre-populate data SlowConsumeMessage("*4\r\n$4\r\nZADD\r\n$1\r\nc\r\n$1\r\n1\r\n$1\r\nd\r\n"u8); @@ -39,19 +38,19 @@ public override void GlobalSetup() [Benchmark] public void ZAddRem() { - _ = session.TryConsumeMessages(zAddRemRequestBufferPointer, zAddRemRequestBuffer.Length); + Send(zAddRem); } [Benchmark] public void LPushPop() { - _ = session.TryConsumeMessages(lPushPopRequestBufferPointer, lPushPopRequestBuffer.Length); + Send(lPushPop); } [Benchmark] public void SAddRem() { - _ = session.TryConsumeMessages(sAddRemRequestBufferPointer, sAddRemRequestBuffer.Length); + Send(sAddRem); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/OperationsBase.cs b/benchmark/BDN.benchmark/Operations/OperationsBase.cs index 17ab08a6a9..8677331de3 100644 --- a/benchmark/BDN.benchmark/Operations/OperationsBase.cs +++ b/benchmark/BDN.benchmark/Operations/OperationsBase.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System.Runtime.CompilerServices; +using System.Text; using BenchmarkDotNet.Attributes; using Embedded.server; using Garnet.server; @@ -97,25 +98,42 @@ public virtual void GlobalCleanup() server.Dispose(); } - protected void Send(byte[] requestBuffer, byte* requestBufferPointer, int length) + protected void Send(Request request) { - _ = session.TryConsumeMessages(requestBufferPointer, length); + _ = session.TryConsumeMessages(request.bufferPtr, request.buffer.Length); } - protected void SetupOperation(ref byte[] requestBuffer, ref byte* requestBufferPointer, ReadOnlySpan operation) + protected unsafe void SetupOperation(ref Request request, ReadOnlySpan operation, int batchSize = batchSize) { - requestBuffer = GC.AllocateArray(operation.Length * batchSize, pinned: true); - requestBufferPointer = (byte*)Unsafe.AsPointer(ref requestBuffer[0]); + request.buffer = GC.AllocateArray(operation.Length * batchSize, pinned: true); + request.bufferPtr = (byte*)Unsafe.AsPointer(ref request.buffer[0]); for (int i = 0; i < batchSize; i++) - operation.CopyTo(new Span(requestBuffer).Slice(i * operation.Length)); + operation.CopyTo(new Span(request.buffer).Slice(i * operation.Length)); + } + + protected unsafe void SetupOperation(ref Request request, string operation, int batchSize = batchSize) + { + request.buffer = GC.AllocateUninitializedArray(operation.Length * batchSize, pinned: true); + for (var i = 0; i < batchSize; i++) + { + var start = i * operation.Length; + Encoding.UTF8.GetBytes(operation, request.buffer.AsSpan().Slice(start, operation.Length)); + } + request.bufferPtr = (byte*)Unsafe.AsPointer(ref request.buffer[0]); + } + + protected unsafe void SetupOperation(ref Request request, List operationBytes) + { + request.buffer = GC.AllocateUninitializedArray(operationBytes.Count, pinned: true); + operationBytes.CopyTo(request.buffer); + request.bufferPtr = (byte*)Unsafe.AsPointer(ref request.buffer[0]); } protected void SlowConsumeMessage(ReadOnlySpan message) { - var buffer = GC.AllocateArray(message.Length, pinned: true); - var bufferPointer = (byte*)Unsafe.AsPointer(ref buffer[0]); - message.CopyTo(new Span(buffer)); - _ = session.TryConsumeMessages(bufferPointer, buffer.Length); + Request request = default; + SetupOperation(ref request, message, 1); + Send(request); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/RawStringOperations.cs b/benchmark/BDN.benchmark/Operations/RawStringOperations.cs index 16592ffa95..ac4cf31db5 100644 --- a/benchmark/BDN.benchmark/Operations/RawStringOperations.cs +++ b/benchmark/BDN.benchmark/Operations/RawStringOperations.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Operations { @@ -12,58 +13,48 @@ namespace BDN.benchmark.Operations public unsafe class RawStringOperations : OperationsBase { static ReadOnlySpan SET => "*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n"u8; - byte[] setRequestBuffer; - byte* setRequestBufferPointer; + Request set; static ReadOnlySpan SETEX => "*4\r\n$5\r\nSETEX\r\n$1\r\nd\r\n$1\r\n9\r\n$1\r\nd\r\n"u8; - byte[] setexRequestBuffer; - byte* setexRequestBufferPointer; + Request setex; static ReadOnlySpan SETNX => "*4\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n$2\r\nNX\r\n"u8; - byte[] setnxRequestBuffer; - byte* setnxRequestBufferPointer; + Request setnx; static ReadOnlySpan SETXX => "*4\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n$2\r\nXX\r\n"u8; - byte[] setxxRequestBuffer; - byte* setxxRequestBufferPointer; + Request setxx; static ReadOnlySpan GETNF => "*2\r\n$3\r\nGET\r\n$1\r\nb\r\n"u8; - byte[] getnfRequestBuffer; - byte* getnfRequestBufferPointer; + Request getnf; static ReadOnlySpan GETF => "*2\r\n$3\r\nGET\r\n$1\r\na\r\n"u8; - byte[] getfRequestBuffer; - byte* getfRequestBufferPointer; + Request getf; static ReadOnlySpan INCR => "*2\r\n$4\r\nINCR\r\n$1\r\ni\r\n"u8; - byte[] incrRequestBuffer; - byte* incrRequestBufferPointer; + Request incr; static ReadOnlySpan DECR => "*2\r\n$4\r\nDECR\r\n$1\r\nj\r\n"u8; - byte[] decrRequestBuffer; - byte* decrRequestBufferPointer; + Request decr; static ReadOnlySpan INCRBY => "*3\r\n$6\r\nINCRBY\r\n$1\r\nk\r\n$10\r\n1234567890\r\n"u8; - byte[] incrbyRequestBuffer; - byte* incrbyRequestBufferPointer; + Request incrby; static ReadOnlySpan DECRBY => "*3\r\n$6\r\nDECRBY\r\n$1\r\nl\r\n$10\r\n1234567890\r\n"u8; - byte[] decrbyRequestBuffer; - byte* decrbyRequestBufferPointer; + Request decrby; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref setRequestBuffer, ref setRequestBufferPointer, SET); - SetupOperation(ref setexRequestBuffer, ref setexRequestBufferPointer, SETEX); - SetupOperation(ref setnxRequestBuffer, ref setnxRequestBufferPointer, SETNX); - SetupOperation(ref setxxRequestBuffer, ref setxxRequestBufferPointer, SETXX); - SetupOperation(ref getfRequestBuffer, ref getfRequestBufferPointer, GETF); - SetupOperation(ref getnfRequestBuffer, ref getnfRequestBufferPointer, GETNF); - SetupOperation(ref incrRequestBuffer, ref incrRequestBufferPointer, INCR); - SetupOperation(ref decrRequestBuffer, ref decrRequestBufferPointer, DECR); - SetupOperation(ref incrbyRequestBuffer, ref incrbyRequestBufferPointer, INCRBY); - SetupOperation(ref decrbyRequestBuffer, ref decrbyRequestBufferPointer, DECRBY); + SetupOperation(ref set, SET); + SetupOperation(ref setex, SETEX); + SetupOperation(ref setnx, SETNX); + SetupOperation(ref setxx, SETXX); + SetupOperation(ref getf, GETF); + SetupOperation(ref getnf, GETNF); + SetupOperation(ref incr, INCR); + SetupOperation(ref decr, DECR); + SetupOperation(ref incrby, INCRBY); + SetupOperation(ref decrby, DECRBY); // Pre-populate data SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n"u8); @@ -76,61 +67,61 @@ public override void GlobalSetup() [Benchmark] public void Set() { - Send(setRequestBuffer, setRequestBufferPointer, setRequestBuffer.Length); + Send(set); } [Benchmark] public void SetEx() { - Send(setexRequestBuffer, setexRequestBufferPointer, setexRequestBuffer.Length); + Send(setex); } [Benchmark] public void SetNx() { - Send(setnxRequestBuffer, setnxRequestBufferPointer, setnxRequestBuffer.Length); + Send(setnx); } [Benchmark] public void SetXx() { - Send(setxxRequestBuffer, setxxRequestBufferPointer, setxxRequestBuffer.Length); + Send(setxx); } [Benchmark] public void GetFound() { - Send(getfRequestBuffer, getfRequestBufferPointer, getfRequestBuffer.Length); + Send(getf); } [Benchmark] public void GetNotFound() { - Send(getnfRequestBuffer, getnfRequestBufferPointer, getnfRequestBuffer.Length); + Send(getnf); } [Benchmark] public void Increment() { - Send(incrRequestBuffer, incrRequestBufferPointer, incrRequestBuffer.Length); + Send(incr); } [Benchmark] public void Decrement() { - Send(decrRequestBuffer, decrRequestBufferPointer, decrRequestBuffer.Length); + Send(decr); } [Benchmark] public void IncrementBy() { - Send(incrbyRequestBuffer, incrbyRequestBufferPointer, incrbyRequestBuffer.Length); + Send(incrby); } [Benchmark] public void DecrementBy() { - Send(decrbyRequestBuffer, decrbyRequestBufferPointer, decrbyRequestBuffer.Length); + Send(decrby); } } } \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Operations/ScriptOperations.cs b/benchmark/BDN.benchmark/Operations/ScriptOperations.cs index 26436bfea9..8a6cd34f08 100644 --- a/benchmark/BDN.benchmark/Operations/ScriptOperations.cs +++ b/benchmark/BDN.benchmark/Operations/ScriptOperations.cs @@ -5,6 +5,7 @@ using System.Security.Cryptography; using System.Text; using BenchmarkDotNet.Attributes; +using Embedded.server; namespace BDN.benchmark.Operations { @@ -133,81 +134,62 @@ public unsafe class ScriptOperations : OperationsBase "; static ReadOnlySpan SCRIPT_LOAD => "*3\r\n$6\r\nSCRIPT\r\n$4\r\nLOAD\r\n$8\r\nreturn 1\r\n"u8; - byte[] scriptLoadRequestBuffer; - byte* scriptLoadRequestBufferPointer; + Request scriptLoad; static ReadOnlySpan SCRIPT_EXISTS_LOADED => "*3\r\n$6\r\nSCRIPT\r\n$4\r\nLOAD\r\n$10\r\nreturn nil\r\n"u8; static ReadOnlySpan SCRIPT_EXISTS_TRUE => "*3\r\n$6\r\nSCRIPT\r\n$6\r\nEXISTS\r\n$40\r\n79cefb99366d8809d2e903c5f36f50c2b731913f\r\n"u8; - byte[] scriptExistsTrueRequestBuffer; - byte* scriptExistsTrueRequestBufferPointer; + Request scriptExistsTrue; static ReadOnlySpan SCRIPT_EXISTS_FALSE => "*3\r\n$6\r\nSCRIPT\r\n$6\r\nEXISTS\r\n$40\r\n0000000000000000000000000000000000000000\r\n"u8; - byte[] scriptExistsFalseRequestBuffer; - byte* scriptExistsFalseRequestBufferPointer; + Request scriptExistsFalse; static ReadOnlySpan EVAL => "*3\r\n$4\r\nEVAL\r\n$10\r\nreturn nil\r\n$1\r\n0\r\n"u8; - byte[] evalRequestBuffer; - byte* evalRequestBufferPointer; + Request eval; static ReadOnlySpan EVALSHA => "*3\r\n$7\r\nEVALSHA\r\n$40\r\n79cefb99366d8809d2e903c5f36f50c2b731913f\r\n$1\r\n0\r\n"u8; - byte[] evalShaRequestBuffer; - byte* evalShaRequestBufferPointer; + Request evalSha; - byte[] evalShaSmallScriptBuffer; - byte* evalShaSmallScriptBufferPointer; - - byte[] evalShaLargeScriptBuffer; - byte* evalShaLargeScriptBufferPointer; + Request evalShaSmallScript; + Request evalShaLargeScript; static ReadOnlySpan ARRAY_RETURN => "*3\r\n$4\r\nEVAL\r\n$22\r\nreturn {1, 2, 3, 4, 5}\r\n$1\r\n0\r\n"u8; - byte[] arrayReturnRequestBuffer; - byte* arrayReturnRequestBufferPointer; + Request arrayReturn; public override void GlobalSetup() { base.GlobalSetup(); - SetupOperation(ref scriptLoadRequestBuffer, ref scriptLoadRequestBufferPointer, SCRIPT_LOAD); - - byte[] scriptExistsLoadedBuffer = null; - byte* scriptExistsLoadedPointer = null; - SetupOperation(ref scriptExistsLoadedBuffer, ref scriptExistsLoadedPointer, SCRIPT_EXISTS_LOADED); - _ = session.TryConsumeMessages(scriptExistsLoadedPointer, scriptExistsLoadedBuffer.Length); - SetupOperation(ref scriptExistsTrueRequestBuffer, ref scriptExistsTrueRequestBufferPointer, SCRIPT_EXISTS_TRUE); - - SetupOperation(ref scriptExistsFalseRequestBuffer, ref scriptExistsFalseRequestBufferPointer, SCRIPT_EXISTS_FALSE); - - SetupOperation(ref evalRequestBuffer, ref evalRequestBufferPointer, EVAL); + SetupOperation(ref scriptLoad, SCRIPT_LOAD); - SetupOperation(ref evalShaRequestBuffer, ref evalShaRequestBufferPointer, EVALSHA); + Request scriptExistsLoaded = default; + SetupOperation(ref scriptExistsLoaded, SCRIPT_EXISTS_LOADED, 1); + Send(scriptExistsLoaded); - SetupOperation(ref arrayReturnRequestBuffer, ref arrayReturnRequestBufferPointer, ARRAY_RETURN); + SetupOperation(ref scriptExistsTrue, SCRIPT_EXISTS_TRUE); + SetupOperation(ref scriptExistsFalse, SCRIPT_EXISTS_FALSE); + SetupOperation(ref eval, EVAL); + SetupOperation(ref evalSha, EVALSHA); + SetupOperation(ref arrayReturn, ARRAY_RETURN); // Setup small script var loadSmallScript = $"*3\r\n$6\r\nSCRIPT\r\n$4\r\nLOAD\r\n${SmallScriptText.Length}\r\n{SmallScriptText}\r\n"; var loadSmallScriptBytes = Encoding.UTF8.GetBytes(loadSmallScript); fixed (byte* loadPtr = loadSmallScriptBytes) { - _ = session.TryConsumeMessages(loadPtr, loadSmallScriptBytes.Length); + Send(new Request { buffer = loadSmallScriptBytes, bufferPtr = loadPtr }); } var smallScriptHash = string.Join("", SHA1.HashData(Encoding.UTF8.GetBytes(SmallScriptText)).Select(static x => x.ToString("x2"))); - var evalShaSmallScript = $"*4\r\n$7\r\nEVALSHA\r\n$40\r\n{smallScriptHash}\r\n$1\r\n1\r\n$3\r\nfoo\r\n"; - evalShaSmallScriptBuffer = GC.AllocateUninitializedArray(evalShaSmallScript.Length * batchSize, pinned: true); - for (var i = 0; i < batchSize; i++) - { - var start = i * evalShaSmallScript.Length; - Encoding.UTF8.GetBytes(evalShaSmallScript, evalShaSmallScriptBuffer.AsSpan().Slice(start, evalShaSmallScript.Length)); - } - evalShaSmallScriptBufferPointer = (byte*)Unsafe.AsPointer(ref evalShaSmallScriptBuffer[0]); + var evalShaSmallScriptStr = $"*4\r\n$7\r\nEVALSHA\r\n$40\r\n{smallScriptHash}\r\n$1\r\n1\r\n$3\r\nfoo\r\n"; + SetupOperation(ref evalShaSmallScript, evalShaSmallScriptStr); // Setup large script var loadLargeScript = $"*3\r\n$6\r\nSCRIPT\r\n$4\r\nLOAD\r\n${LargeScriptText.Length}\r\n{LargeScriptText}\r\n"; var loadLargeScriptBytes = Encoding.UTF8.GetBytes(loadLargeScript); fixed (byte* loadPtr = loadLargeScriptBytes) { - _ = session.TryConsumeMessages(loadPtr, loadLargeScriptBytes.Length); + Send(new Request { buffer = loadLargeScriptBytes, bufferPtr = loadPtr }); } var largeScriptHash = string.Join("", SHA1.HashData(Encoding.UTF8.GetBytes(LargeScriptText)).Select(static x => x.ToString("x2"))); @@ -231,57 +213,55 @@ public override void GlobalSetup() var asBytes = Encoding.UTF8.GetBytes(evalShaLargeScript); largeScriptEvals.AddRange(asBytes); } - evalShaLargeScriptBuffer = GC.AllocateUninitializedArray(largeScriptEvals.Count, pinned: true); - largeScriptEvals.CopyTo(evalShaLargeScriptBuffer); - evalShaLargeScriptBufferPointer = (byte*)Unsafe.AsPointer(ref evalShaLargeScriptBuffer[0]); + SetupOperation(ref evalShaLargeScript, largeScriptEvals); } [Benchmark] public void ScriptLoad() { - _ = session.TryConsumeMessages(scriptLoadRequestBufferPointer, scriptLoadRequestBuffer.Length); + Send(scriptLoad); } [Benchmark] public void ScriptExistsTrue() { - _ = session.TryConsumeMessages(scriptExistsTrueRequestBufferPointer, scriptExistsTrueRequestBuffer.Length); + Send(scriptExistsTrue); } [Benchmark] public void ScriptExistsFalse() { - _ = session.TryConsumeMessages(scriptExistsFalseRequestBufferPointer, scriptExistsFalseRequestBuffer.Length); + Send(scriptExistsFalse); } [Benchmark] public void Eval() { - _ = session.TryConsumeMessages(evalRequestBufferPointer, evalRequestBuffer.Length); + Send(eval); } [Benchmark] public void EvalSha() { - _ = session.TryConsumeMessages(evalShaRequestBufferPointer, evalShaRequestBuffer.Length); + Send(evalSha); } [Benchmark] public void SmallScript() { - _ = session.TryConsumeMessages(evalShaSmallScriptBufferPointer, evalShaSmallScriptBuffer.Length); + Send(evalShaSmallScript); } [Benchmark] public void LargeScript() { - _ = session.TryConsumeMessages(evalShaLargeScriptBufferPointer, evalShaLargeScriptBuffer.Length); + Send(evalShaLargeScript); } [Benchmark] public void ArrayReturn() { - _ = session.TryConsumeMessages(arrayReturnRequestBufferPointer, arrayReturnRequestBuffer.Length); + Send(arrayReturn); } } } \ No newline at end of file diff --git a/playground/Embedded.perftest/Embedded.perftest.csproj b/playground/Embedded.perftest/Embedded.perftest.csproj index 1bb09ceed3..9ac00ea182 100644 --- a/playground/Embedded.perftest/Embedded.perftest.csproj +++ b/playground/Embedded.perftest/Embedded.perftest.csproj @@ -10,10 +10,11 @@ - - - - + + + + + @@ -28,4 +29,8 @@ + + + +