Skip to content

Commit 54bce96

Browse files
author
Jack Dermody
committed
merge from perf refactor branch
2 parents 562200e + 90ed92c commit 54bce96

File tree

577 files changed

+53778
-38792
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

577 files changed

+53778
-38792
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@
6161
/BrightAPI/UI/.parcel-cache
6262
/BrightAPI/UI/dist
6363
/BrightAPI/UI/node_modules
64+
/BrightData.Table/bin
65+
/BrightData.Table/obj
6466
/Benchmarks/bin
6567
/Benchmarks/obj
6668
/BrightData.Parquet/bin
6769
/BrightData.Parquet/obj
68-
/BrightData.Table/bin
69-
/BrightData.Table/obj

Benchmarks/Benchmarks.csproj

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\BrightData\BrightData.csproj" />
17+
</ItemGroup>
18+
19+
</Project>

Benchmarks/Dot.cs

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
using System.Runtime.InteropServices;
2+
using System.Runtime.Intrinsics;
3+
using System.Runtime.Intrinsics.X86;
4+
using BenchmarkDotNet.Attributes;
5+
6+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
7+
8+
namespace Benchmarks
9+
{
10+
public unsafe class Dot
11+
{
12+
const int Length = 32 * 1024;
13+
float[] data1, data2;
14+
float* _ptr1, _ptr2;
15+
16+
[GlobalSetup]
17+
public void GlobalSetup()
18+
{
19+
data1 = Enumerable.Range(0, Length).Select(x => (float)x).ToArray();
20+
data2 = Enumerable.Range(0, Length).Select(x => (float)(x + 1)).ToArray();
21+
_ptr1 = GetAligned(data1);
22+
_ptr2 = GetAligned(data2);
23+
}
24+
25+
[GlobalCleanup]
26+
public void GlobalCleanup()
27+
{
28+
NativeMemory.AlignedFree(_ptr1);
29+
NativeMemory.AlignedFree(_ptr2);
30+
}
31+
32+
[Benchmark(Baseline = true)]
33+
public float SimpleDot() => SimpleDot(data1, data2);
34+
35+
[Benchmark]
36+
public float VectorDot() => VectorDot(data1, data2);
37+
38+
[Benchmark]
39+
public float VectorDotAligned() => VectorAligned(data1, data2);
40+
41+
[Benchmark]
42+
public float VectorDotAligned2() => VectorAligned2(_ptr1, _ptr2, Length);
43+
44+
[Benchmark]
45+
public float VectorDotAligned3() => VectorAligned3(_ptr1, _ptr2, Length);
46+
47+
public static float SimpleDot(Span<float> data1, Span<float> data2)
48+
{
49+
var ret = 0f;
50+
var size = data1.Length;
51+
for (var i = 0; i < size; i++)
52+
ret += data1[i] * data2[i];
53+
return ret;
54+
}
55+
56+
public static float* GetAligned(Span<float> data)
57+
{
58+
var size = (uint)(data.Length * sizeof(float));
59+
var ptr = (float*)NativeMemory.AlignedAlloc(size, 32);
60+
fixed(float* source = data)
61+
NativeMemory.Copy(source, ptr, size);
62+
return ptr;
63+
}
64+
65+
public static float VectorDot(Span<float> data1, Span<float> data2)
66+
{
67+
const int VectorSize = 256 / sizeof(float) / 8;
68+
fixed (float* ptr1 = data1)
69+
fixed (float* ptr2 = data2) {
70+
var size = data1.Length;
71+
float* p1 = ptr1, end1 = ptr1 + size;
72+
float* p2 = ptr2;
73+
var vectorSum = Vector256<float>.Zero;
74+
for(int i = 0, numVectors = size / VectorSize; i < numVectors; i++) {
75+
var left = Avx.LoadVector256(p1);
76+
p1 += VectorSize;
77+
var right = Avx.LoadVector256(p2);
78+
p2 += VectorSize;
79+
vectorSum += left * right;
80+
}
81+
82+
// sum the result vector
83+
var temp = stackalloc float[VectorSize];
84+
Avx.Store(temp, vectorSum);
85+
var ret = 0f;
86+
for (var i = 0; i < VectorSize; i++)
87+
ret += temp[i];
88+
89+
// sum any remaining values
90+
while (p1 < end1)
91+
ret += *p1++ * *p2++;
92+
93+
return ret;
94+
}
95+
}
96+
97+
public static float VectorAligned(Span<float> data1, Span<float> data2)
98+
{
99+
const int VectorSize = 256 / sizeof(float) / 8;
100+
var ptr1 = GetAligned(data1);
101+
var ptr2 = GetAligned(data2);
102+
103+
try {
104+
var size = data1.Length;
105+
float* p1 = ptr1, end1 = ptr1 + size;
106+
float* p2 = ptr2;
107+
var vectorSum = Vector256<float>.Zero;
108+
for (int i = 0, numVectors = size / VectorSize; i < numVectors; i++) {
109+
var left = Avx.LoadAlignedVector256(p1);
110+
p1 += VectorSize;
111+
var right = Avx.LoadAlignedVector256(p2);
112+
p2 += VectorSize;
113+
vectorSum += left * right;
114+
}
115+
116+
// sum the result vector
117+
var temp = stackalloc float[VectorSize];
118+
Avx.Store(temp, vectorSum);
119+
var ret = 0f;
120+
for (var i = 0; i < VectorSize; i++)
121+
ret += temp[i];
122+
123+
// sum any remaining values
124+
while (p1 < end1)
125+
ret += *p1++ * *p2++;
126+
return ret;
127+
}
128+
finally {
129+
NativeMemory.AlignedFree(ptr1);
130+
NativeMemory.AlignedFree(ptr2);
131+
}
132+
}
133+
134+
public static float VectorAligned2(float* ptr1, float* ptr2, int size)
135+
{
136+
const int VectorSize = 256 / sizeof(float) / 8;
137+
138+
float* p1 = ptr1, end1 = ptr1 + size;
139+
float* p2 = ptr2;
140+
var vectorSum = Vector256<float>.Zero;
141+
for (int i = 0, numVectors = size / VectorSize; i < numVectors; i++) {
142+
var left = Avx.LoadAlignedVector256(p1);
143+
p1 += VectorSize;
144+
var right = Avx.LoadAlignedVector256(p2);
145+
p2 += VectorSize;
146+
vectorSum += left * right;
147+
}
148+
149+
// sum the result vector
150+
var temp = stackalloc float[VectorSize];
151+
Avx.Store(temp, vectorSum);
152+
var ret = 0f;
153+
for (var i = 0; i < VectorSize; i++)
154+
ret += temp[i];
155+
156+
// sum any remaining values
157+
while (p1 < end1)
158+
ret += *p1++ * *p2++;
159+
return ret;
160+
}
161+
162+
public static float VectorAligned3(float* ptr1, float* ptr2, int size)
163+
{
164+
const int VectorSize = 256 / sizeof(float) / 8;
165+
166+
float* p1 = ptr1, end1 = ptr1 + size;
167+
float* p2 = ptr2;
168+
var vectorSum = Vector256<float>.Zero;
169+
170+
// bulk vector sum
171+
var vectorIndex = 0;
172+
var numVectors = size / VectorSize;
173+
for (var numBulkVectors = numVectors / 4 * 4; vectorIndex < numBulkVectors; vectorIndex += 4) {
174+
var a1 = Avx.LoadAlignedVector256(p1);
175+
var b1 = Avx.LoadAlignedVector256(p1 + VectorSize);
176+
var c1 = Avx.LoadAlignedVector256(p1 + VectorSize * 2);
177+
var d1 = Avx.LoadAlignedVector256(p1 + VectorSize * 3);
178+
p1 += VectorSize * 4;
179+
180+
var a2 = Avx.LoadAlignedVector256(p2);
181+
var b2 = Avx.LoadAlignedVector256(p2 + VectorSize);
182+
var c2 = Avx.LoadAlignedVector256(p2 + VectorSize * 2);
183+
var d2 = Avx.LoadAlignedVector256(p2 + VectorSize * 3);
184+
p2 += VectorSize * 4;
185+
186+
vectorSum += a1 * a2;
187+
vectorSum += b1 * b2;
188+
vectorSum += c1 * c2;
189+
vectorSum += d1 * d2;
190+
}
191+
192+
// vector sum
193+
for (; vectorIndex < numVectors; vectorIndex++) {
194+
var left = Avx.LoadAlignedVector256(p1);
195+
p1 += VectorSize;
196+
var right = Avx.LoadAlignedVector256(p2);
197+
p2 += VectorSize;
198+
vectorSum += left * right;
199+
}
200+
201+
// sum the result vector
202+
var temp = stackalloc float[VectorSize];
203+
Avx.Store(temp, vectorSum);
204+
var ret = 0f;
205+
for (var i = 0; i < VectorSize; i++)
206+
ret += temp[i];
207+
208+
// sum any remaining values
209+
while (p1 < end1)
210+
ret += *p1++ * *p2++;
211+
return ret;
212+
}
213+
}
214+
}

