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 SignedInt32EncodedValues - => ToRespIntegerTestCases(RespIntegerWriteBenchmarks.SignedInt32Values); + => ToRespIntegerTestCases(IntegerToResp.SignedInt32Values); public static IEnumerable LengthHeaderValues - => ToRespLengthHeaderTestCases(RespIntegerWriteBenchmarks.SignedInt32Values); + => ToRespLengthHeaderTestCases(IntegerToResp.SignedInt32Values); public static IEnumerable SignedInt64EncodedValues - => ToRespIntegerTestCases(RespIntegerWriteBenchmarks.SignedInt64Values); + => ToRespIntegerTestCases(IntegerToResp.SignedInt64Values); public static IEnumerable UnsignedInt64EncodedValues - => ToRespIntegerTestCases(RespIntegerWriteBenchmarks.UnsignedInt64Values); + => ToRespIntegerTestCases(IntegerToResp.UnsignedInt64Values); public static IEnumerable SignedInt32EncodedValuesWithLengthHeader - => ToRespIntegerWithLengthHeader(RespIntegerWriteBenchmarks.SignedInt32Values); + => ToRespIntegerWithLengthHeader(IntegerToResp.SignedInt32Values); public static IEnumerable SignedInt64EncodedValuesWithLengthHeader - => ToRespIntegerWithLengthHeader(RespIntegerWriteBenchmarks.SignedInt64Values); + => ToRespIntegerWithLengthHeader(IntegerToResp.SignedInt64Values); public static IEnumerable UnsignedInt64EncodedValuesWithLengthHeader - => ToRespIntegerWithLengthHeader(RespIntegerWriteBenchmarks.UnsignedInt64Values); + => ToRespIntegerWithLengthHeader(IntegerToResp.UnsignedInt64Values); public static IEnumerable ToRespIntegerTestCases(T[] integerValues) where T : struct => integerValues.Select(testCase => new AsciiTestCase($":{testCase}\r\n")); diff --git a/benchmark/BDN.benchmark/RecoveryBenchmark.cs b/benchmark/BDN.benchmark/RecoveryBenchmark.cs deleted file mode 100644 index 9cbd76ef0f..0000000000 --- a/benchmark/BDN.benchmark/RecoveryBenchmark.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Columns; -using Embedded.perftest; -using Garnet.server; - -namespace BDN.benchmark -{ - [Config(typeof(Config))] - public class RecoveryBenchmark - { - private class Config : BaseConfig - { - public Config() - { - AddColumn(StatisticColumn.P90); - AddColumn(StatisticColumn.P95); - } - } - - [ParamsSource(nameof(CommandLineArgsProvider))] - public string LogDir { get; set; } - - public IEnumerable CommandLineArgsProvider() - { - // Return the command line arguments as an enumerable - return Environment.GetCommandLineArgs().Skip(1); - } - - [Params("100m")] - public string MemorySize { get; set; } - - EmbeddedRespServer server; - - [IterationSetup] - public void Setup() - { - Console.WriteLine($"LogDir: {LogDir}"); - server = new EmbeddedRespServer(new GarnetServerOptions() - { - EnableStorageTier = true, - LogDir = LogDir, - CheckpointDir = LogDir, - IndexSize = "1m", - DisableObjects = true, - MemorySize = MemorySize, - PageSize = "32k", - }); - } - - [IterationCleanup] - public void Cleanup() - { - server.Dispose(); - } - - [Benchmark] - public void Recover() - { - server.StoreWrapper.RecoverCheckpoint(); - } - } -} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Resp/RespAofStress.cs b/benchmark/BDN.benchmark/Resp/RespAofStress.cs deleted file mode 100644 index 7e52feec90..0000000000 --- a/benchmark/BDN.benchmark/Resp/RespAofStress.cs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System.Runtime.CompilerServices; -using BenchmarkDotNet.Attributes; -using Embedded.perftest; -using Garnet.server; - -namespace BDN.benchmark.Resp -{ - [MemoryDiagnoser] - public unsafe class RespAofStress - { - EmbeddedRespServer server; - RespServerSession session; - const int batchSize = 128; - - 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 INCR => "*2\r\n$4\r\nINCR\r\n$1\r\ni\r\n"u8; - byte[] incrRequestBuffer; - byte* incrRequestBufferPointer; - - 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; - - [GlobalSetup] - public void GlobalSetup() - { - var opt = new GarnetServerOptions - { - QuietMode = true, - EnableAOF = true, - UseAofNullDevice = true, - MainMemoryReplication = true, - CommitFrequencyMs = -1, - AofPageSize = "128m", - AofMemorySize = "256m", - }; - server = new EmbeddedRespServer(opt); - - session = server.GetRespSession(); - - setRequestBuffer = GC.AllocateArray(SET.Length * batchSize, pinned: true); - setRequestBufferPointer = (byte*)Unsafe.AsPointer(ref setRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - SET.CopyTo(new Span(setRequestBuffer).Slice(i * SET.Length)); - - _ = session.TryConsumeMessages(setRequestBufferPointer, setRequestBuffer.Length); - - incrRequestBuffer = GC.AllocateArray(INCR.Length * batchSize, pinned: true); - incrRequestBufferPointer = (byte*)Unsafe.AsPointer(ref incrRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - INCR.CopyTo(new Span(incrRequestBuffer).Slice(i * INCR.Length)); - - _ = session.TryConsumeMessages(incrRequestBufferPointer, incrRequestBuffer.Length); - - lPushPopRequestBuffer = GC.AllocateArray(LPUSHPOP.Length * batchSize, pinned: true); - lPushPopRequestBufferPointer = (byte*)Unsafe.AsPointer(ref lPushPopRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - LPUSHPOP.CopyTo(new Span(lPushPopRequestBuffer).Slice(i * LPUSHPOP.Length)); - - // Pre-populate list with a single element to avoid repeatedly emptying it during the benchmark - SlowConsumeMessage("*3\r\n$5\r\nLPUSH\r\n$1\r\nd\r\n$1\r\nf\r\n"u8); - } - - [GlobalCleanup] - public void GlobalCleanup() - { - session.Dispose(); - server.Dispose(); - } - - [Benchmark] - public void Set() - { - _ = session.TryConsumeMessages(setRequestBufferPointer, setRequestBuffer.Length); - } - - [Benchmark] - public void Increment() - { - _ = session.TryConsumeMessages(incrRequestBufferPointer, incrRequestBuffer.Length); - } - - [Benchmark] - public void LPushPop() - { - _ = session.TryConsumeMessages(lPushPopRequestBufferPointer, lPushPopRequestBuffer.Length); - } - - private 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/Resp/RespIncrementStress.cs b/benchmark/BDN.benchmark/Resp/RespIncrementStress.cs deleted file mode 100644 index 562338b144..0000000000 --- a/benchmark/BDN.benchmark/Resp/RespIncrementStress.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System.Text; -using BenchmarkDotNet.Attributes; -using Embedded.perftest; -using Garnet.common; -using Garnet.server; - -namespace BDN.benchmark.Resp -{ - public unsafe class RespIncrementStress - { - EmbeddedRespServer server; - RespServerSession session; - - static ReadOnlySpan SINGLE_INCR => "*2\r\n$4\r\nINCR\r\n$1\r\nx\r\n"u8; - static ReadOnlySpan SINGLE_DECR => "*2\r\n$4\r\nDECR\r\n$1\r\nx\r\n"u8; - - [GlobalSetup] - public void GlobalSetup() - { - var opt = new GarnetServerOptions - { - QuietMode = true - }; - server = new EmbeddedRespServer(opt); - session = server.GetRespSession(); - } - - [GlobalCleanup] - public void GlobalCleanup() - { - session.Dispose(); - server.Dispose(); - } - - [Benchmark] - public void Increment() - { - fixed (byte* ptr = SINGLE_INCR) - { - _ = session.TryConsumeMessages(ptr, SINGLE_INCR.Length); - } - } - - [Benchmark] - public void Decrement() - { - fixed (byte* ptr = SINGLE_DECR) - { - _ = session.TryConsumeMessages(ptr, SINGLE_DECR.Length); - } - } - - [Benchmark] - [ArgumentsSource(nameof(IncrByBenchInput))] - public void IncrementBy(byte[] input) - { - fixed (byte* ptr = input) - { - _ = session.TryConsumeMessages(ptr, input.Length); - } - } - - [Benchmark] - [ArgumentsSource(nameof(DecrByBenchInput))] - public void DecrementBy(byte[] input) - { - fixed (byte* ptr = input) - { - _ = session.TryConsumeMessages(ptr, input.Length); - } - } - - public static IEnumerable IncrByBenchInput => values.Select(x => Get(RespCommand.INCRBY, x)); - public static IEnumerable DecrByBenchInput => values.Select(x => Get(RespCommand.DECRBY, x)); - - public static int[] values => [int.MinValue, -1, 0, int.MaxValue]; - - public static byte[] Get(RespCommand cmd, long val) - { - var length = NumUtils.NumDigitsInLong(val); - return cmd switch - { - RespCommand.INCRBY => Encoding.ASCII.GetBytes($"*2\r\n$6\r\nINCRBY\r\n$1\r\nx\r\n${length}\r\n{val}\r\n"), - RespCommand.DECRBY => Encoding.ASCII.GetBytes($"*2\r\n$6\r\nDECRBY\r\n$1\r\nx\r\n${length}\r\n{val}\r\n"), - _ => throw new Exception($"Option {cmd} not supported") - }; - } - } -} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Resp/RespLuaStress.cs b/benchmark/BDN.benchmark/Resp/RespLuaStress.cs deleted file mode 100644 index 45cdcefbf7..0000000000 --- a/benchmark/BDN.benchmark/Resp/RespLuaStress.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using BenchmarkDotNet.Attributes; -using NLua; - -namespace BDN.benchmark.Resp -{ - [MemoryDiagnoser] - public unsafe class RespLuaStress - { - Lua state; - LuaFunction f1, f2, f3, f4; - - public string garnet_call(string arg1) => arg1; - - [GlobalSetup] - public void GlobalSetup() - { - state = new Lua(); - - state.RegisterFunction("garnet_call", this, this.GetType().GetMethod("garnet_call")); - state["KEYS"] = new string[] { "key1", "key2" }; - state["ARGV"] = new string[] { "arg1", "arg2" }; - - state.DoString(@" - import = function () end - redis = {} - function redis.call(a) - return garnet_call(a) - end - function load_sandboxed(source) - if (not source) then return nil end - return load(source) - end - "); - - f1 = CreateFunction("return"); - f2 = CreateFunction("return 1 + 1"); - f3 = CreateFunction("return KEYS[1]"); - f4 = CreateFunction("return redis.call(KEYS[1])"); - } - - [GlobalCleanup] - public void GlobalCleanup() - { - f1.Dispose(); - f2.Dispose(); - f3.Dispose(); - f4.Dispose(); - state.Dispose(); - } - - LuaFunction CreateFunction(string source) - { - using var loader = (LuaFunction)state["load_sandboxed"]; - return loader.Call(source)[0] as LuaFunction; - } - - [Benchmark] - public void BasicLua1() - => f1.Call(); - - [Benchmark] - public void BasicLua2() - => f2.Call(); - - [Benchmark] - public void BasicLua3() - => f3.Call(); - - [Benchmark] - public void BasicLua4() - => f4.Call(); - } -} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Resp/RespParseACLStress.cs b/benchmark/BDN.benchmark/Resp/RespParseACLStress.cs deleted file mode 100644 index 08142c834a..0000000000 --- a/benchmark/BDN.benchmark/Resp/RespParseACLStress.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using BenchmarkDotNet.Attributes; -using Garnet.server.Auth.Settings; - -namespace BDN.benchmark.Resp -{ - [MemoryDiagnoser] - public unsafe class RespParseACLStress : RespParseStress - { - [Params(false, true)] - public bool UseACLs { get; set; } - - public override void GlobalSetup() - { - string aclFile = null; - - try - { - if (UseACLs) - { - aclFile = Path.GetTempFileName(); - File.WriteAllText(aclFile, @"user default on nopass -@all +ping +set +get"); - authSettings = new AclAuthenticationPasswordSettings(aclFile); - } - base.GlobalSetup(); - } - finally - { - if (aclFile != null) - { - File.Delete(aclFile); - } - } - } - } -} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/Resp/RespParseStress.cs b/benchmark/BDN.benchmark/Resp/RespParseStress.cs deleted file mode 100644 index 6a087a52c8..0000000000 --- a/benchmark/BDN.benchmark/Resp/RespParseStress.cs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System.Runtime.CompilerServices; -using BenchmarkDotNet.Attributes; -using Embedded.perftest; -using Garnet; -using Garnet.server; -using Garnet.server.Auth.Settings; - -namespace BDN.benchmark.Resp -{ - [MemoryDiagnoser] - public unsafe class RespParseStress - { - EmbeddedRespServer server; - RespServerSession session; - protected IAuthenticationSettings authSettings = null; - - const int batchSize = 128; - - static ReadOnlySpan INLINE_PING => "PING\r\n"u8; - byte[] pingRequestBuffer; - byte* pingRequestBufferPointer; - - 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 GET => "*2\r\n$3\r\nGET\r\n$1\r\nb\r\n"u8; - byte[] getRequestBuffer; - byte* getRequestBufferPointer; - - static ReadOnlySpan INCR => "*2\r\n$4\r\nINCR\r\n$1\r\ni\r\n"u8; - byte[] incrRequestBuffer; - byte* incrRequestBufferPointer; - - 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; - - [GlobalSetup] - public virtual void GlobalSetup() - { - var opt = new GarnetServerOptions - { - QuietMode = true, - AuthSettings = authSettings, - }; - server = new EmbeddedRespServer(opt); - - 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(CustomProcSetBench.CommandName, () => new CustomProcSetBench(), new RespCommandsInfo { Arity = CustomProcSetBench.Arity }); - - session = server.GetRespSession(); - - pingRequestBuffer = GC.AllocateArray(INLINE_PING.Length * batchSize, pinned: true); - pingRequestBufferPointer = (byte*)Unsafe.AsPointer(ref pingRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - INLINE_PING.CopyTo(new Span(pingRequestBuffer).Slice(i * INLINE_PING.Length)); - - setRequestBuffer = GC.AllocateArray(SET.Length * batchSize, pinned: true); - setRequestBufferPointer = (byte*)Unsafe.AsPointer(ref setRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - SET.CopyTo(new Span(setRequestBuffer).Slice(i * SET.Length)); - - setexRequestBuffer = GC.AllocateArray(SETEX.Length * batchSize, pinned: true); - setexRequestBufferPointer = (byte*)Unsafe.AsPointer(ref setexRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - SETEX.CopyTo(new Span(setexRequestBuffer).Slice(i * SETEX.Length)); - - setnxRequestBuffer = GC.AllocateArray(SETNX.Length * batchSize, pinned: true); - setnxRequestBufferPointer = (byte*)Unsafe.AsPointer(ref setnxRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - SETNX.CopyTo(new Span(setnxRequestBuffer).Slice(i * SETNX.Length)); - - setxxRequestBuffer = GC.AllocateArray(SETXX.Length * batchSize, pinned: true); - setxxRequestBufferPointer = (byte*)Unsafe.AsPointer(ref setxxRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - SETXX.CopyTo(new Span(setxxRequestBuffer).Slice(i * SETXX.Length)); - - getRequestBuffer = GC.AllocateArray(GET.Length * batchSize, pinned: true); - getRequestBufferPointer = (byte*)Unsafe.AsPointer(ref getRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - GET.CopyTo(new Span(getRequestBuffer).Slice(i * GET.Length)); - - incrRequestBuffer = GC.AllocateArray(INCR.Length * batchSize, pinned: true); - incrRequestBufferPointer = (byte*)Unsafe.AsPointer(ref incrRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - INCR.CopyTo(new Span(incrRequestBuffer).Slice(i * INCR.Length)); - - zAddRemRequestBuffer = GC.AllocateArray(ZADDREM.Length * batchSize, pinned: true); - zAddRemRequestBufferPointer = (byte*)Unsafe.AsPointer(ref zAddRemRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - ZADDREM.CopyTo(new Span(zAddRemRequestBuffer).Slice(i * ZADDREM.Length)); - - lPushPopRequestBuffer = GC.AllocateArray(LPUSHPOP.Length * batchSize, pinned: true); - lPushPopRequestBufferPointer = (byte*)Unsafe.AsPointer(ref lPushPopRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - LPUSHPOP.CopyTo(new Span(lPushPopRequestBuffer).Slice(i * LPUSHPOP.Length)); - - sAddRemRequestBuffer = GC.AllocateArray(SADDREM.Length * batchSize, pinned: true); - sAddRemRequestBufferPointer = (byte*)Unsafe.AsPointer(ref sAddRemRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - SADDREM.CopyTo(new Span(sAddRemRequestBuffer).Slice(i * SADDREM.Length)); - - hSetDelRequestBuffer = GC.AllocateArray(HSETDEL.Length * batchSize, pinned: true); - hSetDelRequestBufferPointer = (byte*)Unsafe.AsPointer(ref hSetDelRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - HSETDEL.CopyTo(new Span(hSetDelRequestBuffer).Slice(i * HSETDEL.Length)); - - // Pre-populate raw string set with a single element - SlowConsumeMessage("*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\na\r\n"u8); - - // Pre-populate sorted set with a single element to avoid repeatedly emptying it during the benchmark - 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); - - // Pre-populate list with a single element to avoid repeatedly emptying it during the benchmark - SlowConsumeMessage("*3\r\n$5\r\nLPUSH\r\n$1\r\nd\r\n$1\r\nf\r\n"u8); - - // Pre-populate set with a single element to avoid repeatedly emptying it during the benchmark - SlowConsumeMessage("*3\r\n$4\r\nSADD\r\n$1\r\ne\r\n$1\r\nb\r\n"u8); - - // Pre-populate hash with a single element to avoid repeatedly emptying it during the benchmark - 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); - - myDictSetGetRequestBuffer = GC.AllocateArray(MYDICTSETGET.Length * batchSize, pinned: true); - myDictSetGetRequestBufferPointer = (byte*)Unsafe.AsPointer(ref myDictSetGetRequestBuffer[0]); - for (int i = 0; i < batchSize; i++) - MYDICTSETGET.CopyTo(new Span(myDictSetGetRequestBuffer).Slice(i * MYDICTSETGET.Length)); - - // Pre-populate custom object - 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); - - cpbsetBuffer = GC.AllocateArray(CPBSET.Length * batchSize, pinned: true); - cpbsetBufferPointer = (byte*)Unsafe.AsPointer(ref cpbsetBuffer[0]); - for (var i = 0; i < batchSize; i++) - CPBSET.CopyTo(new Span(cpbsetBuffer).Slice(i * CPBSET.Length)); - - // Pre-populate custom object - SlowConsumeMessage(cpbsetBuffer); - } - - [GlobalCleanup] - public void GlobalCleanup() - { - session.Dispose(); - server.Dispose(); - } - - [Benchmark] - public void InlinePing() - { - _ = session.TryConsumeMessages(pingRequestBufferPointer, pingRequestBuffer.Length); - } - - [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 Get() - { - _ = session.TryConsumeMessages(getRequestBufferPointer, getRequestBuffer.Length); - } - - [Benchmark] - public void Increment() - { - _ = session.TryConsumeMessages(incrRequestBufferPointer, incrRequestBuffer.Length); - } - - [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 CustomProceSetBench() - { - _ = session.TryConsumeMessages(cpbsetBufferPointer, cpbsetBuffer.Length); - } - - private 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/Resp/RespTsavoriteStress.cs b/benchmark/BDN.benchmark/Resp/RespTsavoriteStress.cs deleted file mode 100644 index e11e4133e5..0000000000 --- a/benchmark/BDN.benchmark/Resp/RespTsavoriteStress.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System.Runtime.CompilerServices; -using BenchmarkDotNet.Attributes; -using Embedded.perftest; -using Garnet.server; - -namespace BDN.benchmark.Resp -{ - public unsafe class RespTsavoriteStress - { - EmbeddedRespServer server; - RespServerSession session; - - const int batchSize = 128; - - static ReadOnlySpan GET => "*2\r\n$3\r\nGET\r\n$1\r\nx\r\n"u8; - byte[] getRequestBuffer; - byte* getRequestBufferPointer; - - static ReadOnlySpan SET => "*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$1\r\n1\r\n"u8; - byte[] setRequestBuffer; - byte* setRequestBufferPointer; - - static ReadOnlySpan INCR => "*2\r\n$4\r\nINCR\r\n$1\r\nx\r\n"u8; - byte[] incrRequestBuffer; - byte* incrRequestBufferPointer; - - [GlobalSetup] - public void GlobalSetup() - { - var opt = new GarnetServerOptions - { - QuietMode = true - }; - server = new EmbeddedRespServer(opt); - session = server.GetRespSession(); - - CreateBuffer(GET, out getRequestBuffer, out getRequestBufferPointer); - CreateBuffer(SET, out setRequestBuffer, out setRequestBufferPointer); - CreateBuffer(INCR, out incrRequestBuffer, out incrRequestBufferPointer); - - // Set the initial value (needed for GET) - _ = session.TryConsumeMessages(setRequestBufferPointer, setRequestBuffer.Length); - } - - unsafe void CreateBuffer(ReadOnlySpan cmd, out byte[] buffer, out byte* bufferPointer) - { - buffer = GC.AllocateArray(cmd.Length * batchSize, pinned: true); - bufferPointer = (byte*)Unsafe.AsPointer(ref buffer[0]); - for (int i = 0; i < batchSize; i++) - cmd.CopyTo(new Span(buffer).Slice(i * cmd.Length)); - } - - [GlobalCleanup] - public void GlobalCleanup() - { - session.Dispose(); - server.Dispose(); - } - - [Benchmark] - public void Get() - { - _ = session.TryConsumeMessages(getRequestBufferPointer, getRequestBuffer.Length); - } - - [Benchmark] - public void Set() - { - _ = session.TryConsumeMessages(setRequestBufferPointer, setRequestBuffer.Length); - } - - [Benchmark] - public void Incr() - { - _ = session.TryConsumeMessages(incrRequestBufferPointer, incrRequestBuffer.Length); - } - } -} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/SpanVsPointer.cs b/benchmark/BDN.benchmark/SpanVsPointer.cs deleted file mode 100644 index 147f6d863a..0000000000 --- a/benchmark/BDN.benchmark/SpanVsPointer.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -using System.Runtime.CompilerServices; -using BenchmarkDotNet.Attributes; - -namespace BDN.benchmark -{ - public unsafe class SpanVsPointer - { - const int Count = 1024; - - byte[] bytes; - byte* bytesPtr; - - [GlobalSetup] - public void GlobalSetup() - { - bytes = GC.AllocateArray(Count, true); - bytesPtr = (byte*)Unsafe.AsPointer(ref bytes[0]); - for (var ii = 0; ii < Count; ++ii) - bytes[ii] = (byte)ii; - } - - [BenchmarkCategory("Swap"), Benchmark(Baseline = true)] - public void Pointer() - { - byte* pointer = bytesPtr; - byte* end = pointer + Count - 1; - while (pointer < end) - { - var tmp = *pointer; - *pointer = *++pointer; - *pointer = tmp; - } - } - - [BenchmarkCategory("Swap"), Benchmark] - public void Span() - { - var span = new Span(bytesPtr, Count); - int i = 0; - while (i < Count - 1) - { - var tmp = span[i]; - span[i] = span[++i]; - span[i] = tmp; - } - } - - [BenchmarkCategory("Swap"), Benchmark] - public void SpanToPointer() - { - var span = new Span(bytesPtr, Count); - fixed (byte* ptr = span) - { - byte* pointer = ptr; - byte* end = pointer + Count - 1; - while (pointer < end) - { - var tmp = *pointer; - *pointer = *++pointer; - *pointer = tmp; - } - } - } - } -} \ No newline at end of file diff --git a/benchmark/BDN.benchmark/BenchUtils.cs b/benchmark/BDN.benchmark/Utils/BenchUtils.cs similarity index 100% rename from benchmark/BDN.benchmark/BenchUtils.cs rename to benchmark/BDN.benchmark/Utils/BenchUtils.cs diff --git a/benchmark/Resp.benchmark/RespOnlineBench.cs b/benchmark/Resp.benchmark/RespOnlineBench.cs index 6b89212f5a..c7813ca3cc 100644 --- a/benchmark/Resp.benchmark/RespOnlineBench.cs +++ b/benchmark/Resp.benchmark/RespOnlineBench.cs @@ -541,7 +541,7 @@ public unsafe void OpRunnerLightClient(int thread_id) RespWriteUtils.WriteAsciiBulkString(sskey, ref zremCurr, zremEnd); RespWriteUtils.WriteIntegerAsBulkString(1, ref zremCurr, zremEnd); RespWriteUtils.WriteAsciiBulkString(req.GenerateKey(), ref zremCurr, zremEnd); - client.Send(zremBuffer, (int)(zremCurr - zremEnd), 1); + client.Send(zremBuffer, (int)(zremCurr - zremBuffer), 1); client.CompletePendingRequests(); break; case OpType.ZCARD: diff --git a/playground/Embedded.perftest/DummyNetworkSender.cs b/playground/Embedded.perftest/DummyNetworkSender.cs index 59224556bf..049f979a39 100644 --- a/playground/Embedded.perftest/DummyNetworkSender.cs +++ b/playground/Embedded.perftest/DummyNetworkSender.cs @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -using System.Net.Sockets; using System.Runtime.CompilerServices; -using System.Threading; using Garnet.networking; namespace Embedded.perftest