-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MemoryExtensions to CoreLib and type forward for .NET Core #24107
Comments
SpanHelpers uses vectors though which aren't in coreclr? |
This is why I had initially split the SpanExtension class into separate files and SpanExtensions.cs contained methods that could not be implemented in core: |
Can we instead use the new intrinsics? My understanding is that those will be available in corelib. |
I feel I let myself down with that meme; apologies... |
Just move the dozen .cs files that implement
Eventually. I am not sure whether Intel will be able to get all of them in place for .NET Core 2.1. Also, |
In addition, there are some duplicated methods in the platform now: public static class Span {
public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source) where T : struct;
public static Span<byte> AsBytes<T>(this Span<T> source) where T : struct;
public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text);
public static ReadOnlySpan<char> AsReadOnlySpan(this string text);
public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source) where TFrom : struct where TTo : struct;
public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source) where TFrom : struct where TTo : struct; public static bool TryGetString(this ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length);
}
public static class MemoryExtensions {
public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source) where T : struct;
public static Span<byte> AsBytes<T>(this Span<T> source) where T : struct;
public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text);
public static ReadOnlySpan<char> AsReadOnlySpan(this string text);
public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source) where TFrom : struct where TTo : struct;
public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source) where TFrom : struct where TTo : struct;
public static bool TryGetString(this ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length);
} We should get rid of this duplication as part of this workitem |
I'm not sure moving the Vector class into corelib is going to be that simple. The The hardware intrinsics are coming along. Maybe we should re-evaluate whether we can use them or not. /cc @fiigii @tannergooding @CarolEidt - do you have a timeline when each ISA will be complete? Specifically, it looks like for sure we would need |
I am trying my best to ship all the |
@eerhardt It is not OOB for NET Core. It is inbox on .NET Core and it is tigthly coupled with the JIT. |
I have Provided it gets proper review/sign-off, I think I believe the majority of the remaining work on Sse is containment analysis for better codegen (which I have started on) and adding a lot more tests. Getting the table-driven PR (dotnet/coreclr#15749) resolved and merged will also greatly help accelerate some of these efforts (as less duplicate code needs to be written). |
Agreed. But we also ship a NuGet package out of band that supports |
Pending investigation, performance checks, etc. It might also be possible to rewrite the library to use HWIntrinsics and decouple it from the JIT in the future |
Right. Nothing would change about this NuGet package. We are on the same plan for number of other NuGet packages. |
So the code would be duplicated between |
Right. Nothing would change about this NuGet package. We are on the same duplicated code plan for number of other NuGet packages. E.g. ArrayPool or Span - lives in CoreLib for .NET Core, and slightly different more portable slower implementation ships in NuGet package. |
https://github.com/dotnet/corefx/issues/25188 is about making management of the duplicates easier. |
Regarding |
Moving S.N.Vector down to mscorlib looks not a good idea, which requires many changes in RyuJIT/VM (most changes are about intrinsic recognition). And these changes would become useless soon if we implement S.N.Vector in hardware intrinsic in the future. @ahsonkhan Which vector intrinsics do you need? Maybe I can try to enable them in Intel HW intrinsics at first. |
We need |
So a good portion of Sse, Sse2, Avx, and Avx2 |
And we do not want the complexity of the implementation to go through the roof. E,g. we want the following IndexOf method to be CoreLib: https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/SpanHelpers.byte.cs#L96 |
I do not think it is many changes. |
|
I think that's the only reasonable way to do this. |
@jkotas unlike Span and ArrayPool, Vectors ships an OOB implementation for netcoreapp which allows the application to override the inbox version cleanly. I'm not sure if we have a great scenario to ship updates with the application but we eliminate that as a possibility if we move it into CoreLib. We also require the JIT intrinsics to be different and I suspect we will need to make them recognize both CoreLib and Vectors library for finding them. Beyond the intrinics we may need to carry the IL fallback implementation in corelib which is a decent size increase (~228KB). To me that seems like a pretty high price just for one method in Span. |
I can see both sides of this, but I hope that we don't make a decision in the interest of short-term expediency, rather than what is the best long-term approach. Perhaps there is some obvious flaw in my thinking, but I believe that one of the main sources of size & complexity of the IL implementation is that it must support variable-sized vectors. At that time, we didn't use the "mustExpand when recursive" approach, so the IL implementation had to support variable-length vectors in the event that the method was exposed indirectly, or was exposed for the purposes of diagnostic tools, etc. What if the IL implementation only had to deal with a default vector size (e.g. 16 bytes)? It could look something like this (pseudo code for method Foo on a Vector v)
What have I missed? If we went the route of supporting both methods for recognizing |
That makes sense to me. The code should be functionally equivalent to before, so back-compat doesn't seem like a concern. It would likely also produce a perf improvement for any indirect calls to the methods. I put some of my thoughts on this (the general topic) here, but it can basically be summed up as:
|
I would not call this a clean override. Vectors are coupled with the JIT. If app overrides the inbox version and there are new methods added, they will not be accelerated by the old JIT and it is hard to reason about how to write a performant code against it under these conditions. When we were versioning System.Numerics independently in .NET Framework, I have seen people writing code that checked clrjit.dll version to figure out which methods on Vector are good and fast, and then pick the right algorithm implementation based on that.
It is not just one method in Span. There are number of them on Span, and folks wanted to use in CoreLib outside the Span for performance optimizations.
This is just moving the bytes from one .dll to other .dll that ship together. I do not think it has any material negative impact at end-to-end metrics, like .NET Core runtime distro size. In fact, having this in corelib sets us up to not compile in the IL fallback on platforms that do not need it. E.g. we require SSE2+ on x86 and x64 today and so it should be safe to assume that I think that the alternative is to leave System.Numerics alone and create a smaller internal |
There is large group of most basic algorithms which were successfully vectorized and in .NET Core large part of them lives in CoreLib. Once |
I don't personally have a strong opinion in either direction I just wanted to make sure we are considering all the options and understand the implications. Looks like @eerhardt and @ViktorHofer are the current owners for this library according to https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/issue-guide.md so the decision is up to them. |
cc'ing @terrajobst as well |
Could type forward the Span methods and use intrinsics rather than Would mean it would be a completely different implementation to corefx though |
To be clear, we will still have the MemoryExtensions class with all the APIs implemented in System.Memory.dll for the portable span. For netcore specifically though, we will type forward down to corelib. This will result in some duplication (which we can manage by the mirroring that was recently setup, cc @tarekgh). Does anyone have concerns with this approach? @eerhardt, what's the verdict? |
Do we have to duplicate the whole assembly? Or could just How much work would the smaller internal |
I am not really sure since I am still unfamiliar with S.N.V code. I don't know what changes are required on the JIT side, but I would imagine that work would remain unchanged regardless of whether we duplicate the whole assembly or only have an internal Vector<T>. cc @tannergooding, @AndyAyersMS - can you please confirm? |
The work required for internal |
It seems that the best approach is to move |
Where can I find AsBytes? I need this function. |
Wow I googled for it and could not find it. Thanks. |
From thread (for context): dotnet/corefx#25120 (comment)
cc @KrzysztofCwalina, @jkotas, @stephentoub
The text was updated successfully, but these errors were encountered: