Skip to content

Commit b4d2f16

Browse files
Added System.Reflection.Emit.Lightweight via Nuget to have DynamicMethod available in NETSTandard2.0 as well. Guarded the use of ILEmit with a runtime check and fallback to regular reflection for AOT platforms. Removed software fallbacks that skip Span creation to simplify code, with the ILEmit there is no performance penalty for using Span and the SIMDVectorOperations have a fallback as well. Some code cleanup.
1 parent a365879 commit b4d2f16

5 files changed

Lines changed: 18 additions & 72 deletions

File tree

Benchmarks/VectorTransformBenchmark.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ public AxisAlignedBox2D BoundsSpanSIMDVector()
389389

390390
if (dims == 2 && coordinates.Count >= Vector<float>.Count)
391391
{
392-
var coordSpan = vectorBlock.RawCoordinates().AsSpan();
392+
var coordSpan = coordinates.AsSpan();
393393
var vecSpan = MemoryMarshal.Cast<float, Vector<float>>(coordSpan);
394394
int chunkSize = Vector<float>.Count;
395395

@@ -417,7 +417,7 @@ public AxisAlignedBox2D BoundsSpanSIMDVector()
417417
bounds.YMax = Math.Max(bounds.YMax, maxVector[i + 1]);
418418
}
419419
}
420-
else if(coordinates.Count >= 24) {
420+
else if(coordinates.Count >= Vector<float>.Count * 3) {
421421
var coordSpan = vectorBlock.RawCoordinates().AsSpan();
422422
var vecSpan = MemoryMarshal.Cast<float, Vector<float>>(coordSpan);
423423
//var vecSpanShifted = MemoryMarshal.Cast<float, Vector<float>>(coordSpan.Slice(1));
@@ -787,7 +787,7 @@ public static void Main(string[] args)
787787
debugVec3Rot();
788788
debugVec2Bounds();
789789
debugVec3Bounds();
790-
Type[] benchmarks = { typeof(VectorTranslate) };//typeof(VectorBlockBounds) };//, typeof(VectorTranslate), typeof(VectorRotate) };
790+
Type[] benchmarks = { typeof(VectorBlockBounds) };//typeof(VectorBlockBounds) };//, typeof(VectorTranslate), typeof(VectorRotate) };
791791
var summary = BenchmarkRunner.Run(benchmarks);
792792
}
793793

ReaderWriter/OVFDefinition/OVFDefinition.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<PrivateAssets>all</PrivateAssets>
2929
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3030
</PackageReference>
31+
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
3132

3233
<Protobuf Include="../../submodules/OpenVectorFormat/build_processor_strategy.proto" />
3334
<Protobuf Include="../../submodules/OpenVectorFormat/open_vector_format.proto" />

ReaderWriter/OVFDefinition/ProtoUtils.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,19 @@ You should have received a copy of the GNU Lesser General Public
3737
namespace OpenVectorFormat.Utils
3838
{
3939
/// <summary>
40-
/// Class to hold general, usefull utilites for working with protobuf messages.
40+
/// Class to hold general, useful utilities for working with protobuf messages.
4141
/// </summary>
4242
public static class ProtoUtils
4343
{
4444
//this fieldInfo to access private fields of repeatedField<float> is only calculated once
4545
private static readonly FieldInfo repFieldPrivateArrayFieldInfo = typeof(RepeatedField<float>).GetField("array", BindingFlags.NonPublic | BindingFlags.Instance);
4646

47+
private static readonly Func<RepeatedField<float>, float[]> repFieldArrayDynamicGetter =
4748
#if NETCOREAPP3_0_OR_GREATER
48-
private static readonly Func<RepeatedField<float>, float[]> repFieldArrayDynamicGetter = CreateGetter<RepeatedField<float>, float[]>(repFieldPrivateArrayFieldInfo);
49+
!System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported ?
50+
ReflectGetter :
51+
#endif
52+
CreateGetter<RepeatedField<float>, float[]>(repFieldPrivateArrayFieldInfo);
4953

5054
private static Func<S, T> CreateGetter<S, T>(FieldInfo field)
5155
{
@@ -64,7 +68,11 @@ private static Func<S, T> CreateGetter<S, T>(FieldInfo field)
6468
gen.Emit(OpCodes.Ret);
6569
return (Func<S, T>)getterMethod.CreateDelegate(typeof(Func<S, T>));
6670
}
67-
#endif
71+
72+
private static float[] ReflectGetter(RepeatedField<float> field)
73+
{
74+
return (float[])repFieldPrivateArrayFieldInfo.GetValue(field);
75+
}
6876

6977
/// <summary>
7078
/// Creates a copy of a protobuf message with some fields excluded.
@@ -141,16 +149,11 @@ public static Span<T> AsSpan<T>(this RepeatedField<T> repeatedField)
141149
/// It is not safe to add or remove to and from the repeated field while using the Span,
142150
/// since this might allocate a new private array.
143151
/// </summary>
144-
/// <typeparam name="T"></typeparam>
145152
/// <param name="repeatedField"></param>
146153
/// <returns></returns>
147154
public static Span<float> AsSpan(this RepeatedField<float> repeatedField)
148155
{
149-
#if NETCOREAPP3_0_OR_GREATER
150156
var privateArray = repFieldArrayDynamicGetter(repeatedField);
151-
#else
152-
var privateArray = (float[]) repFieldPrivateArrayFieldInfo.GetValue(repeatedField);
153-
#endif
154157
return privateArray.AsSpan().Slice(0, repeatedField.Count);
155158
}
156159
}

ReaderWriter/OVFDefinition/SIMDVectorOperations.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,12 @@ You should have received a copy of the GNU Lesser General Public
2323
*/
2424

2525
using System;
26-
using System.Collections.Generic;
2726
using System.Numerics;
2827
using System.Runtime.InteropServices;
2928
#if NETCOREAPP3_0_OR_GREATER
3029
using System.Runtime.Intrinsics.X86;
3130
using System.Runtime.Intrinsics;
3231
#endif
33-
using System.Text;
34-
using System.Transactions;
35-
using System.Threading;
3632

3733
namespace OpenVectorFormat
3834
{

ReaderWriter/OVFDefinition/VectorBlockExtensions.cs

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ You should have received a copy of the GNU Lesser General Public
2828
using System.Collections.Generic;
2929
using System.Linq;
3030
using System.Numerics;
31-
using System.Runtime.InteropServices;
32-
#if NETCOREAPP3_0_OR_GREATER
33-
using System.Runtime.Intrinsics;
34-
using System.Runtime.Intrinsics.X86;
35-
#endif
36-
using System.Transactions;
3731
using static OpenVectorFormat.SIMDVectorOperations;
3832

3933
namespace OpenVectorFormat
@@ -442,67 +436,21 @@ public static RepeatedField<float> RawCoordinates(this VectorBlock vectorBlock)
442436
}
443437
}
444438

445-
#if NETCOREAPP3_0_OR_GREATER
446-
[StructLayout(LayoutKind.Sequential, Pack = 4)]
447-
private struct Vec256FromVec3
448-
{
449-
public Vector256<float> vec256;
450-
private float unused;
451-
}
452-
#endif
453-
454439
private static void RotateVector2(RepeatedField<float> coordinates, float angleRad, int dims)
455440
{
456-
if (coordinates.Count % dims != 0) throw new ArgumentException($"coordinates count is {coordinates.Count} but must be a multiple of {dims}");
457-
458-
#if NETCOREAPP3_0_OR_GREATER
459-
if (Avx2.IsSupported & coordinates.Count > 80 * dims)
460-
{
461-
var coordSpan = ProtoUtils.AsSpan<float>(coordinates);
462-
RotateAsVector2(coordSpan, angleRad, dims);
463-
return;
464-
}
465-
#endif
466-
467-
var sin = (float)Math.Sin(angleRad);
468-
var cos = (float)Math.Cos(angleRad);
469-
var nsin = -sin;
470-
471-
for (int i = 0; i < coordinates.Count - 1; i += dims)
472-
{
473-
float xNew = coordinates[i] * cos + coordinates[i + 1] * nsin;
474-
float yNew = coordinates[i] * sin + coordinates[i + 1] * cos;
475-
coordinates[i] = xNew; coordinates[i + 1] = yNew;
476-
}
441+
var coordSpan = coordinates.AsSpan();
442+
RotateAsVector2(coordSpan, angleRad, dims);
477443
}
478444

479445
private static AxisAlignedBox2D Bounds2DFromCoordinates(RepeatedField<float> coordinates, int dims)
480446
{
481447
if (coordinates.Count == 0)
482448
return AxisAlignedBox2DExtensions.EmptyAAB2D();
483-
else if (coordinates.Count > 100 * dims)
449+
else
484450
{
485451
var coordSpan = coordinates.AsSpan();
486452
return SIMDVectorOperations.Bounds2D(coordSpan, dims);
487453
}
488-
else
489-
{
490-
var bounds = new AxisAlignedBox2D()
491-
{
492-
XMin = coordinates[0],
493-
YMin = coordinates[1],
494-
XMax = coordinates[0],
495-
YMax = coordinates[1],
496-
};
497-
for (int i = dims; i < coordinates.Count - 1; i += dims)
498-
{
499-
if (coordinates[i] < bounds.XMin) bounds.XMin = coordinates[i];
500-
if (coordinates[i + 1] < bounds.YMin) bounds.YMin = coordinates[i + 1];
501-
if (coordinates[i] > bounds.XMax) bounds.XMax = coordinates[i];
502-
if (coordinates[i + 1] > bounds.YMax) bounds.YMax = coordinates[i + 1];
503-
}
504-
return bounds;
505-
}
506454
}
507455

508456
/// <summary>
@@ -514,7 +462,6 @@ private static AxisAlignedBox2D Bounds2DFromCoordinates(RepeatedField<float> coo
514462
/// <returns></returns>
515463
public static List<Vector2> ToVector2(this VectorBlock vectorBlock)
516464
{
517-
var list = new List<Vector2>();
518465
switch (vectorBlock.VectorDataCase)
519466
{
520467
case VectorBlock.VectorDataOneofCase.LineSequence:
@@ -556,7 +503,6 @@ public static List<Vector2> ToVector2(this VectorBlock vectorBlock)
556503
/// <returns></returns>
557504
public static List<Vector3> ToVector3(this VectorBlock vectorBlock)
558505
{
559-
var list = new List<Vector2>();
560506
switch (vectorBlock.VectorDataCase)
561507
{
562508
case VectorBlock.VectorDataOneofCase.LineSequence:

0 commit comments

Comments
 (0)