Skip to content

Commit 96574c5

Browse files
committed
refactor: Xor benchmark
1 parent 13bcca3 commit 96574c5

File tree

4 files changed

+187
-111
lines changed

4 files changed

+187
-111
lines changed

test/CryptoBase.Benchmark.Tests/BenchmarkTest.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,10 @@ public void Xor64Benchmark()
175175
{
176176
BenchmarkRunner.Run<Xor64Benchmark>();
177177
}
178+
179+
[Fact]
180+
public void XorBenchmark()
181+
{
182+
BenchmarkRunner.Run<XorBenchmark>();
183+
}
178184
}

test/CryptoBase.Benchmark/Xor16Benchmark.cs

Lines changed: 67 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace CryptoBase.Benchmark;
99

10+
[RankColumn]
1011
public class Xor16Benchmark
1112
{
1213
private Memory<byte> _a;
@@ -22,91 +23,70 @@ public void Setup()
2223
[Benchmark(Baseline = true, Description = @"Normal")]
2324
public void A()
2425
{
25-
Xor(_a.Span, _b.Span);
26+
Span<byte> a = _a.Span;
27+
Span<byte> b = _b.Span;
2628

27-
return;
28-
29-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
30-
static void Xor(Span<byte> a, Span<byte> b)
29+
for (int i = 0; i < 16; ++i)
3130
{
32-
for (int i = 0; i < 16; ++i)
33-
{
34-
a[i] ^= b[i];
35-
}
31+
a[i] ^= b[i];
3632
}
3733
}
3834

3935
[Benchmark(Description = @"Without bounds checking")]
4036
public void B()
4137
{
42-
Xor(_a.Span, _b.Span);
43-
44-
return;
38+
Span<byte> a = _a.Span;
39+
Span<byte> b = _b.Span;
4540

46-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
47-
static void Xor(Span<byte> a, Span<byte> b)
41+
for (int i = 0; i < 16; ++i)
4842
{
49-
for (int i = 0; i < 16; ++i)
50-
{
51-
a.GetRef(i) ^= b.GetRef(i);
52-
}
43+
a.GetRef(i) ^= b.GetRef(i);
5344
}
5445
}
5546

5647
[Benchmark(Description = @"Without bounds checking + unrolling")]
5748
public void B2()
5849
{
59-
Xor(_a.Span, _b.Span);
60-
61-
return;
62-
63-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64-
static void Xor(Span<byte> a, Span<byte> b)
65-
{
66-
a.GetRef(0) ^= b.GetRef(0);
67-
a.GetRef(1) ^= b.GetRef(1);
68-
a.GetRef(2) ^= b.GetRef(2);
69-
a.GetRef(3) ^= b.GetRef(3);
70-
a.GetRef(4) ^= b.GetRef(4);
71-
a.GetRef(5) ^= b.GetRef(5);
72-
a.GetRef(6) ^= b.GetRef(6);
73-
a.GetRef(7) ^= b.GetRef(7);
74-
a.GetRef(8) ^= b.GetRef(8);
75-
a.GetRef(9) ^= b.GetRef(9);
76-
a.GetRef(10) ^= b.GetRef(10);
77-
a.GetRef(11) ^= b.GetRef(11);
78-
a.GetRef(12) ^= b.GetRef(12);
79-
a.GetRef(13) ^= b.GetRef(13);
80-
a.GetRef(14) ^= b.GetRef(14);
81-
a.GetRef(15) ^= b.GetRef(15);
82-
}
50+
Span<byte> a = _a.Span;
51+
Span<byte> b = _b.Span;
52+
53+
a.GetRef(0) ^= b.GetRef(0);
54+
a.GetRef(1) ^= b.GetRef(1);
55+
a.GetRef(2) ^= b.GetRef(2);
56+
a.GetRef(3) ^= b.GetRef(3);
57+
a.GetRef(4) ^= b.GetRef(4);
58+
a.GetRef(5) ^= b.GetRef(5);
59+
a.GetRef(6) ^= b.GetRef(6);
60+
a.GetRef(7) ^= b.GetRef(7);
61+
a.GetRef(8) ^= b.GetRef(8);
62+
a.GetRef(9) ^= b.GetRef(9);
63+
a.GetRef(10) ^= b.GetRef(10);
64+
a.GetRef(11) ^= b.GetRef(11);
65+
a.GetRef(12) ^= b.GetRef(12);
66+
a.GetRef(13) ^= b.GetRef(13);
67+
a.GetRef(14) ^= b.GetRef(14);
68+
a.GetRef(15) ^= b.GetRef(15);
8369
}
8470

8571
[Benchmark(Description = @"Vector128")]
8672
public void C()
8773
{
88-
Xor(_a.Span, _b.Span);
74+
Span<byte> a = _a.Span;
75+
Span<byte> b = _b.Span;
8976

90-
return;
77+
ref Vector128<byte> v0 = ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(a));
78+
ref Vector128<byte> v1 = ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(b));
9179

92-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
93-
static void Xor(Span<byte> a, Span<byte> b)
94-
{
95-
Vector128<byte> v0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(a));
96-
Vector128<byte> v1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(b));
97-
(v0 ^ v1).CopyTo(a);
98-
}
80+
v0 ^= v1;
9981
}
10082