Benchmarks/Program.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System.Runtime.InteropServices;
2+
using BenchmarkDotNet.Running;
3+
4+
namespace Benchmarks
5+
{
6+
public class Program
7+
{
8+
static void Main(string[] args)
9+
{
10+
BenchmarkSetProperty();
11+
BenchmarkSum();
12+
BenchmarkDot();
13+
}
14+
15+
static void BenchmarkSetProperty()
16+
{
17+
BenchmarkRunner.Run<SetPropertyFromExpression>();
18+
}
19+
20+
static void BenchmarkSum()
21+
{
22+
var data1 = Enumerable.Range(0, 256).Select(x => (float)x).ToArray();
23+
Console.WriteLine($"Sum Baseline: {Sum.SimpleSum(data1):N0}");
24+
Console.WriteLine($"Vector Sum: {Sum.VectorSum(data1):N0}");
25+
Console.WriteLine($"Vector Sum 2: {Sum.VectorSum2(data1):N0}");
26+
Console.WriteLine($"Vector Sum 3: {Sum.VectorSum3(data1):N0}");
27+
Console.WriteLine($"Vector Aligned: {Sum.VectorAligned(data1):N0}");
28+
Console.WriteLine($"Vector Bulk Aligned:{Sum.VectorBulkAligned(data1):N0}");
29+
BenchmarkRunner.Run<Sum>();
30+
}
31+
32+
static unsafe void BenchmarkDot()
33+
{
34+
var data1 = Enumerable.Range(0, 256).Select(x => (float)x).ToArray();
35+
var data2 = Enumerable.Range(0, 256).Select(x => (float)(x+1)).ToArray();
36+
var alignedPtr1 = Dot.GetAligned(data1);
37+
var alignedPtr2 = Dot.GetAligned(data2);
38+
try {
39+
Console.WriteLine($"Baseline: {Dot.SimpleDot(data1, data2):N0}");
40+
Console.WriteLine($"Vector Dot: {Dot.VectorDot(data1, data2):N0}");
41+
Console.WriteLine($"Vector Dot Aligned: {Dot.VectorAligned(data1, data2):N0}");
42+
Console.WriteLine($"Vector Dot Aligned2:{Dot.VectorAligned2(alignedPtr1, alignedPtr2, 256):N0}");
43+
Console.WriteLine($"Vector Dot Aligned3:{Dot.VectorAligned3(alignedPtr1, alignedPtr2, 256):N0}");
44+
BenchmarkRunner.Run<Dot>();
45+
}
46+
finally {
47+
NativeMemory.Free(alignedPtr1);
48+
NativeMemory.Free(alignedPtr2);
49+
}
50+
}
51+
}
52+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using BenchmarkDotNet.Attributes;
2+
using System.Linq.Expressions;
3+
using System.Reflection;
4+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
5+
6+
namespace Benchmarks
7+
{
8+
public class SetPropertyFromExpression
9+
{
10+
struct TestStruct
11+
{
12+
public int SomeField;
13+
14+
public readonly override string ToString() => $"{SomeField}";
15+
}
16+
17+
[Params(100, 1000, 10000)]
18+
public int Size { get; set; }
19+
20+
TestStruct[] _structs;
21+
int[] _values;
22+
23+
[GlobalSetup]
24+
public void SetupData()
25+
{
26+
_structs = new TestStruct[Size];
27+
_values = Enumerable.Range(0, Size).ToArray();
28+
}
29+
30+
31+
[Benchmark(Baseline = true)]
32+
public void Direct()
33+
{
34+
for(var i = 0; i < _structs.Length; i++)
35+
_structs[i].SomeField = _values[i];
36+
}
37+
38+
[Benchmark]
39+
public void SetPropertyDirect()
40+
{
41+
SetPropertyDirect(_values, _structs, (ref TestStruct obj, int val) => obj.SomeField = val);
42+
}
43+
44+
[Benchmark]
45+
public void ViaSetter()
46+
{
47+
SetPropertyViaSetter<TestStruct, int>(_values, _structs, x => x.SomeField);
48+
}
49+
50+
[Benchmark]
51+
public void ViaReflection()
52+
{
53+
SetPropertyViaReflection<TestStruct, int>(_values, _structs, x => x.SomeField);
54+
}
55+
56+
public delegate void SetPropertyDelegate<T, in PT>(ref T item, PT value);
57+
public static void SetPropertyViaSetter<T, P>(ReadOnlySpan<P> input, Span<T> output, Expression<Func<T, P>> property) where P : notnull
58+
{
59+
var prop = ((MemberExpression)property.Body).Member;
60+
var typeParam = Expression.Parameter(typeof(T).MakeByRefType());
61+
var valueParam = Expression.Parameter(typeof(P));
62+
var setter = Expression.Lambda<SetPropertyDelegate<T, P>>(Expression.Assign(Expression.MakeMemberAccess(typeParam, prop), valueParam), typeParam, valueParam).Compile();
63+
64+
var index = 0;
65+
foreach (ref var item in output)
66+
setter(ref item, input[index++]);
67+
}
68+
69+
public static void SetPropertyViaReflection<T, P>(ReadOnlySpan<P> input, Span<T> output, Expression<Func<T, P>> property) where P : notnull
70+
{
71+
var prop = (FieldInfo)((MemberExpression)property.Body).Member;
72+
73+
var index = 0;
74+
foreach (ref var item in output) {
75+
var reference = __makeref(item);
76+
prop.SetValueDirect(reference, input[index++]);
77+
}
78+
}
79+
80+
public static void SetPropertyDirect<T, P>(ReadOnlySpan<P> input, Span<T> output, SetPropertyDelegate<T, P> setProperty) where P : notnull
81+
{
82+
var index = 0;
83+
foreach (ref var item in output)
84+
setProperty(ref item, input[index++]);
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)