-
Notifications
You must be signed in to change notification settings - Fork 279
/
Copy pathOneBodyConstraintBenchmarks.cs
115 lines (103 loc) · 7.01 KB
/
OneBodyConstraintBenchmarks.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
using BenchmarkDotNet.Attributes;
using BepuPhysics;
using BepuPhysics.Constraints;
using BepuPhysics.Constraints.Contact;
using BepuUtilities;
using System.Numerics;
namespace DemoBenchmarks;
/// <summary>
/// Evaluates performance of a representative subset of one body constraints. Excluded types are benchmarked in <see cref="OneBodyConstraintBenchmarksDeep"/>.
/// </summary>
/// <remarks>
/// Note that all constraints operate across <see cref="Vector{}.Count"/> lanes simultaneously where T is of type <see cref="float"/>.
/// <para>The number of bundles being executed does not change if <see cref="Vector{}.Count"/> changes; if larger bundles are allowed, then more lanes end up getting solved.</para>
/// </remarks>
[BenchmarkCategory(Categories.BepuPhysics)]
public class OneBodyConstraintBenchmarks
{
public static BodyVelocityWide BenchmarkOneBodyConstraint<TConstraintFunctions, TPrestep, TAccumulatedImpulse>(Vector3Wide positionA, QuaternionWide orientationA, BodyInertiaWide inertiaA, TPrestep prestep)
where TConstraintFunctions : unmanaged, IOneBodyConstraintFunctions<TPrestep, TAccumulatedImpulse> where TPrestep : unmanaged where TAccumulatedImpulse : unmanaged
{
var functions = default(TConstraintFunctions);
var accumulatedImpulse = default(TAccumulatedImpulse);
var velocityA = default(BodyVelocityWide);
//Individual constraint iterations are often extremely cheap, so beef the benchmark up a bit.
const int iterations = 1000;
const float inverseDt = 60f;
const float dt = 1f / inverseDt;
for (int i = 0; i < iterations; ++i)
{
functions.WarmStart(positionA, orientationA, inertiaA, ref prestep, ref accumulatedImpulse, ref velocityA);
functions.Solve(positionA, orientationA, inertiaA, dt, inverseDt, ref prestep, ref accumulatedImpulse, ref velocityA);
}
return velocityA;
}
//Contact constraints for a given bodycount/convexity are very similar. Trimming out the submaximal contact count benchmarks should usually be fine without losing important coverage.
[Benchmark]
public BodyVelocityWide Contact4OneBody()
{
var prestep = new Contact4OneBodyPrestepData
{
Contact0 = new() { Depth = Vector<float>.Zero, OffsetA = Vector3Wide.Broadcast(new Vector3(1, 0, 0)) },
Contact1 = new() { Depth = Vector<float>.Zero, OffsetA = Vector3Wide.Broadcast(new Vector3(1, 0, 0)) },
Contact2 = new() { Depth = Vector<float>.Zero, OffsetA = Vector3Wide.Broadcast(new Vector3(1, 0, 0)) },
Contact3 = new() { Depth = Vector<float>.Zero, OffsetA = Vector3Wide.Broadcast(new Vector3(1, 0, 0)) },
MaterialProperties = new MaterialPropertiesWide
{
FrictionCoefficient = new Vector<float>(1f),
MaximumRecoveryVelocity = new Vector<float>(2f),
SpringSettings = new() { TwiceDampingRatio = new Vector<float>(2), AngularFrequency = new Vector<float>(20 * MathF.PI) }
},
Normal = Vector3Wide.Broadcast(new Vector3(0, 1, 0))
};
QuaternionWide.Broadcast(Quaternion.Identity, out var orientationA);
var inertia = new BodyInertiaWide { InverseInertiaTensor = new Symmetric3x3Wide { XX = Vector<float>.One, YY = Vector<float>.One, ZZ = Vector<float>.One }, InverseMass = Vector<float>.One };
return BenchmarkOneBodyConstraint<Contact4OneBodyFunctions, Contact4OneBodyPrestepData, Contact4AccumulatedImpulses>(new Vector3Wide(), orientationA, inertia, prestep);
}
[Benchmark]
public BodyVelocityWide Contact4NonconvexOneBody()
{
var prestep = new Contact4NonconvexOneBodyPrestepData
{
Contact0 = new() { Depth = Vector<float>.Zero, Offset = Vector3Wide.Broadcast(new Vector3(1, 0, 0)), Normal = Vector3Wide.Broadcast(new Vector3(0, 1, 0)) },
Contact1 = new() { Depth = Vector<float>.Zero, Offset = Vector3Wide.Broadcast(new Vector3(1, 0, 0)), Normal = Vector3Wide.Broadcast(new Vector3(0, 1, 0)) },
Contact2 = new() { Depth = Vector<float>.Zero, Offset = Vector3Wide.Broadcast(new Vector3(1, 0, 0)), Normal = Vector3Wide.Broadcast(new Vector3(0, 1, 0)) },
Contact3 = new() { Depth = Vector<float>.Zero, Offset = Vector3Wide.Broadcast(new Vector3(1, 0, 0)), Normal = Vector3Wide.Broadcast(new Vector3(0, 1, 0)) },
MaterialProperties = new MaterialPropertiesWide
{
FrictionCoefficient = new Vector<float>(1f),
MaximumRecoveryVelocity = new Vector<float>(2f),
SpringSettings = new() { TwiceDampingRatio = new Vector<float>(2), AngularFrequency = new Vector<float>(20 * MathF.PI) }
},
};
QuaternionWide.Broadcast(Quaternion.Identity, out var orientation);
var inertia = new BodyInertiaWide { InverseInertiaTensor = new Symmetric3x3Wide { XX = Vector<float>.One, YY = Vector<float>.One, ZZ = Vector<float>.One }, InverseMass = Vector<float>.One };
return BenchmarkOneBodyConstraint<ContactNonconvexOneBodyFunctions<Contact4NonconvexOneBodyPrestepData, Contact4NonconvexAccumulatedImpulses>,
Contact4NonconvexOneBodyPrestepData, Contact4NonconvexAccumulatedImpulses>(new Vector3Wide(), orientation, inertia, prestep);
}
//Servos and motors tend to be fairly similar. They're not *identical*, though, so we'll use one servo and one motor. The others will be in the deep tests.
[Benchmark]
public BodyVelocityWide OneBodyAngularServo()
{
QuaternionWide.Broadcast(Quaternion.Identity, out var orientation);
var prestep = new OneBodyAngularServoPrestepData
{
ServoSettings = new() { BaseSpeed = Vector<float>.Zero, MaximumForce = new Vector<float>(float.MaxValue), MaximumSpeed = new Vector<float>(float.MaxValue) },
SpringSettings = new() { TwiceDampingRatio = new Vector<float>(2), AngularFrequency = new Vector<float>(20 * MathF.PI) },
TargetOrientation = orientation
};
var inertia = new BodyInertiaWide { InverseInertiaTensor = new Symmetric3x3Wide { XX = Vector<float>.One, YY = Vector<float>.One, ZZ = Vector<float>.One }, InverseMass = Vector<float>.One };
return BenchmarkOneBodyConstraint<OneBodyAngularServoFunctions, OneBodyAngularServoPrestepData, Vector3Wide>(new Vector3Wide(), orientation, inertia, prestep);
}
[Benchmark]
public BodyVelocityWide OneBodyLinearMotor()
{
QuaternionWide.Broadcast(Quaternion.Identity, out var orientation);
var prestep = new OneBodyLinearMotorPrestepData
{
Settings = new() { Damping = Vector<float>.One, MaximumForce = Vector<float>.One },
};
var inertia = new BodyInertiaWide { InverseInertiaTensor = new Symmetric3x3Wide { XX = Vector<float>.One, YY = Vector<float>.One, ZZ = Vector<float>.One }, InverseMass = Vector<float>.One };
return BenchmarkOneBodyConstraint<OneBodyLinearMotorFunctions, OneBodyLinearMotorPrestepData, Vector3Wide>(new Vector3Wide(), orientation, inertia, prestep);
}
}