diff --git a/benchmark/BDN.benchmark/BDN.benchmark.csproj b/benchmark/BDN.benchmark/BDN.benchmark.csproj
index d8880a2e8a..2965fbcf83 100644
--- a/benchmark/BDN.benchmark/BDN.benchmark.csproj
+++ b/benchmark/BDN.benchmark/BDN.benchmark.csproj
@@ -20,11 +20,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/benchmark/BDN.benchmark/Cluster/ClusterContext.cs b/benchmark/BDN.benchmark/Cluster/ClusterContext.cs
index 243264acfe..4215e0da68 100644
--- a/benchmark/BDN.benchmark/Cluster/ClusterContext.cs
+++ b/benchmark/BDN.benchmark/Cluster/ClusterContext.cs
@@ -1,35 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text;
+using BDN.benchmark.CustomProcs;
using Embedded.perftest;
using Garnet.common;
using Garnet.server;
namespace BDN.benchmark.Cluster
{
- public unsafe struct Request
- {
- public byte[] buffer;
- public byte* ptr;
-
- public Request(int size)
- {
- buffer = GC.AllocateArray(size, pinned: true);
- ptr = (byte*)Unsafe.AsPointer(ref buffer[0]);
- }
- }
-
- public unsafe class ClusterContext
+ unsafe class ClusterContext
{
EmbeddedRespServer server;
RespServerSession session;
- BenchUtils benchUtils = new();
-
- private readonly int Port = 7000;
+ readonly BenchUtils benchUtils = new();
+ readonly int port = 7000;
- public ReadOnlySpan keyTag => "{0}"u8;
+ public static ReadOnlySpan keyTag => "{0}"u8;
public Request[] singleGetSet;
public Request[] singleMGetMSet;
public Request singleCPBSET;
@@ -40,18 +28,20 @@ public void Dispose()
server.Dispose();
}
- public void SetupSingleInstance(bool enableCluster = true)
+ public void SetupSingleInstance(bool disableSlotVerification = false)
{
var opt = new GarnetServerOptions
{
QuietMode = true,
- EnableCluster = enableCluster,
- Port = Port,
+ EnableCluster = !disableSlotVerification,
+ Port = port,
CleanClusterConfig = true,
};
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ opt.CheckpointDir = "/tmp";
server = new EmbeddedRespServer(opt);
session = server.GetRespSession();
- server.Register.NewTransactionProc(CustomProcSetBench.CommandName, () => new CustomProcSetBench(), new RespCommandsInfo { Arity = CustomProcSetBench.Arity });
+ _ = server.Register.NewTransactionProc(CustomProcSet.CommandName, () => new CustomProcSet(), new RespCommandsInfo { Arity = CustomProcSet.Arity });
}
public void AddSlotRange(List<(int, int)> slotRanges)
@@ -66,7 +56,7 @@ public void AddSlotRange(List<(int, int)> slotRanges)
}
}
- public void CreateGetSet(int keySize = 8, int valueSize = 32, int batchSize = 128)
+ public void CreateGetSet(int keySize = 8, int valueSize = 32, int batchSize = 100)
{
var pairs = new (byte[], byte[])[batchSize];
for (var i = 0; i < batchSize; i++)
@@ -78,7 +68,7 @@ public void CreateGetSet(int keySize = 8, int valueSize = 32, int batchSize = 12
benchUtils.RandomBytes(ref pairs[i].Item2);
}
- var setByteCount = batchSize * ("*2\r\n$3\r\nSET\r\n"u8.Length + (1 + NumUtils.NumDigits(keySize) + 2 + keySize + 2) + (1 + NumUtils.NumDigits(valueSize) + 2 + valueSize + 2));
+ var setByteCount = batchSize * ("*2\r\n$3\r\nSET\r\n"u8.Length + 1 + NumUtils.NumDigits(keySize) + 2 + keySize + 2 + 1 + NumUtils.NumDigits(valueSize) + 2 + valueSize + 2);
var setReq = new Request(setByteCount);
var curr = setReq.ptr;
var end = curr + setReq.buffer.Length;
@@ -103,7 +93,7 @@ public void CreateGetSet(int keySize = 8, int valueSize = 32, int batchSize = 12
singleGetSet = [getReq, setReq];
}
- public void CreateMGetMSet(int keySize = 8, int valueSize = 32, int batchSize = 128)
+ public void CreateMGetMSet(int keySize = 8, int valueSize = 32, int batchSize = 100)
{
var pairs = new (byte[], byte[])[batchSize];
for (var i = 0; i < batchSize; i++)
@@ -127,14 +117,14 @@ public void CreateMGetMSet(int keySize = 8, int valueSize = 32, int batchSize =
for (var i = 0; i < batchSize; i++)
_ = RespWriteUtils.WriteBulkString(pairs[i].Item1, ref curr, end);
- var mSetHeaderSize = 1 + NumUtils.NumDigits(1 + batchSize * 2) + 2 + "$4\r\nMSET\r\n"u8.Length;
+ var mSetHeaderSize = 1 + NumUtils.NumDigits(1 + (batchSize * 2)) + 2 + "$4\r\nMSET\r\n"u8.Length;
var setRespSize = 1 + NumUtils.NumDigits(keySize) + 2 + keySize + 2 + 1 + NumUtils.NumDigits(valueSize) + 2 + valueSize + 2;
var mSetByteCount = mSetHeaderSize + (batchSize * setRespSize);
var mSetReq = new Request(mSetByteCount);
curr = mSetReq.ptr;
end = curr + mSetReq.buffer.Length;
- _ = RespWriteUtils.WriteArrayLength(1 + batchSize * 2, ref curr, end);
+ _ = RespWriteUtils.WriteArrayLength(1 + (batchSize * 2), ref curr, end);
_ = RespWriteUtils.WriteBulkString("MSET"u8, ref curr, end);
for (var i = 0; i < batchSize; i++)
{
@@ -144,7 +134,7 @@ public void CreateMGetMSet(int keySize = 8, int valueSize = 32, int batchSize =
singleMGetMSet = [mGetReq, mSetReq];
}
- public void CreateCPBSET(int keySize = 8, int valueSize = 32, int batchSize = 128)
+ public void CreateCPBSET(int keySize = 8, int batchSize = 100)
{
var keys = new byte[8][];
for (var i = 0; i < 8; i++)
diff --git a/benchmark/BDN.benchmark/Cluster/RespClusterMigrateBench.cs b/benchmark/BDN.benchmark/Cluster/ClusterMigrate.cs
similarity index 82%
rename from benchmark/BDN.benchmark/Cluster/RespClusterMigrateBench.cs
rename to benchmark/BDN.benchmark/Cluster/ClusterMigrate.cs
index 5da448d03c..8461e621b3 100644
--- a/benchmark/BDN.benchmark/Cluster/RespClusterMigrateBench.cs
+++ b/benchmark/BDN.benchmark/Cluster/ClusterMigrate.cs
@@ -8,10 +8,14 @@
namespace BDN.benchmark.Cluster
{
+ ///
+ /// Cluster migrate benchmark
+ ///
[MemoryDiagnoser]
- public unsafe class RespClusterMigrateBench
+ public unsafe class ClusterMigrate
{
ClusterContext cc;
+
[GlobalSetup]
public void GlobalSetup()
{
@@ -44,7 +48,7 @@ public void GlobalSetup()
cc.Consume(req, gossipReq.Length);
// Set slot to migrating state
- var slot = HashSlotUtils.HashSlot(cc.keyTag.ToArray());
+ var slot = HashSlotUtils.HashSlot(ClusterContext.keyTag.ToArray());
SetSlot(slot, "MIGRATING", config.LocalNodeId);
}
@@ -58,12 +62,12 @@ private void SetSlot(int slot, string state, string nodeId)
var setSlotReq = new Request(reqBytes);
var curr = setSlotReq.ptr;
var end = curr + setSlotReq.buffer.Length;
- RespWriteUtils.WriteArrayLength(5, ref curr, end);
- RespWriteUtils.WriteBulkString("CLUSTER"u8, ref curr, end);
- RespWriteUtils.WriteBulkString("SETSLOT"u8, ref curr, end);
- RespWriteUtils.WriteIntegerAsBulkString(slot, ref curr, end);
- RespWriteUtils.WriteBulkString(Encoding.ASCII.GetBytes(state), ref curr, end);
- RespWriteUtils.WriteBulkString(Encoding.ASCII.GetBytes(nodeId), ref curr, end);
+ _ = RespWriteUtils.WriteArrayLength(5, ref curr, end);
+ _ = RespWriteUtils.WriteBulkString("CLUSTER"u8, ref curr, end);
+ _ = RespWriteUtils.WriteBulkString("SETSLOT"u8, ref curr, end);
+ _ = RespWriteUtils.WriteIntegerAsBulkString(slot, ref curr, end);
+ _ = RespWriteUtils.WriteBulkString(Encoding.ASCII.GetBytes(state), ref curr, end);
+ _ = RespWriteUtils.WriteBulkString(Encoding.ASCII.GetBytes(nodeId), ref curr, end);
cc.Consume(setSlotReq.ptr, setSlotReq.buffer.Length);
}
diff --git a/benchmark/BDN.benchmark/Cluster/RespClusterBench.cs b/benchmark/BDN.benchmark/Cluster/ClusterOperations.cs
similarity index 73%
rename from benchmark/BDN.benchmark/Cluster/RespClusterBench.cs
rename to benchmark/BDN.benchmark/Cluster/ClusterOperations.cs
index f13a6f0df9..3602060a12 100644
--- a/benchmark/BDN.benchmark/Cluster/RespClusterBench.cs
+++ b/benchmark/BDN.benchmark/Cluster/ClusterOperations.cs
@@ -5,17 +5,34 @@
namespace BDN.benchmark.Cluster
{
+ ///
+ /// Cluster operations benchmark
+ ///
[MemoryDiagnoser]
- public unsafe class RespClusterBench
+ public unsafe class ClusterOperations
{
- protected bool enableCluster = true;
+ ///
+ /// Cluster parameters
+ ///
+ [ParamsSource(nameof(ClusterParamsProvider))]
+ public ClusterParams Params { get; set; }
+
+ ///
+ /// Cluster parameters provider
+ ///
+ public IEnumerable ClusterParamsProvider()
+ {
+ yield return new(false);
+ yield return new(true);
+ }
+
ClusterContext cc;
[GlobalSetup]
public virtual void GlobalSetup()
{
cc = new ClusterContext();
- cc.SetupSingleInstance(enableCluster);
+ cc.SetupSingleInstance(Params.disableSlotVerification);
cc.AddSlotRange([(0, 16383)]);
cc.CreateGetSet();
cc.CreateMGetMSet();
diff --git a/benchmark/BDN.benchmark/Cluster/ClusterParams.cs b/benchmark/BDN.benchmark/Cluster/ClusterParams.cs
new file mode 100644
index 0000000000..a47a86568b
--- /dev/null
+++ b/benchmark/BDN.benchmark/Cluster/ClusterParams.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+namespace BDN.benchmark.Cluster
+{
+ ///
+ /// Cluster parameters
+ ///
+ public struct ClusterParams
+ {
+ ///
+ /// Whether to disable slot verification
+ ///
+ public bool disableSlotVerification;
+
+ ///
+ /// Constructor
+ ///
+ public ClusterParams(bool disableSlotVerification)
+ {
+ this.disableSlotVerification = disableSlotVerification;
+ }
+
+ ///
+ /// String representation
+ ///
+ public override string ToString()
+ {
+ if (!disableSlotVerification)
+ return "None";
+
+ var ret = "";
+ if (disableSlotVerification)
+ ret += "DSV";
+ return ret;
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Cluster/Request.cs b/benchmark/BDN.benchmark/Cluster/Request.cs
new file mode 100644
index 0000000000..e4de839ca1
--- /dev/null
+++ b/benchmark/BDN.benchmark/Cluster/Request.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using System.Runtime.CompilerServices;
+
+namespace BDN.benchmark.Cluster
+{
+ ///
+ /// Request struct
+ ///
+ unsafe struct Request
+ {
+ public byte[] buffer;
+ public byte* ptr;
+
+ public Request(int size)
+ {
+ buffer = GC.AllocateArray(size, pinned: true);
+ ptr = (byte*)Unsafe.AsPointer(ref buffer[0]);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Cluster/RespClusterDisableSlotVerificationBench.cs b/benchmark/BDN.benchmark/Cluster/RespClusterDisableSlotVerificationBench.cs
deleted file mode 100644
index 19899c8097..0000000000
--- a/benchmark/BDN.benchmark/Cluster/RespClusterDisableSlotVerificationBench.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-using BenchmarkDotNet.Attributes;
-
-namespace BDN.benchmark.Cluster
-{
- [MemoryDiagnoser]
- public unsafe class RespClusterDisableSlotVerificationBench : RespClusterBench
- {
- public override void GlobalSetup()
- {
- enableCluster = false;
- base.GlobalSetup();
- }
- }
-}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/CustomProc/SetGetCustomProc.cs b/benchmark/BDN.benchmark/CustomProcs/CustomProcSet.cs
similarity index 92%
rename from benchmark/BDN.benchmark/CustomProc/SetGetCustomProc.cs
rename to benchmark/BDN.benchmark/CustomProcs/CustomProcSet.cs
index 92a5360047..d602f0d6c4 100644
--- a/benchmark/BDN.benchmark/CustomProc/SetGetCustomProc.cs
+++ b/benchmark/BDN.benchmark/CustomProcs/CustomProcSet.cs
@@ -5,9 +5,12 @@
using Garnet.server;
using Tsavorite.core;
-namespace BDN.benchmark
+namespace BDN.benchmark.CustomProcs
{
- sealed class CustomProcSetBench : CustomTransactionProcedure
+ ///
+ /// Custom procedure to set values
+ ///
+ sealed class CustomProcSet : CustomTransactionProcedure
{
///
/// Parameters including command
diff --git a/benchmark/BDN.benchmark/Geo/GeoHash.cs b/benchmark/BDN.benchmark/Geo/GeoHash.cs
new file mode 100644
index 0000000000..72d407b0d3
--- /dev/null
+++ b/benchmark/BDN.benchmark/Geo/GeoHash.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using BenchmarkDotNet.Attributes;
+
+namespace BDN.benchmark.Geo
+{
+ ///
+ /// Benchmark for GeoHash
+ ///
+ [MemoryDiagnoser]
+ public class GeoHash
+ {
+ private const double Latitude = 47.642219912251285;
+ private const double Longitude = -122.14205560231471;
+
+ private const long GeoHashInteger = 1557413161902764;
+
+ [Benchmark]
+ public long GeoToLongValue() => Garnet.server.GeoHash.GeoToLongValue(Latitude, Longitude);
+
+ [Benchmark]
+ public (double, double) GetCoordinatesFromLong() => Garnet.server.GeoHash.GetCoordinatesFromLong(GeoHashInteger);
+
+ [Benchmark]
+ public string GetGeoHashCode() => Garnet.server.GeoHash.GetGeoHashCode(GeoHashInteger);
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/GeoHashBenchmarks.cs b/benchmark/BDN.benchmark/GeoHashBenchmarks.cs
deleted file mode 100644
index 0f9ac9aff6..0000000000
--- a/benchmark/BDN.benchmark/GeoHashBenchmarks.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-
-using BenchmarkDotNet.Attributes;
-
-using Garnet.server;
-
-namespace BDN.benchmark
-{
- [MemoryDiagnoser]
- public class GeoHashBenchmarks
- {
- private const double Latitude = 47.642219912251285;
- private const double Longitude = -122.14205560231471;
-
- private const long GeoHashInteger = 1557413161902764;
-
- [Benchmark]
- public long GeoToLongValue() => GeoHash.GeoToLongValue(Latitude, Longitude);
-
- [Benchmark]
- public (double, double) GetCoordinatesFromLong() => GeoHash.GetCoordinatesFromLong(GeoHashInteger);
-
- [Benchmark]
- public string GetGeoHashCode() => GeoHash.GetGeoHashCode(GeoHashInteger);
- }
-}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Resp/RespLuaRunnerStress.cs b/benchmark/BDN.benchmark/Lua/Lua.cs
similarity index 81%
rename from benchmark/BDN.benchmark/Resp/RespLuaRunnerStress.cs
rename to benchmark/BDN.benchmark/Lua/Lua.cs
index a766d729dc..08b3fa3f67 100644
--- a/benchmark/BDN.benchmark/Resp/RespLuaRunnerStress.cs
+++ b/benchmark/BDN.benchmark/Lua/Lua.cs
@@ -4,10 +4,13 @@
using BenchmarkDotNet.Attributes;
using Garnet.server;
-namespace BDN.benchmark.Resp
+namespace BDN.benchmark.Lua
{
+ ///
+ /// Benchmark for Lua
+ ///
[MemoryDiagnoser]
- public unsafe class RespLuaRunnerStress
+ public unsafe class Lua
{
LuaRunner r1, r2, r3, r4;
readonly string[] keys = ["key1"];
@@ -35,19 +38,19 @@ public void GlobalCleanup()
}
[Benchmark]
- public void BasicLua1()
+ public void Lua1()
=> r1.Run();
[Benchmark]
- public void BasicLua2()
+ public void Lua2()
=> r2.Run();
[Benchmark]
- public void BasicLua3()
+ public void Lua3()
=> r3.Run(keys, null);
[Benchmark]
- public void BasicLua4()
+ public void Lua4()
=> r4.Run(keys, null);
}
}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Operations/BasicOperations.cs b/benchmark/BDN.benchmark/Operations/BasicOperations.cs
new file mode 100644
index 0000000000..326a5cc548
--- /dev/null
+++ b/benchmark/BDN.benchmark/Operations/BasicOperations.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using BenchmarkDotNet.Attributes;
+
+namespace BDN.benchmark.Operations
+{
+ ///
+ /// Benchmark for BasicOperations
+ ///
+ [MemoryDiagnoser]
+ public unsafe class BasicOperations : OperationsBase
+ {
+ static ReadOnlySpan INLINE_PING => "PING\r\n"u8;
+ byte[] pingRequestBuffer;
+ byte* pingRequestBufferPointer;
+
+ public override void GlobalSetup()
+ {
+ base.GlobalSetup();
+ SetupOperation(ref pingRequestBuffer, ref pingRequestBufferPointer, INLINE_PING);
+ }
+
+ [Benchmark]
+ public void InlinePing()
+ {
+ _ = session.TryConsumeMessages(pingRequestBufferPointer, pingRequestBuffer.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Operations/ObjectOperations.cs b/benchmark/BDN.benchmark/Operations/ObjectOperations.cs
new file mode 100644
index 0000000000..8dcd7ffa21
--- /dev/null
+++ b/benchmark/BDN.benchmark/Operations/ObjectOperations.cs
@@ -0,0 +1,106 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using BDN.benchmark.CustomProcs;
+using BenchmarkDotNet.Attributes;
+using Garnet;
+using Garnet.server;
+
+namespace BDN.benchmark.Operations
+{
+ ///
+ /// Benchmark for ObjectOperations
+ ///
+ [MemoryDiagnoser]
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ static ReadOnlySpan CPBSET => "*9\r\n$6\r\nCPBSET\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[] cpbsetBuffer;
+ byte* cpbsetBufferPointer;
+
+ void CreateExtensions()
+ {
+ var factory = new MyDictFactory();
+ server.Register.NewType(factory);
+ server.Register.NewCommand("MYDICTSET", CommandType.ReadModifyWrite, factory, new MyDictSet(), new RespCommandsInfo { Arity = 4 });
+ server.Register.NewCommand("MYDICTGET", CommandType.Read, factory, new MyDictGet(), new RespCommandsInfo { Arity = 3 });
+ server.Register.NewTransactionProc(CustomProcs.CustomProcSet.CommandName, () => new CustomProcSet(), new RespCommandsInfo { Arity = CustomProcs.CustomProcSet.Arity });
+ }
+
+ public override void GlobalSetup()
+ {
+ base.GlobalSetup();
+ CreateExtensions();
+ SetupOperation(ref zAddRemRequestBuffer, ref zAddRemRequestBufferPointer, ZADDREM);
+ SetupOperation(ref lPushPopRequestBuffer, ref lPushPopRequestBufferPointer, LPUSHPOP);
+ SetupOperation(ref sAddRemRequestBuffer, ref sAddRemRequestBufferPointer, SADDREM);
+ SetupOperation(ref hSetDelRequestBuffer, ref hSetDelRequestBufferPointer, HSETDEL);
+ SetupOperation(ref myDictSetGetRequestBuffer, ref myDictSetGetRequestBufferPointer, MYDICTSETGET);
+ SetupOperation(ref cpbsetBuffer, ref cpbsetBufferPointer, CPBSET);
+
+ // 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);
+ SlowConsumeMessage("*3\r\n$5\r\nLPUSH\r\n$1\r\nd\r\n$1\r\nf\r\n"u8);
+ SlowConsumeMessage("*3\r\n$4\r\nSADD\r\n$1\r\ne\r\n$1\r\nb\r\n"u8);
+ 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);
+ 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(cpbsetBuffer);
+ }
+
+ [Benchmark]
+ public void ZAddRem()
+ {
+ _ = session.TryConsumeMessages(zAddRemRequestBufferPointer, zAddRemRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void LPushPop()
+ {
+ _ = session.TryConsumeMessages(lPushPopRequestBufferPointer, lPushPopRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void SAddRem()
+ {
+ _ = session.TryConsumeMessages(sAddRemRequestBufferPointer, sAddRemRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void HSetDel()
+ {
+ _ = session.TryConsumeMessages(hSetDelRequestBufferPointer, hSetDelRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void MyDictSetGet()
+ {
+ _ = session.TryConsumeMessages(myDictSetGetRequestBufferPointer, myDictSetGetRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void CustomProcSet()
+ {
+ _ = session.TryConsumeMessages(cpbsetBufferPointer, cpbsetBuffer.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Operations/OperationParams.cs b/benchmark/BDN.benchmark/Operations/OperationParams.cs
new file mode 100644
index 0000000000..c47d7c4f03
--- /dev/null
+++ b/benchmark/BDN.benchmark/Operations/OperationParams.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+namespace BDN.benchmark.Operations
+{
+ ///
+ /// Operation parameters
+ ///
+ public struct OperationParams
+ {
+ ///
+ /// Whether to use ACLs
+ ///
+ public bool useACLs;
+
+ ///
+ /// Whether to use AOF
+ ///
+ public bool useAof;
+
+ ///
+ /// Constructor
+ ///
+ public OperationParams(bool useACLs, bool useAof)
+ {
+ this.useACLs = useACLs;
+ this.useAof = useAof;
+ }
+
+ ///
+ /// String representation
+ ///
+ public override string ToString()
+ {
+ if (!useACLs && !useAof)
+ return "None";
+
+ var ret = "";
+ if (useACLs)
+ ret += "ACL";
+ if (useAof)
+ ret += (ret.Length > 0 ? "+" : "") + "AOF";
+ return ret;
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Operations/OperationsBase.cs b/benchmark/BDN.benchmark/Operations/OperationsBase.cs
new file mode 100644
index 0000000000..6c7bb35166
--- /dev/null
+++ b/benchmark/BDN.benchmark/Operations/OperationsBase.cs
@@ -0,0 +1,112 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using System.Runtime.CompilerServices;
+using BenchmarkDotNet.Attributes;
+using Embedded.perftest;
+using Garnet.server;
+using Garnet.server.Auth.Settings;
+
+namespace BDN.benchmark.Operations
+{
+ ///
+ /// Base class for operations benchmarks
+ ///
+ public abstract unsafe class OperationsBase
+ {
+ ///
+ /// Batch size per method invocation
+ /// With a batchSize of 100, we have a convenient conversion of latency to throughput:
+ /// 5 us = 20 Mops/sec
+ /// 10 us = 10 Mops/sec
+ /// 20 us = 5 Mops/sec
+ /// 25 us = 4 Mops/sec
+ /// 100 us = 1 Mops/sec
+ ///
+ const int batchSize = 100;
+ internal EmbeddedRespServer server;
+ internal RespServerSession session;
+
+ ///
+ /// Parameters
+ ///
+ [ParamsSource(nameof(OperationParamsProvider))]
+ public OperationParams Params { get; set; }
+
+ ///
+ /// Operation parameters provider
+ ///
+ public IEnumerable OperationParamsProvider()
+ {
+ yield return new(false, false);
+ yield return new(true, false);
+ yield return new(false, true);
+ }
+
+ ///
+ /// Setup
+ ///
+ [GlobalSetup]
+ public virtual void GlobalSetup()
+ {
+ var opts = new GarnetServerOptions
+ {
+ QuietMode = true
+ };
+ if (Params.useAof)
+ {
+ opts.EnableAOF = true;
+ opts.UseAofNullDevice = true;
+ opts.MainMemoryReplication = true;
+ opts.CommitFrequencyMs = -1;
+ opts.AofPageSize = "128m";
+ opts.AofMemorySize = "256m";
+ }
+
+ string aclFile = null;
+ try
+ {
+ if (Params.useACLs)
+ {
+ aclFile = Path.GetTempFileName();
+ File.WriteAllText(aclFile, @"user default on nopass -@all +ping +set +get +setex +incr +decr +incrby +decrby");
+ opts.AuthSettings = new AclAuthenticationPasswordSettings(aclFile);
+ }
+ server = new EmbeddedRespServer(opts);
+ }
+ finally
+ {
+ if (aclFile != null)
+ File.Delete(aclFile);
+ }
+
+ session = server.GetRespSession();
+ }
+
+ ///
+ /// Cleanup
+ ///
+ [GlobalCleanup]
+ public virtual void GlobalCleanup()
+ {
+ session.Dispose();
+ server.Dispose();
+ }
+
+ protected void SetupOperation(ref byte[] requestBuffer, ref byte* requestBufferPointer, ReadOnlySpan operation)
+ {
+ requestBuffer = GC.AllocateArray(operation.Length * batchSize, pinned: true);
+ requestBufferPointer = (byte*)Unsafe.AsPointer(ref requestBuffer[0]);
+ for (int i = 0; i < batchSize; i++)
+ operation.CopyTo(new Span(requestBuffer).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));
+ _ = session.TryConsumeMessages(bufferPointer, buffer.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Operations/RawStringOperations.cs b/benchmark/BDN.benchmark/Operations/RawStringOperations.cs
new file mode 100644
index 0000000000..7ccc92abfb
--- /dev/null
+++ b/benchmark/BDN.benchmark/Operations/RawStringOperations.cs
@@ -0,0 +1,136 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using BenchmarkDotNet.Attributes;
+
+namespace BDN.benchmark.Operations
+{
+ ///
+ /// Benchmark for RawStringOperations
+ ///
+ [MemoryDiagnoser]
+ 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;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ static ReadOnlySpan GETNF => "*2\r\n$3\r\nGET\r\n$1\r\nb\r\n"u8;
+ byte[] getnfRequestBuffer;
+ byte* getnfRequestBufferPointer;
+
+ static ReadOnlySpan GETF => "*2\r\n$3\r\nGET\r\n$1\r\na\r\n"u8;
+ byte[] getfRequestBuffer;
+ byte* getfRequestBufferPointer;
+
+ static ReadOnlySpan INCR => "*2\r\n$4\r\nINCR\r\n$1\r\ni\r\n"u8;
+ byte[] incrRequestBuffer;
+ byte* incrRequestBufferPointer;
+
+ static ReadOnlySpan DECR => "*2\r\n$4\r\nDECR\r\n$1\r\nj\r\n"u8;
+ byte[] decrRequestBuffer;
+ byte* decrRequestBufferPointer;
+
+ 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;
+
+ 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;
+
+ 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);
+
+ // Pre-populate data
+ SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n"u8);
+ SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\ni\r\n$1\r\n0\r\n"u8);
+ SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\nj\r\n$1\r\n0\r\n"u8);
+ SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\nk\r\n$1\r\n0\r\n"u8);
+ SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\nl\r\n$1\r\n0\r\n"u8);
+ }
+
+ [Benchmark]
+ public void Set()
+ {
+ _ = session.TryConsumeMessages(setRequestBufferPointer, setRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void SetEx()
+ {
+ _ = session.TryConsumeMessages(setexRequestBufferPointer, setexRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void SetNx()
+ {
+ _ = session.TryConsumeMessages(setnxRequestBufferPointer, setnxRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void SetXx()
+ {
+ _ = session.TryConsumeMessages(setxxRequestBufferPointer, setxxRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void GetFound()
+ {
+ _ = session.TryConsumeMessages(getfRequestBufferPointer, getfRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void GetNotFound()
+ {
+ _ = session.TryConsumeMessages(getnfRequestBufferPointer, getnfRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void Increment()
+ {
+ _ = session.TryConsumeMessages(incrRequestBufferPointer, incrRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void Decrement()
+ {
+ _ = session.TryConsumeMessages(decrRequestBufferPointer, decrRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void IncrementBy()
+ {
+ _ = session.TryConsumeMessages(incrbyRequestBufferPointer, incrbyRequestBuffer.Length);
+ }
+
+ [Benchmark]
+ public void DecrementBy()
+ {
+ _ = session.TryConsumeMessages(decrbyRequestBufferPointer, decrbyRequestBuffer.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmark/BDN.benchmark/Resp/RespDoubleBenchmarks.cs b/benchmark/BDN.benchmark/Parsing/DoubleToResp.cs
similarity index 91%
rename from benchmark/BDN.benchmark/Resp/RespDoubleBenchmarks.cs
rename to benchmark/BDN.benchmark/Parsing/DoubleToResp.cs
index 060dde5784..2b14c1a759 100644
--- a/benchmark/BDN.benchmark/Resp/RespDoubleBenchmarks.cs
+++ b/benchmark/BDN.benchmark/Parsing/DoubleToResp.cs
@@ -6,10 +6,13 @@
using BenchmarkDotNet.Attributes;
using Garnet.common;
-namespace BDN.benchmark.Resp
+namespace BDN.benchmark.Parsing
{
+ ///
+ /// Benchmark for DoubleToResp
+ ///
[MemoryDiagnoser]
- public unsafe class RespDoubleWriteBenchmarks
+ public unsafe class DoubleToResp
{
// Big enough buffer for the benchmarks
private readonly byte[] _buffer = new byte[512];
diff --git a/benchmark/BDN.benchmark/Resp/RespIntegerWriteBenchmarks.cs b/benchmark/BDN.benchmark/Parsing/IntegerToResp.cs
similarity index 95%
rename from benchmark/BDN.benchmark/Resp/RespIntegerWriteBenchmarks.cs
rename to benchmark/BDN.benchmark/Parsing/IntegerToResp.cs
index 6b33a19ded..5e9df56387 100644
--- a/benchmark/BDN.benchmark/Resp/RespIntegerWriteBenchmarks.cs
+++ b/benchmark/BDN.benchmark/Parsing/IntegerToResp.cs
@@ -5,9 +5,13 @@
using BenchmarkDotNet.Attributes;
using Garnet.common;
-namespace BDN.benchmark.Resp
+namespace BDN.benchmark.Parsing
{
- public unsafe class RespIntegerWriteBenchmarks
+ ///
+ /// Benchmark for IntegerToResp
+ ///
+ [MemoryDiagnoser]
+ public unsafe class IntegerToResp
{
// Big enough buffer for the benchmarks
private readonly byte[] _buffer = new byte[32];
diff --git a/benchmark/BDN.benchmark/Resp/RespIntegerReadBenchmarks.cs b/benchmark/BDN.benchmark/Parsing/RespToInteger.cs
similarity index 84%
rename from benchmark/BDN.benchmark/Resp/RespIntegerReadBenchmarks.cs
rename to benchmark/BDN.benchmark/Parsing/RespToInteger.cs
index 3afca94cf3..8df44ff123 100644
--- a/benchmark/BDN.benchmark/Resp/RespIntegerReadBenchmarks.cs
+++ b/benchmark/BDN.benchmark/Parsing/RespToInteger.cs
@@ -5,9 +5,13 @@
using BenchmarkDotNet.Attributes;
using Garnet.common;
-namespace BDN.benchmark.Resp
+namespace BDN.benchmark.Parsing
{
- public unsafe class RespIntegerReadBenchmarks
+ ///
+ /// Benchmark for RespToInteger
+ ///
+ [MemoryDiagnoser]
+ public unsafe class RespToInteger
{
[Benchmark]
[ArgumentsSource(nameof(LengthHeaderValues))]
@@ -70,25 +74,25 @@ public ulong ReadULongWithLengthHeader(AsciiTestCase testCase)
}
public static IEnumerable