Skip to content

Commit 9e1427e

Browse files
authored
Add ability to disable intrinsics for tests (#1041)
* Allow testsuit to create an external GarnetServer process. Use this to test software fallbacks. * Fmt. * Try to get around format checker. Dotnet format didn't complain... * Connect after waiting. * Give lightClient a bit more time. I guess it doesn't do connection timeouts. --------- Co-authored-by: prvyk <github@privatemail.fastmailbox.net>
1 parent e627748 commit 9e1427e

File tree

5 files changed

+156
-31
lines changed

5 files changed

+156
-31
lines changed

main/GarnetServer/GarnetServer.csproj

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,15 @@
99
<PackageReadmeFile>README.md</PackageReadmeFile>
1010
</PropertyGroup>
1111

12-
<ItemGroup>
13-
<None Include="..\..\test\testcerts\testcert.pfx" Link="testcert.pfx">
12+
<PropertyGroup>
13+
<SignAssembly>true</SignAssembly>
14+
<AssemblyOriginatorKeyFile>../../Garnet.snk</AssemblyOriginatorKeyFile>
15+
<DelaySign>false</DelaySign>
16+
</PropertyGroup>
17+
18+
<ItemGroup>
19+
<InternalsVisibleTo Include="Garnet.test" Key="0024000004800000940000000602000000240000525341310004000001000100011b1661238d3d3c76232193c8aa2de8c05b8930d6dfe8cd88797a8f5624fdf14a1643141f31da05c0f67961b0e3a64c7120001d2f8579f01ac788b0ff545790d44854abe02f42bfe36a056166a75c6a694db8c5b6609cff8a2dbb429855a1d9f79d4d8ec3e145c74bfdd903274b7344beea93eab86b422652f8dd8eecf530d2" />
20+
<None Include="..\..\test\testcerts\testcert.pfx" Link="testcert.pfx">
1421
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1522
</None>
1623
</ItemGroup>

main/GarnetServer/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Garnet
1010
/// <summary>
1111
/// Garnet server entry point
1212
/// </summary>
13-
class Program
13+
public class Program
1414
{
1515
static void Main(string[] args)
1616
{

test/Garnet.test/Garnet.test.csproj

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,6 @@
1212

1313
<ItemGroup>
1414
<Compile Include="..\..\benchmark\BDN.benchmark\Embedded\EmbeddedNetworkSender.cs" Link="EmbeddedNetworkSender.cs" />
15-
<Compile Include="..\..\main\GarnetServer\Extensions\DeleteIfMatch.cs" Link="DeleteIfMatch.cs" />
16-
<Compile Include="..\..\main\GarnetServer\Extensions\MGetIfPM.cs" Link="MGetIfPM.cs" />
17-
<Compile Include="..\..\main\GarnetServer\Extensions\MSetPx.cs" Link="MSetPx.cs" />
18-
<Compile Include="..\..\main\GarnetServer\Extensions\MyDictObject.cs" Link="MyDictObject.cs" />
19-
<Compile Include="..\..\main\GarnetServer\Extensions\MyDictSet.cs" Link="MyDictSet.cs" />
20-
<Compile Include="..\..\main\GarnetServer\Extensions\MyDictGet.cs" Link="MyDictGet.cs" />
21-
<Compile Include="..\..\main\GarnetServer\Extensions\GetTwoKeysNoTxn.cs" Link="GetTwoKeysNoTxn.cs" />
22-
<Compile Include="..\..\main\GarnetServer\Extensions\ReadWriteTxn.cs" Link="ReadWriteTxn.cs" />
23-
<Compile Include="..\..\main\GarnetServer\Extensions\SampleUpdateTxn.cs" Link="SampleUpdateTxn.cs" />
24-
<Compile Include="..\..\main\GarnetServer\Extensions\SampleDeleteTxn.cs" Link="SampleDeleteTxn.cs" />
25-
<Compile Include="..\..\main\GarnetServer\Extensions\SetIfPM.cs" Link="SetIfPM.cs" />
26-
<Compile Include="..\..\main\GarnetServer\Extensions\SetWPIfPGT.cs" Link="SetWPIFPGT.cs" />
27-
<Compile Include="..\..\main\GarnetServer\Extensions\Sum.cs" Link="Sum.cs" />
28-
<Compile Include="..\..\main\GarnetServer\Extensions\SetStringAndList.cs" Link="SetStringAndList.cs" />
2915
</ItemGroup>
3016

3117
<ItemGroup>
@@ -56,6 +42,7 @@
5642
<ProjectReference Include="..\..\libs\host\Garnet.host.csproj" />
5743
<ProjectReference Include="..\..\libs\server\Garnet.server.csproj" />
5844
<ProjectReference Include="..\..\libs\storage\Tsavorite\cs\src\devices\AzureStorageDevice\Tsavorite.devices.AzureStorageDevice.csproj" />
45+
<ProjectReference Include="..\..\main\GarnetServer\GarnetServer.csproj" />
5946
<ProjectReference Include="..\..\playground\GarnetJSON\GarnetJSON.csproj" />
6047
<ProjectReference Include="..\..\playground\NoOpModule\NoOpModule.csproj" />
6148
</ItemGroup>

test/Garnet.test/GarnetBitmapTests.cs

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Runtime.Intrinsics.X86;
67
using Garnet.common;
78
using Garnet.server;
89
using NUnit.Framework;
@@ -259,25 +260,60 @@ public void BitmapSetGetBitTest_LTM(bool preSet)
259260

260261
[Test, Order(6)]
261262
[Category("BITCOUNT")]
262-
public void BitmapSimpleBitCountTest()
263+
[TestCase(0, TestName = "BitmapSimpleBitCountTest(Hardware accelerated)")]
264+
[TestCase(1, TestName = "BitmapSimpleBitCountTest(Avx2 disabled)")]
265+
[TestCase(2, TestName = "BitmapSimpleBitCountTest(Software fallback)")]
266+
public void BitmapSimpleBitCountTest(int acceleration)
263267
{
264-
using var redis = ConnectionMultiplexer.Connect(TestUtils.GetConfig());
265-
var db = redis.GetDatabase(0);
266-
267-
int maxBitmapLen = 1 << 12;
268-
int iter = 1024;
269-
long expectedCount = 0;
270-
string key = "SimpleBitCountTest";
268+
var configOptions = TestUtils.GetConfig();
271269

272-
for (int i = 0; i < iter; i++)
270+
if (acceleration == 0)
273271
{
274-
long offset = r.Next(1, maxBitmapLen);
275-
bool set = !db.StringSetBit(key, offset, true);
276-
expectedCount += set ? 1 : 0;
272+
SimpleBitCountTest();
277273
}
274+
else
275+
{
276+
Dictionary<string, string> env = [];
278277

279-
long count = db.StringBitCount(key);
280-
ClassicAssert.AreEqual(expectedCount, count);
278+
if (acceleration == 1)
279+
{
280+
if (!Avx2.IsSupported && Ssse3.IsSupported)
281+
Assert.Ignore("Already tested by main path");
282+
283+
env.Add("DOTNET_EnableAVX2", "0");
284+
}
285+
else
286+
{
287+
if (!Avx2.IsSupported && !Ssse3.IsSupported)
288+
Assert.Ignore("Already tested by main path");
289+
290+
env.Add("DOTNET_EnableHWIntrinsic", "0");
291+
}
292+
293+
using var p = new GarnetServerTestProcess(out configOptions, env);
294+
295+
SimpleBitCountTest();
296+
}
297+
298+
void SimpleBitCountTest()
299+
{
300+
using var redis = ConnectionMultiplexer.Connect(configOptions);
301+
var db = redis.GetDatabase(0);
302+
var maxBitmapLen = 1 << 12;
303+
var iter = 1024;
304+
var expectedCount = 0;
305+
var key = "SimpleBitCountTest";
306+
307+
for (var i = 0; i < iter; i++)
308+
{
309+
var offset = r.Next(1, maxBitmapLen);
310+
var set = !db.StringSetBit(key, offset, true);
311+
expectedCount += set ? 1 : 0;
312+
}
313+
314+
var count = db.StringBitCount(key);
315+
ClassicAssert.AreEqual(expectedCount, count);
316+
}
281317
}
282318

283319
private static int Index(long offset) => (int)(offset >> 3);

test/Garnet.test/TestProcess.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Net;
5+
using System.Reflection;
6+
using System.Runtime.InteropServices;
7+
using System.Threading;
8+
using Garnet.common;
9+
using NUnit.Framework.Legacy;
10+
using StackExchange.Redis;
11+
12+
namespace Garnet.test
13+
{
14+
internal class GarnetServerTestProcess : IDisposable
15+
{
16+
private readonly Process p = default;
17+
private readonly Stopwatch stopWatch = default;
18+
private readonly LightClientRequest lightClientRequest = default;
19+
20+
internal GarnetServerTestProcess(out ConfigurationOptions opts,
21+
Dictionary<string, string> env = default,
22+
int port = 7000)
23+
{
24+
var a = Assembly.GetAssembly(typeof(Garnet.Program));
25+
var name = a.Location;
26+
var pos = name.LastIndexOf('.');
27+
28+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
29+
{
30+
name = name.AsSpan().Slice(0, pos).ToString() + ".exe";
31+
}
32+
else
33+
{
34+
name = name.AsSpan().Slice(0, pos).ToString();
35+
}
36+
37+
var endPoint = new IPEndPoint(IPAddress.Loopback, port);
38+
opts = TestUtils.GetConfig([endPoint]);
39+
40+
// We don't have to disable objects, it's done to improve startup time a bit.
41+
var psi = new ProcessStartInfo(name, ["--bind", "127.0.0.1", "--port", port.ToString(), "--enable-debug-command", "local", "--no-pubsub", "--no-obj"])
42+
{
43+
CreateNoWindow = true,
44+
RedirectStandardInput = true,
45+
RedirectStandardOutput = true
46+
};
47+
48+
if (env != default)
49+
{
50+
foreach (var e in env)
51+
psi.Environment.Add(e.Key, e.Value);
52+
}
53+
54+
p = Process.Start(psi);
55+
ClassicAssert.NotNull(p);
56+
57+
// Block until the startup message to ensure process is up.
58+
var dummy = new char[1];
59+
_ = p.StandardOutput.ReadBlock(dummy, 0, 1);
60+
61+
// Give it a bit more time
62+
Thread.Sleep(100);
63+
lightClientRequest = new LightClientRequest(endPoint, 0);
64+
65+
stopWatch = Stopwatch.StartNew();
66+
}
67+
68+
public void Dispose()
69+
{
70+
if (stopWatch != default)
71+
{
72+
stopWatch.Stop();
73+
Console.WriteLine(stopWatch.ElapsedMilliseconds);
74+
}
75+
76+
if (p != default)
77+
{
78+
// We want to be sure the process is down, otherwise it may conflict
79+
// with a future run. First, we'll ask nicely and then kill it.
80+
try
81+
{
82+
// More reliable than QUIT.
83+
_ = lightClientRequest.SendCommand("DEBUG PANIC");
84+
lightClientRequest.Dispose();
85+
}
86+
catch { }
87+
88+
try { p.Kill(); }
89+
catch { }
90+
91+
p.Close();
92+
}
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)