-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
577 changed files
with
53,778 additions
and
38,792 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\BrightData\BrightData.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
using System.Runtime.InteropServices; | ||
using System.Runtime.Intrinsics; | ||
using System.Runtime.Intrinsics.X86; | ||
using BenchmarkDotNet.Attributes; | ||
|
||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. | ||
|
||
namespace Benchmarks | ||
{ | ||
public unsafe class Dot | ||
{ | ||
const int Length = 32 * 1024; | ||
float[] data1, data2; | ||
float* _ptr1, _ptr2; | ||
|
||
[GlobalSetup] | ||
public void GlobalSetup() | ||
{ | ||
data1 = Enumerable.Range(0, Length).Select(x => (float)x).ToArray(); | ||
data2 = Enumerable.Range(0, Length).Select(x => (float)(x + 1)).ToArray(); | ||
_ptr1 = GetAligned(data1); | ||
_ptr2 = GetAligned(data2); | ||
} | ||
|
||
[GlobalCleanup] | ||
public void GlobalCleanup() | ||
{ | ||
NativeMemory.AlignedFree(_ptr1); | ||
NativeMemory.AlignedFree(_ptr2); | ||
} | ||
|
||
[Benchmark(Baseline = true)] | ||
public float SimpleDot() => SimpleDot(data1, data2); | ||
|
||
[Benchmark] | ||
public float VectorDot() => VectorDot(data1, data2); | ||
|
||
[Benchmark] | ||
public float VectorDotAligned() => VectorAligned(data1, data2); | ||
|
||
[Benchmark] | ||
public float VectorDotAligned2() => VectorAligned2(_ptr1, _ptr2, Length); | ||
|
||
[Benchmark] | ||
public float VectorDotAligned3() => VectorAligned3(_ptr1, _ptr2, Length); | ||
|
||
public static float SimpleDot(Span<float> data1, Span<float> data2) | ||
{ | ||
var ret = 0f; | ||
var size = data1.Length; | ||
for (var i = 0; i < size; i++) | ||
ret += data1[i] * data2[i]; | ||
return ret; | ||
} | ||
|
||
public static float* GetAligned(Span<float> data) | ||
{ | ||
var size = (uint)(data.Length * sizeof(float)); | ||
var ptr = (float*)NativeMemory.AlignedAlloc(size, 32); | ||
fixed(float* source = data) | ||
NativeMemory.Copy(source, ptr, size); | ||
return ptr; | ||
} | ||
|
||
public static float VectorDot(Span<float> data1, Span<float> data2) | ||
{ | ||
const int VectorSize = 256 / sizeof(float) / 8; | ||
fixed (float* ptr1 = data1) | ||
fixed (float* ptr2 = data2) { | ||
var size = data1.Length; | ||
float* p1 = ptr1, end1 = ptr1 + size; | ||
float* p2 = ptr2; | ||
var vectorSum = Vector256<float>.Zero; | ||
for(int i = 0, numVectors = size / VectorSize; i < numVectors; i++) { | ||
var left = Avx.LoadVector256(p1); | ||
p1 += VectorSize; | ||
var right = Avx.LoadVector256(p2); | ||
p2 += VectorSize; | ||
vectorSum += left * right; | ||
} | ||
|
||
// sum the result vector | ||
var temp = stackalloc float[VectorSize]; | ||
Avx.Store(temp, vectorSum); | ||
var ret = 0f; | ||
for (var i = 0; i < VectorSize; i++) | ||
ret += temp[i]; | ||
|
||
// sum any remaining values | ||
while (p1 < end1) | ||
ret += *p1++ * *p2++; | ||
|
||
return ret; | ||
} | ||
} | ||
|
||
public static float VectorAligned(Span<float> data1, Span<float> data2) | ||
{ | ||
const int VectorSize = 256 / sizeof(float) / 8; | ||
var ptr1 = GetAligned(data1); | ||
var ptr2 = GetAligned(data2); | ||
|
||
try { | ||
var size = data1.Length; | ||
float* p1 = ptr1, end1 = ptr1 + size; | ||
float* p2 = ptr2; | ||
var vectorSum = Vector256<float>.Zero; | ||
for (int i = 0, numVectors = size / VectorSize; i < numVectors; i++) { | ||
var left = Avx.LoadAlignedVector256(p1); | ||
p1 += VectorSize; | ||
var right = Avx.LoadAlignedVector256(p2); | ||
p2 += VectorSize; | ||
vectorSum += left * right; | ||
} | ||
|
||
// sum the result vector | ||
var temp = stackalloc float[VectorSize]; | ||
Avx.Store(temp, vectorSum); | ||
var ret = 0f; | ||
for (var i = 0; i < VectorSize; i++) | ||
ret += temp[i]; | ||
|
||
// sum any remaining values | ||
while (p1 < end1) | ||
ret += *p1++ * *p2++; | ||
return ret; | ||
} | ||
finally { | ||
NativeMemory.AlignedFree(ptr1); | ||
NativeMemory.AlignedFree(ptr2); | ||
} | ||
} | ||
|
||
public static float VectorAligned2(float* ptr1, float* ptr2, int size) | ||
{ | ||
const int VectorSize = 256 / sizeof(float) / 8; | ||
|
||
float* p1 = ptr1, end1 = ptr1 + size; | ||
float* p2 = ptr2; | ||
var vectorSum = Vector256<float>.Zero; | ||
for (int i = 0, numVectors = size / VectorSize; i < numVectors; i++) { | ||
var left = Avx.LoadAlignedVector256(p1); | ||
p1 += VectorSize; | ||
var right = Avx.LoadAlignedVector256(p2); | ||
p2 += VectorSize; | ||
vectorSum += left * right; | ||
} | ||
|
||
// sum the result vector | ||
var temp = stackalloc float[VectorSize]; | ||
Avx.Store(temp, vectorSum); | ||
var ret = 0f; | ||
for (var i = 0; i < VectorSize; i++) | ||
ret += temp[i]; | ||
|
||
// sum any remaining values | ||
while (p1 < end1) | ||
ret += *p1++ * *p2++; | ||
return ret; | ||
} | ||
|
||
public static float VectorAligned3(float* ptr1, float* ptr2, int size) | ||
{ | ||
const int VectorSize = 256 / sizeof(float) / 8; | ||
|
||
float* p1 = ptr1, end1 = ptr1 + size; | ||
float* p2 = ptr2; | ||
var vectorSum = Vector256<float>.Zero; | ||
|
||
// bulk vector sum | ||
var vectorIndex = 0; | ||
var numVectors = size / VectorSize; | ||
for (var numBulkVectors = numVectors / 4 * 4; vectorIndex < numBulkVectors; vectorIndex += 4) { | ||
var a1 = Avx.LoadAlignedVector256(p1); | ||
var b1 = Avx.LoadAlignedVector256(p1 + VectorSize); | ||
var c1 = Avx.LoadAlignedVector256(p1 + VectorSize * 2); | ||
var d1 = Avx.LoadAlignedVector256(p1 + VectorSize * 3); | ||
p1 += VectorSize * 4; | ||
|
||
var a2 = Avx.LoadAlignedVector256(p2); | ||
var b2 = Avx.LoadAlignedVector256(p2 + VectorSize); | ||
var c2 = Avx.LoadAlignedVector256(p2 + VectorSize * 2); | ||
var d2 = Avx.LoadAlignedVector256(p2 + VectorSize * 3); | ||
p2 += VectorSize * 4; | ||
|
||
vectorSum += a1 * a2; | ||
vectorSum += b1 * b2; | ||
vectorSum += c1 * c2; | ||
vectorSum += d1 * d2; | ||
} | ||
|
||
// vector sum | ||
for (; vectorIndex < numVectors; vectorIndex++) { | ||
var left = Avx.LoadAlignedVector256(p1); | ||
p1 += VectorSize; | ||
var right = Avx.LoadAlignedVector256(p2); | ||
p2 += VectorSize; | ||
vectorSum += left * right; | ||
} | ||
|
||
// sum the result vector | ||
var temp = stackalloc float[VectorSize]; | ||
Avx.Store(temp, vectorSum); | ||
var ret = 0f; | ||
for (var i = 0; i < VectorSize; i++) | ||
ret += temp[i]; | ||
|
||
// sum any remaining values | ||
while (p1 < end1) | ||
ret += *p1++ * *p2++; | ||
return ret; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System.Runtime.InteropServices; | ||
using BenchmarkDotNet.Running; | ||
|
||
namespace Benchmarks | ||
{ | ||
public class Program | ||
{ | ||
static void Main(string[] args) | ||
{ | ||
BenchmarkSetProperty(); | ||
BenchmarkSum(); | ||
BenchmarkDot(); | ||
} | ||
|
||
static void BenchmarkSetProperty() | ||
{ | ||
BenchmarkRunner.Run<SetPropertyFromExpression>(); | ||
} | ||
|
||
static void BenchmarkSum() | ||
{ | ||
var data1 = Enumerable.Range(0, 256).Select(x => (float)x).ToArray(); | ||
Console.WriteLine($"Sum Baseline: {Sum.SimpleSum(data1):N0}"); | ||
Console.WriteLine($"Vector Sum: {Sum.VectorSum(data1):N0}"); | ||
Console.WriteLine($"Vector Sum 2: {Sum.VectorSum2(data1):N0}"); | ||
Console.WriteLine($"Vector Sum 3: {Sum.VectorSum3(data1):N0}"); | ||
Console.WriteLine($"Vector Aligned: {Sum.VectorAligned(data1):N0}"); | ||
Console.WriteLine($"Vector Bulk Aligned:{Sum.VectorBulkAligned(data1):N0}"); | ||
BenchmarkRunner.Run<Sum>(); | ||
} | ||
|
||
static unsafe void BenchmarkDot() | ||
{ | ||
var data1 = Enumerable.Range(0, 256).Select(x => (float)x).ToArray(); | ||
var data2 = Enumerable.Range(0, 256).Select(x => (float)(x+1)).ToArray(); | ||
var alignedPtr1 = Dot.GetAligned(data1); | ||
var alignedPtr2 = Dot.GetAligned(data2); | ||
try { | ||
Console.WriteLine($"Baseline: {Dot.SimpleDot(data1, data2):N0}"); | ||
Console.WriteLine($"Vector Dot: {Dot.VectorDot(data1, data2):N0}"); | ||
Console.WriteLine($"Vector Dot Aligned: {Dot.VectorAligned(data1, data2):N0}"); | ||
Console.WriteLine($"Vector Dot Aligned2:{Dot.VectorAligned2(alignedPtr1, alignedPtr2, 256):N0}"); | ||
Console.WriteLine($"Vector Dot Aligned3:{Dot.VectorAligned3(alignedPtr1, alignedPtr2, 256):N0}"); | ||
BenchmarkRunner.Run<Dot>(); | ||
} | ||
finally { | ||
NativeMemory.Free(alignedPtr1); | ||
NativeMemory.Free(alignedPtr2); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using BenchmarkDotNet.Attributes; | ||
using System.Linq.Expressions; | ||
using System.Reflection; | ||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. | ||
|
||
namespace Benchmarks | ||
{ | ||
public class SetPropertyFromExpression | ||
{ | ||
struct TestStruct | ||
{ | ||
public int SomeField; | ||
|
||
public readonly override string ToString() => $"{SomeField}"; | ||
} | ||
|
||
[Params(100, 1000, 10000)] | ||
public int Size { get; set; } | ||
|
||
TestStruct[] _structs; | ||
int[] _values; | ||
|
||
[GlobalSetup] | ||
public void SetupData() | ||
{ | ||
_structs = new TestStruct[Size]; | ||
_values = Enumerable.Range(0, Size).ToArray(); | ||
} | ||
|
||
|
||
[Benchmark(Baseline = true)] | ||
public void Direct() | ||
{ | ||
for(var i = 0; i < _structs.Length; i++) | ||
_structs[i].SomeField = _values[i]; | ||
} | ||
|
||
[Benchmark] | ||
public void SetPropertyDirect() | ||
{ | ||
SetPropertyDirect(_values, _structs, (ref TestStruct obj, int val) => obj.SomeField = val); | ||
} | ||
|
||
[Benchmark] | ||
public void ViaSetter() | ||
{ | ||
SetPropertyViaSetter<TestStruct, int>(_values, _structs, x => x.SomeField); | ||
} | ||
|
||
[Benchmark] | ||
public void ViaReflection() | ||
{ | ||
SetPropertyViaReflection<TestStruct, int>(_values, _structs, x => x.SomeField); | ||
} | ||
|
||
public delegate void SetPropertyDelegate<T, in PT>(ref T item, PT value); | ||
public static void SetPropertyViaSetter<T, P>(ReadOnlySpan<P> input, Span<T> output, Expression<Func<T, P>> property) where P : notnull | ||
{ | ||
var prop = ((MemberExpression)property.Body).Member; | ||
var typeParam = Expression.Parameter(typeof(T).MakeByRefType()); | ||
var valueParam = Expression.Parameter(typeof(P)); | ||
var setter = Expression.Lambda<SetPropertyDelegate<T, P>>(Expression.Assign(Expression.MakeMemberAccess(typeParam, prop), valueParam), typeParam, valueParam).Compile(); | ||
|
||
var index = 0; | ||
foreach (ref var item in output) | ||
setter(ref item, input[index++]); | ||
} | ||
|
||
public static void SetPropertyViaReflection<T, P>(ReadOnlySpan<P> input, Span<T> output, Expression<Func<T, P>> property) where P : notnull | ||
{ | ||
var prop = (FieldInfo)((MemberExpression)property.Body).Member; | ||
|
||
var index = 0; | ||
foreach (ref var item in output) { | ||
var reference = __makeref(item); | ||
prop.SetValueDirect(reference, input[index++]); | ||
} | ||
} | ||
|
||
public static void SetPropertyDirect<T, P>(ReadOnlySpan<P> input, Span<T> output, SetPropertyDelegate<T, P> setProperty) where P : notnull | ||
{ | ||
var index = 0; | ||
foreach (ref var item in output) | ||
setProperty(ref item, input[index++]); | ||
} | ||
} | ||
} |
Oops, something went wrong.