10183
[Benchmark(Description = @"SSE2")]
10284
public void D()
10385
{
104-
Xor(_a.Span, _b.Span);
105-
106-
return;
86+
Span<byte> a = _a.Span;
87+
Span<byte> b = _b.Span;
10788

108-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
109-
static unsafe void Xor(Span<byte> a, Span<byte> b)
89+
unsafe
11090
{
11191
Vector128<byte> v0 = Sse2.LoadVector128((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(a)));
11292
Vector128<byte> v1 = Sse2.LoadVector128((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(b)));
@@ -117,12 +97,10 @@ static unsafe void Xor(Span<byte> a, Span<byte> b)
11797
[Benchmark(Description = @"Unsafe")]
11898
public void E()
11999
{
120-
Xor(_a.Span, _b.Span);
100+
Span<byte> a = _a.Span;
101+
Span<byte> b = _b.Span;
121102

122-
return;
123-
124-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
125-
static unsafe void Xor(Span<byte> a, Span<byte> b)
103+
unsafe
126104
{
127105
fixed (byte* pa = &MemoryMarshal.GetReference(a))
128106
fixed (byte* pb = &MemoryMarshal.GetReference(b))
@@ -138,12 +116,10 @@ static unsafe void Xor(Span<byte> a, Span<byte> b)
138116
[Benchmark(Description = @"Unsafe unrolling")]
139117
public void F()
140118
{
141-
Xor(_a.Span, _b.Span);
142-
143-
return;
119+
Span<byte> a = _a.Span;
120+
Span<byte> b = _b.Span;
144121

145-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
146-
static unsafe void Xor(Span<byte> a, Span<byte> b)
122+
unsafe
147123
{
148124
fixed (byte* pa = &MemoryMarshal.GetReference(a))
149125
fixed (byte* pb = &MemoryMarshal.GetReference(b))
@@ -167,4 +143,29 @@ static unsafe void Xor(Span<byte> a, Span<byte> b)
167143
}
168144
}
169145
}
146+
147+
[Benchmark(Description = @"UInt128")]
148+
public void G()
149+
{
150+
Span<byte> a = _a.Span;
151+
Span<byte> b = _b.Span;
152+
153+
ref UInt128 xa = ref Unsafe.As<byte, UInt128>(ref MemoryMarshal.GetReference(a));
154+
ref UInt128 xb = ref Unsafe.As<byte, UInt128>(ref MemoryMarshal.GetReference(b));
155+
156+
xa ^= xb;
157+
}
158+
159+
[Benchmark(Description = @"ulong")]
160+
public void G2()
161+
{
162+
Span<byte> a = _a.Span;
163+
Span<byte> b = _b.Span;
164+
165+
Span<ulong> xa = MemoryMarshal.Cast<byte, ulong>(a);
166+
ReadOnlySpan<ulong> xb = MemoryMarshal.Cast<byte, ulong>(b);
167+
168+
xa.GetRef(0) ^= xb.GetRef(0);
169+
xa.GetRef(1) ^= xb.GetRef(1);
170+
}
170171
}

test/CryptoBase.Benchmark/Xor64Benchmark.cs

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,83 +22,74 @@ public void Setup()
2222
[Benchmark(Baseline = true, Description = @"Normal")]
2323
public void A()
2424
{
25-
Xor(_a.Span, _b.Span);
25+
Span<byte> a = _a.Span;
26+
Span<byte> b = _b.Span;
2627

27-
return;
28-
29-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
30-
static void Xor(Span<byte> a, Span<byte> b)
28+
for (int i = 0; i < 64; ++i)
3129
{
32-
for (int i = 0; i < 64; ++i)
33-
{
34-
a[i] ^= b[i];
35-
}
30+
a[i] ^= b[i];
3631
}
3732
}
3833

3934
[Benchmark(Description = @"Without bounds checking")]
4035
public void B()
4136
{
42-
Xor(_a.Span, _b.Span);
37+
Span<byte> a = _a.Span;
38+
Span<byte> b = _b.Span;
4339

44-
return;
45-
46-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
47-
static void Xor(Span<byte> a, Span<byte> b)
40+
for (int i = 0; i < 64; ++i)
4841
{
49-
for (int i = 0; i < 64; ++i)
50-
{
51-
a.GetRef(i) ^= b.GetRef(i);
52-
}
42+
a.GetRef(i) ^= b.GetRef(i);
5343
}
5444
}
5545

5646
[Benchmark(Description = @"Vector512")]
5747
public void C()
5848
{
59-
Xor(_a.Span, _b.Span);
49+
Span<byte> a = _a.Span;
50+
Span<byte> b = _b.Span;
6051

61-
return;
52+
ref Vector512<byte> v0 = ref Unsafe.As<byte, Vector512<byte>>(ref MemoryMarshal.GetReference(a));
53+
ref Vector512<byte> v1 = ref Unsafe.As<byte, Vector512<byte>>(ref MemoryMarshal.GetReference(b));
6254

63-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64-
static void Xor(Span<byte> a, Span<byte> b)
65-
{
66-
Vector512<byte> v0 = Unsafe.ReadUnaligned<Vector512<byte>>(ref MemoryMarshal.GetReference(a));
67-
Vector512<byte> v1 = Unsafe.ReadUnaligned<Vector512<byte>>(ref MemoryMarshal.GetReference(b));
68-
(v0 ^ v1).CopyTo(a);
69-
}
55+
v0 ^= v1;
7056
}
7157

72-
7358
[Benchmark(Description = @"Vector256")]
7459
public void D()
7560
{
76-
Xor(_a.Span, _b.Span);
61+
Span<byte> a = _a.Span;
62+
Span<byte> b = _b.Span;
7763

78-
return;
64+
Span<Vector256<byte>> xa = MemoryMarshal.Cast<byte, Vector256<byte>>(a);
65+
ReadOnlySpan<Vector256<byte>> xb = MemoryMarshal.Cast<byte, Vector256<byte>>(b);
7966

80-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
81-
static void Xor(Span<byte> a, Span<byte> b)
82-
{
83-
Vector256<byte> va0 = Unsafe.ReadUnaligned<Vector256<byte>>(ref MemoryMarshal.GetReference(a));
84-
Vector256<byte> va1 = Unsafe.ReadUnaligned<Vector256<byte>>(ref Unsafe.Add(ref MemoryMarshal.GetReference(a), 32));
85-
Vector256<byte> vb0 = Unsafe.ReadUnaligned<Vector256<byte>>(ref MemoryMarshal.GetReference(b));
86-
Vector256<byte> vb1 = Unsafe.ReadUnaligned<Vector256<byte>>(ref Unsafe.Add(ref MemoryMarshal.GetReference(b), 32));
67+
xa.GetRef(0) ^= xb.GetRef(0);
68+
xa.GetRef(1) ^= xb.GetRef(1);
69+
}
8770

88-
(va0 ^ vb0).CopyTo(a);
89-
(va1 ^ vb1).CopyTo(a[32..]);
90-
}
71+
[Benchmark(Description = @"Vector128")]
72+
public void D1()
73+
{
74+
Span<byte> a = _a.Span;
75+
Span<byte> b = _b.Span;
76+
77+
Span<Vector128<byte>> xa = MemoryMarshal.Cast<byte, Vector128<byte>>(a);
78+
ReadOnlySpan<Vector128<byte>> xb = MemoryMarshal.Cast<byte, Vector128<byte>>(b);
79+
80+
xa.GetRef(0) ^= xb.GetRef(0);
81+
xa.GetRef(1) ^= xb.GetRef(1);
82+
xa.GetRef(2) ^= xb.GetRef(2);
83+
xa.GetRef(3) ^= xb.GetRef(3);
9184
}
9285

9386
[Benchmark(Description = @"Unsafe")]
9487
public void E()
9588
{
96-
Xor(_a.Span, _b.Span);
89+
Span<byte> a = _a.Span;
90+
Span<byte> b = _b.Span;
9791

98-
return;
99-
100-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
101-
static unsafe void Xor(Span<byte> a, Span<byte> b)
92+
unsafe
10293
{
10394
fixed (byte* pa = &MemoryMarshal.GetReference(a))
10495
fixed (byte* pb = &MemoryMarshal.GetReference(b))
@@ -110,4 +101,38 @@ static unsafe void Xor(Span<byte> a, Span<byte> b)
110101
}
111102
}
112103
}
104+
105+
[Benchmark(Description = @"UInt128")]
106+
public void F()
107+
{
108+
Span<byte> a = _a.Span;
109+
Span<byte> b = _b.Span;
110+
111+
Span<UInt128> xa = MemoryMarshal.Cast<byte, UInt128>(a);
112+
ReadOnlySpan<UInt128> xb = MemoryMarshal.Cast<byte, UInt128>(b);
113+
114+
xa.GetRef(0) ^= xb.GetRef(0);
115+
xa.GetRef(1) ^= xb.GetRef(1);
116+
xa.GetRef(2) ^= xb.GetRef(2);
117+
xa.GetRef(3) ^= xb.GetRef(3);
118+
}
119+
120+
[Benchmark(Description = @"ulong")]
121+
public void G()
122+
{
123+
Span<byte> a = _a.Span;
124+
Span<byte> b = _b.Span;
125+
126+
Span<ulong> xa = MemoryMarshal.Cast<byte, ulong>(a);
127+
ReadOnlySpan<ulong> xb = MemoryMarshal.Cast<byte, ulong>(b);
128+
129+
xa.GetRef(0) ^= xb.GetRef(0);
130+
xa.GetRef(1) ^= xb.GetRef(1);
131+
xa.GetRef(2) ^= xb.GetRef(2);
132+
xa.GetRef(3) ^= xb.GetRef(3);
133+
xa.GetRef(4) ^= xb.GetRef(4);
134+
xa.GetRef(5) ^= xb.GetRef(5);
135+
xa.GetRef(6) ^= xb.GetRef(6);
136+
xa.GetRef(7) ^= xb.GetRef(7);
137+
}
113138
}

0 commit comments

Comments
 (0)