-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Refer directly to static data when ReadOnlySpan wraps arrays of bytes. #24621
Conversation
@dotnet/roslyn-compiler - please review |
When available, this could be useful to our own tests. We allocate a lot of single-use strings for the code and IL. If plumbed through as |
@stephentoub @jkotas @KrzysztofCwalina - you may like this :-) #Resolved |
@marek-safar Is this going to work for Mono on big endian machines? #Resolved |
IL_0000: call ""string Test.Hello()"" | ||
IL_0005: call ""System.ReadOnlySpan<char> System.ReadOnlySpan<char>.op_Implicit(string)"" | ||
IL_000a: stloc.0 | ||
IL_000b: ldsflda ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=10 <PrivateImplementationDetails>.D2EFCBBA102ED3339947E85F4141EB08926E40E9"" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the PrivateImplementationDetails types have the right alignment in the final binary? (E.g. if the Span element type long, they should be aligned at 8 bytes).
Are there enough breadcrumbs for IL rewriting tools to maintain the alignment? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use the same for ordinary arrays inits.
Would that imply the use for span is ok or span has extra requirements? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InitializeArray gets the breadcrumbs about the element size via the RuntimeFieldHandle argument.
And the old CoreCLR big endian path through InitializeArray (currently unused) is explicitly handling the misasligned case: https://github.com/dotnet/coreclr/blob/46ab1d132c9ad471d79afa20c188c2f9c85e5f20/src/classlibnative/bcltype/arraynative.cpp#L1442 .
The optimization is definitely fine for span of bytes - it would be very useful even for just that. But it may need more plumbing to work well for spans of larger types to handle alignment and endianess. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this memory be written to?
I can re-end in a static ctor #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It cannot be written to. The static data are R/O in IL-only images. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, assuming that runtime can fixup endiannes, it would need to know the size of the "element" in the blob. It cannot know it now.
We refer to the blobs via FieldRVA static fields. The fields have types of appropriate size - byte
, short
, int
, long
or a synthetic struct with .size
.
The types have no meaning in existing cases, only size matters. I.E. 4 shorts will be mapped via a long
field...
What if for the blobs where we care about alignment/endiannes, we always use syntetic struct with .size
specifying the size and .pack
specifying the element size?
Would that be sufficient?
Alternatively the synthetic struct could have a dummy primitive field of appropriate size. - byte
, ..., long
.
Or even the actual element type field, may be even N fields, although that seems a bit of an overkill, since there are often thousands of elements in these blobs.
What are the IL rewriters going to do?
IL rewriters should align on 8 bytes and keep the rest as-is. Most likely they do that already.
FWIW System.Reflection.Metadata
exposes the desired alignment as ManagedPEBuilder.MappedFieldDataAlignment
.
#Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively the synthetic struct could have a dummy primitive field of appropriate size.
I think this would be my pick. There is prior art in managed C++. Managed C++ emits dummy field like that (together with size directive) to control alignment of opaque structs. .pack
does not make any guarantees about alignment today.
IL rewriters should align on 8 bytes and keep the rest as-is. Most likely they do that already.
It would be useful to confirm.
Should the availability of this optimization be controlled via new RuntimeFeature
(for spans of larger types)? #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively the synthetic struct could have a dummy primitive field of appropriate size.
Will add this to the PR, then. And add alignment tests.
Will have to check the rewriters, but I think that is not blocking, just need to tell them.
Need to think about RuntimeFeature
. Maybe. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alrz - FYI. Re: #24249
Whatever is decided here will have effect on the stackalloc initializers. The cpblk
path in initializers is exposed to the endianness in the same way.
Nothing here is actionable to your current PR right now, so this is mostly FYI, but whatever approach is used for big types will have to be used in stackalloc initializers as well. #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we are constrained to 1-byte elements, this is irrelevant now
In reply to: 165826041 [](ancestors = 165826041)
@jkotas that's a good question. I think it depends if used ReadOnlySpan ctor is endian friendly (we are using CoreFX implementation) #Resolved |
It is not. It just takes pointer to raw data. #Resolved |
@jkotas right so it'll break unless the underlying Unsafe class implementation can handle it #Resolved |
I cannot think of a magic in the underlying Unsafe class that can handle it. To make this optimization endianess agnostic, I think we would need a new runtime API. It can be similar to the existing RuntimeHelpers.InitializeArray API. Something like:
|
Yep, that would work #Resolved |
If we go with the new API, how soon can we have it? Also -We will face the same issue with the stackalloc initializers. Efficient implementation would |
Getting this API to .NET Core 2.1 would be a stretch. We are trying to lock down for .NET Core 2.1 stabilization in a week or so.
Yes, it should be simple for littleendian system. But it would be nice to give Mono team time to validate that the design works for bigendian systems before we ship it as stable. #Resolved |
Also, I assume, |
The other advantage of |
Ok, until the https://github.com/dotnet/corefx/issues/26948 is resolved we will not try optimizing the cases where elements are larger then 1 byte. #Resolved |
@VSadov Is this PR ready for review or still design or dependency to figure out? #Resolved |
There is a dependency that is unlikely to be ready soon. I will scale this down to be applicable only to 1-byte sized element types. #Resolved |
Ok. I added the "personal PR" label for now. #Resolved |
…literals. No need to allocate anything in this case.
a9a4534
to
13adbac
Compare
We should do this for Utf8String where there are no endiannes issues. |
Yes, once we have Utf8String literals, this optimization will be applicable. #Resolved |
@dotnet-bot test windows_debug_vs-integration_prtest please #Resolved |
license/cla seems to be stuck #Resolved |
Test ReadOnlySpan initialization from static data (#24621)
Adding an `.editorconfig` using the rules from dotnet/runtime repo. See: * https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md * https://github.com/dotnet/runtime/blob/master/.editorconfig Violating these rules won't fail the build, but Visual Studio will respect these rules when formatting the code and make suggestions. The bulk of the violations were `var` usages. There was one unnecessary usage of `this.`. And the rest were naming static fields with `s_`. In `BitUtility.cs`, I made a slight optimization using the pattern recognized by dotnet/roslyn#24621 instead of prefixing the fields with `s_`. Tagging anyone who has contributed to the C# library (please let me know if I missed anyone): @chutchinson @zgramana @nhustler @HashidaTKS @abbotware @pgovind @stephentoub Closes #7246 from eerhardt/Editorconfig Authored-by: Eric Erhardt <eric.erhardt@microsoft.com> Signed-off-by: Eric Erhardt <eric.erhardt@microsoft.com>
* Use ReadOnlySpan<byte> optimization see: dotnet/roslyn#24621 * Reduce array allocations * Prefer OrdinalIgnoreCase to InvariantCultureIgnoreCase * Use StringComparison.Ordinal with StartsWith * Add readonly to readonly Rect members
* Eliminate array allocation in MimeUtils.Unquote() * Use stackalloc in Header.Unfold() to reduce string allocations * Use stackalloc in Header constructor * Eliminate two buffer allocations in DecodeRfc2231 * Use static ReadOnlySpan<byte> compiler feature to reference to static data directly in the encoders See dotnet/roslyn#24621 & https://vcsjones.dev/csharp-readonly-span-bytes-static/ for more information about the ReadOnlySpan<byte> static array usage.
Refer directly to static data when ReadOnlySpan wraps strings or arrays of primitive literals.
No need to allocate anything in this case.
Fixes:#23358
Related:dotnet/corefx#25413
Ask Mode template not completed
Customer scenario
What does the customer do to get into this situation, and why do we think this
is common enough to address for this release. (Granted, sometimes this will be
obvious "Open project, VS crashes" but in general, I need to understand how
common a scenario is)
Bugs this fixes
(either VSO or GitHub links)
Workarounds, if any
Also, why we think they are insufficient for RC vs. RC2, RC3, or RTW
Risk
This is generally a measure our how central the affected code is to adjacent
scenarios and thus how likely your fix is to destabilize a broader area of code
Performance impact
(with a brief justification for that assessment (e.g. "Low perf impact because no extra allocations/no complexity changes" vs. "Low")
Is this a regression from a previous update?
Root cause analysis
How did we miss it? What tests are we adding to guard against it in the future?
How was the bug found?
(E.g. customer reported it vs. ad hoc testing)
Test documentation updated?
If this is a new non-compiler feature or a significant improvement to an existing feature, update https://github.com/dotnet/roslyn/wiki/Manual-Testing once you know which release it is targeting.