Open jkotas opened 7 years ago
@tannergooding just want to add support for the solution expressed in #904. Unless I am missing anything, there is currently no way to use our own simple math types and expect the same performance as Vector3 when doing SIMD operations. For example, I have a custom math library that closely follow glsl semantics (vec2, vec3, mat4, etc) and can't get my vec3 type to perform efficiently since I pay the price of loading it into a Vector128 each time. This really seems like the best option rather than forcing developers to use framework types.
Interesting, this makes me think about how kerbal space program (written in Unity) does their math. You've got very large numbers in the hundreds of millions or billions with precision at the 0.01 level. At the same time though all double math would likely be too expensive.
@serp777, yes they cover a few of the standard approaches to solving this in the video. You can see this in other games as well particularly those with modding support such as Minecraft (chunks), or Elder Scrolls (cells), etc. There are tons of papers covering the techniques and approaches that allow all of this to work, including at scale.
Its also worth noting that
double
math isn't itself "expensive". That isfloat + float
anddouble + double
both execute in about 2-3 cycles (going back to at least 2016) and this also applies to most other operations that have hardware support. What makesfloat
faster is when you're using SIMD, as you can then do twice as many operations in the same instruction or when memory is a bottleneck since you can do the same number of operations while using half the memory.
Thanks for this response. One thing I will say is that doubles can be slower beyond just pure operations. For example if I have a class with 20 doubles vs 20 floats, the class with 20 doubles will be twice as big. This quite possibly means twice as much memory pressure, more GC needed, etc. Moving memory around or copying it etc can also be very slow. So if I have gigabytes worth of memory constituted from this hypothetical class, using floats vs doubles could massively improve performance depending on the load that occurs. I mention this specifically because I know KSP has had serious issues with garbage collection and memory pressure. It used to be when playing it would stutter heavily every 3 seconds depending on mods and craft size because of the GC.
Are there any updates? .NET 7 and generic math now available. Why we still have no simd accelerated double precision vectors, matrices, etc.? This is important for games and scientific applications.
Are there any updates? .NET 7 and generic math now available. Why we still have no simd accelerated double precision vectors, matrices, etc.? This is important for games and scientific applications.
For now you can use the Vector128<T>
and Vector256<T>
SIMD types. Keep in mind that their size if fixed to 16 or 32 bytes and so the amount of Ts you can store there varies.
You also need to check whether IsHardwareAccelerated is true on those, otherwise you'll end up with slow software fallbacks. (Vector256 will for example be never accelerated on ARM64 CPUs).
Why we still have no simd accelerated double precision vectors, matrices, etc.? This is important for games and scientific applications.
The API surface needs to be re-reviewed to account for generic math. It is also a non-trivial amount of work, especially if it is to be hardware accelerated as well.
Vector4 as double. Any hope in .NET 8?
This is still something I am very interested in finishing an pushing through. Unfortunately, due to competing priorities its not likely going to be in for .NET 8.
There is significant design work required to ensure the API surface is correct and forward compatible. The implementation cost, particularly to ensure it is performant, is likewise non-trivial.
If the BCL contained Vector2
@SparkieLabs The design for this, while currently approved, does not account for generic maths (originally this was going to be a fixed API surface, and manually specialized implementations which would throw if an unsupported T is used) which vastly changes the implications of expanding System.Numerics. It is true that noone will object to the currently approved surface, but at the same time given recent developments more can definitely be done here. There are other libraries that fill in these blanks (such as Silk.NET.Maths) in the meantime.
Agreed they should be generic. The problem isn't a lack of community libraries with these types its the abundance of them (I've even got my own generic version). Different libraries all having there own types adds friction to interworking say Silk.NET and geometry4Sharp), that's what I think the focus should be on solving.
There has to be a consideration for versioning such APIs over time, however.
Simply throwing up a few types is simple. Ensuring those types have the right shape so that they can be made performant, such that they don't lead to UB, such that they can support the types developers need, etc. That takes time and effort to design.
In the interim, we have APIs like TTo Unsafe.BitCast<TFrom, TTo>(TFrom value)
which allow safely and efficiently reinterpreting (without making it address taken) same sized value types which can be used to ease the interop of the various types custom libraries have.
Exposing another type in the BCL doesn't fix the issue itself, it just compounds to their being "yet another" type that you have to consider, the one difference is that its "in box" so it can be the common interchange between them, but ultimately you would still need to do "two casts" to go from JanesVector4Double
to JimsVector4Double
(where-as BitCast
gives it to you in 1).
Quick look into Intel architecture document shows SIMD instructions for double precision floating points were available with Pentium 4 (see SSE2 for details).
@vukovinski Thanks for that info. The hardware company knows that SIMD with double is a priority, only Microsoft thinks otherswise.
We already provide all the necessary APIs and functionality for someone to roll their own fully SIMD accelerated double-precision Vector2/3/4 types.
Additionally, no one has said that double
isn't a "priority". It's simply been stated that there is quite a substantial amount of design work that needs to be done before the proposal can move forward again.
@tannergooding Your last comment is interesting: We already provide all the necessary APIs and functionality for someone to roll their own fully SIMD accelerated double-precision Vector2/3/4 types.
Is there any description for that? I tried with attribute [Intrinsic] but it didn’t work.
@tannergooding I think there's two separate cases that need to be handled by numeric types: maths and interop.
I agree that in order to support generic maths requires extensive R&D, but not so for interop, and I don't think having a few more commonly used types would harm.
So what I think what people is asking is that while we wait for perfection, it could be desirable to have some temporary solution, something in between.
I understand that temporary solution could not fit into system.numeric.vectors.. So I would like to propose to have a CommunityToolkit.Numeric.Vectors or something like that. After all, CommunityToolkit is being used to fill the gap of things that are commonly needed by the community but don't quite fit into the CLR
I know silk.net has been proposed, and it's not bad at all, but it's not so widely adopted either to become a type exchange library.
I tried with attribute [Intrinsic] but it didn’t work.
@Aniobodo, [Intrinsic]
is an internal only attribute for the runtime so that the runtime can specialize semantics internally. Such as providing custom type layout or specialized node handling to help with overall JIT throughput.
User code has access to the System.Runtime.Intrinsics
namespace which provides access to platform-specific (since .NET Core 3.1) and cross-platform (since .NET 7) hardware intrinsics, much like C/C++ provide.
Interested parties would utilize this in their own types, such as https://source.terrafx.dev/#TerraFX/Numerics/Vector4.cs,927e43c5390e4e41, to provide the underlying acceleration appropriate.
I understand that temporary solution could not fit into system.numeric.vectors.. So I would like to propose to have a CommunityToolkit.Numeric.Vectors or something like that. After all, CommunityToolkit is being used to fill the gap of things that are commonly needed by the community but don't quite fit into the CLR
@vpenades, I already touched on this above.
If we were to expose some CommunityToolkit.Numerics.Vector
purely for interop, it would effectively just be identical to a named version of ValueTuple<double, double>
for Vector2
. This wouldn't then be usable as the interchange type when the System.Numerics.Vector2<T>
comes about in the future, due to layering, and so it does in fact ultimately hurt things more in the long run.
Exposing one more type doesn't fix the root interchange issue. Nor does it fix the issue of differing libraries actually adopting the "one more type" as the actual interchange type. There will always be a need for users to work around a lack of common type, either because the library in question isn't using it or because of performance.
APIs like ref TTo Unsafe.As<TFrom, TTo>(ref TFrom value)
and as of .NET 8 TTo Unsafe.BitCast<TFrom, TTo>(TFrom value)
exist specifically to help solve this scenario and allow reinterpreting bits of type TFrom
as bits of type TTo
.
Value Tuples (particularly with the general language decomposition support) are another good option, as is the Vector128<T>
(particularly from the perf perspective) from the System.Runtime.Intrinsics
namespace. You can also utilize the Vector256<T>
or in .NET 8 the Vector512<T>
type for similar benefits, this is particularly the case on x86/x64, or in .NET 8 on "all platforms" since they are 2x and 4x Vector128<T>
, respectively.
I am personally committed to ensuring this happens, but it needs to be done correctly and needs to be done in relation to other important work that is more broadly impactful to .NET in general.
Vector2/3/4<T>
.Vector512<T>
and the corresponding AVX512 support. This will have general benefits to modern hardware throughout the entirety of the BCL. Such functionality not only allows improving existing SIMD accelerated workloads (such as Span, LINQ, text transcoding, etc), but it also will improve almost all floating-point related code due to powerful new instructions. -- This is true for scalar, 128-bit, 256-bit, and 512-bit code.BigInteger
rewrite. With the advent of generic math this domain is at an inflection point. If Microsoft delivers an offering in .NET 9 the community will rally around it. It they don’t the .NET generic vector space will be the same fragmented mess as the non-generic space is today.
I am told that the future is the metaverse and the fundamental particles of the metaverse are vectors, matrices and quaternions.
I should add that the current System.Numerics.Vectors float implementations are excellent and thanks for all the work you do on them.
@SparkieLabs also, choice operators, but thats another story
Are there any updates on the status of this?
There is a lot of ongoing work in the various spaces of intrinsics and only so much time to get it all done.
This work item in particular is still pending an updated and forward thinking proposal that takes into account generic math
, includes newly introduced API surface, and factors in the considerations of what does or doesn't make sense in a generic context.
The last bit is notably the part that needs the most thought because there is a desire from the community to ensure that Vector2<T>
works with integers
or floating-point
types. However, many of the concepts around these types of Euclidean vectors only make sense for floating-point types and so we really need to think on how this should be split/exposed. This includes thinking around if we should expose both Vector2I<T> where T : IBinaryInteger<T>
and Vector2F<T> where T : IFloatingPointIeee754<T>
(but maybe with better names), etc.
API design is not trivial and it requires significant investment to ensure that we end up with a viable API surface that won't require us to introduce yet another type that doesn't quite mesh in the future and while the immediate ask of supporting just double
is more simple, we can't only consider that when thinking about what to do here since the needs in this space are known to be broader in practice.
If someone is willing to help do the work to drive an updated proposal, I'd be happy to set aside some time to sync with them on a basic outline that I believe would work and then follow up with them after they've gotten the design doc (which would include rationale, examples, and needs elaborated on) written up. That would unblock this from going to API review and then the basic implementation being provided
However, many of the concepts around these types of Euclidean vectors only make sense for floating-point types and so we really need to think on how this should be split/exposed.
Should we really limit the implementation to the meaning of Euclidean vectors? Maybe there is a workaround that will allow us to implement vectors that are constrainted by interfaces only, but still use their own logic for integers or floatings? This will definitely allow people to do a lot of useful custom things based on generic math interfaces.
I'm just interesting, cause it's obvious that after dividing the vectors according to Euclidean, there will be no way back.
These are already Euclidean vectors, by definition. General purpose mathematical vectors or explicit SIMD vectors are different concepts and already exposed or are being exposed by a different set of APIs.
That is, Vector2/3/4
, Matrix4x4
, Quaternion
, Plane
, etc are explicit specializations designed for and around things like graphics and physics. There isn't really a desire to make it more broad outside those concepts because things like System.Runtime.Intrinsics.Vector64/128/256/512<T>
and System.Numerics.Vector<T>
exist for SIMD, while System.Numerics.Tensors.TensorPrimitives
and the likely eventual Tensor<T>
(or similarly shaped API) are designed for the broader mathematical/AI/ML usage of scalars/vectors/matrices/tensors
in exploring how Vector3 is written in .NET 9, it seems that many calls are now going to AsVector128Unsafe()
. For double precision, would one be able to just copy this class and make a double precision Vector3 by changing these to AsVector512Unsafe()
?
It'd be AsVector256Unsafe
, but it's a bit more complicated in practice.
Unlike Vector128
which is largely the core SIMD primitive that exists on all hardware with SIMD support, Vector256
tends to be more limited and x86/x64 specific. As such, you'd really need to detect acceleration and use either 1x Vector256 or 2x Vector128 operations to do the work for Vector3/4. For Vector2 it'd always be 1x Vector128 operation.
This will cause most of the right things to happen, but notably there's still some minor special handling for the System.Numerics.Vector*
types that can't be provided to user-defined structs and so some other minor nuances might also exist leading to it being subpar. Ideally we'll get to a point where it isn't unique to in-box types, but there's a lot of work needed before that is possible.
The approved API is here: https://github.com/dotnet/runtime/issues/24168#issuecomment-642847557
Due to the size of the approved surface area, it is being split into multiple sections for people who want to help implement it. You can see https://github.com/dotnet/runtime/issues/24168#issuecomment-642894470 for more details
Vector2, Vector3, Vector4, Matrix3x2, Matrix4x4, Plane, Quaternion are currently implemented with single precission numbers. Theare are requests (above) and some miror implementations of System.Numerics.* can be found across Internet where double is supported.
These classes should support float and double precission and maybe in future more types. One of possile solution is to miror them as generics with support for both double and single precission numbers.
Rationale and Usage
This is request that developers ask about, one of usages is CAD software.
For example, to use Vector3 and Matrix4x4 with double precission we will be able to write:
Proposed API (mirrored from Vector2, Vector3, Vector4, Matrix3x2, Matrix4x4, Plane)
The following APIs are duplicates of the existing
float
based APIs, but withfloat
replaced withT
to allow forfloat
,double
, and in the futureSystem.Half
.File Vector2OfT.cs
File Vector2_IntrinsicsOfT.cs
File Vector3OfT.cs
File Vector3_IntrinsicsOfT.cs
File Vector4OfT.cs
File Vector4OfT_Intrinsics.cs
File Matrix3x2OfT.cs
File Matrix4x4ofT.cs
File PlaneOfT.cs
File QuaternionOfT.cs
class Vector2 extended with:
class Vector3 extended with:
class Vector4 extended with:
class Matrix3x2 extended with:
class Matrix4x4 extended with:
class Quaternion extended with:
class Plane extended with:
Original Text
From @acecebov on August 25, 2017 16:50
Add support System.Numerics.Vectors types with double precision: Vector2d, Vector3d, Vector4d, Matrix3x2d, Matrix4x4d, PlaneD, QuaternionD.
There are lots of scientific/gaming cases when we want to work with double precision and benefit of SIMD!
Copied from original issue: dotnet/coreclr#13591