Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Reduce asm size of CollectionsMarshal.AsSpan#96773

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
stephentoub merged 4 commits intodotnet:mainfromstephentoub:shrinkasspan
Jan 11, 2024

Conversation

@stephentoub
Copy link
Member

Using the span constructor brings with it some branches and code we don't need due to knowledge ofList<T>'s implementation, in particular that a) it always has an array (even if empty), and b) its array is invariant.

Erroneous use of AsSpan while the list is being mutated could have also led to an ArgumentOutOfRangeException from the span's constructor, which doesn't make much sense in this context. I've changed it to be an InvalidOperationException about the invalid concurrent use.

MethodToolchainCode Size
AsSpan\main\corerun.exe99 B
AsSpan\pr\corerun.exe58 B
Sum\main\corerun.exe112 B
Sum\pr\corerun.exe75 B
usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem.Runtime.InteropServices;BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);[DisassemblyDiagnoser]publicclassTests{privatereadonlyList<string>_list=new(){"a","b","c"};[Benchmark]publicSpan<string>AsSpan()=>CollectionsMarshal.AsSpan(_list);[Benchmark]publicintSum(){inttotal=0;foreach(stringsinCollectionsMarshal.AsSpan(_list)){total+=s.Length;}returntotal;}}

Using the span constructor brings with it some branches and code we don't need due to knowledge of `List<T>`'s implementation, in particular that a) it always has an array (even if empty), and b) its array is invariant.Erroneous use of AsSpan while the list is being mutated could have also led to an ArgumentOutOfRangeException, which doesn't make much sense in this context. I've changed it to be an InvalidOperationException about the invalid concurrent use.
@ghost
Copy link

Tagging subscribers to this area: @dotnet/interop-contrib
See info inarea-owners.md if you want to be subscribed.

Issue Details

Using the span constructor brings with it some branches and code we don't need due to knowledge ofList<T>'s implementation, in particular that a) it always has an array (even if empty), and b) its array is invariant.

Erroneous use of AsSpan while the list is being mutated could have also led to an ArgumentOutOfRangeException from the span's constructor, which doesn't make much sense in this context. I've changed it to be an InvalidOperationException about the invalid concurrent use.

MethodToolchainCode Size
AsSpan\main\corerun.exe99 B
AsSpan\pr\corerun.exe58 B
Sum\main\corerun.exe112 B
Sum\pr\corerun.exe75 B
usingBenchmarkDotNet.Attributes;usingBenchmarkDotNet.Running;usingSystem.Runtime.InteropServices;BenchmarkSwitcher.FromAssembly(typeof(Tests).Assembly).Run(args);[DisassemblyDiagnoser]publicclassTests{privatereadonlyList<string>_list=new(){"a","b","c"};[Benchmark]publicSpan<string>AsSpan()=>CollectionsMarshal.AsSpan(_list);[Benchmark]publicintSum(){inttotal=0;foreach(stringsinCollectionsMarshal.AsSpan(_list)){total+=s.Length;}returntotal;}}
Author:stephentoub
Assignees:stephentoub
Labels:

area-System.Runtime.InteropServices

Milestone:-

@jkotas
Copy link
Member

Why is the JIT not able to optimize the original code well?

cc @dotnet/jit-contrib

AaronRobinsonMSFT and ShreyasJejurkar reacted with thumbs up emoji

@stephentoub
Copy link
MemberAuthor

Why is the JIT not able to optimize the original code well?

For starters I assume because it doesn't know that it can elide the null check on the array and elide the variance check on the array, since it's not privvy to the information about how the list was constructed.

@EgorBo
Copy link
Member

EgorBo commentedJan 10, 2024
edited
Loading

For the variance check, minimal repro:

publicclassMyList<T>{publicT[]arr;}boolTest(MyList<string>list)=>list.arr.GetType()==typeof(string[]);

codegen:

; Method Program:Foo(MyList`1[System.String]):ubyte:this (FullOpts)G_M55733_IG01:G_M55733_IG02:movrax, gword ptr[rdx+0x08]movrcx,0xD1FFAB1E      ; System.String[]cmp      qword ptr[rax],rcx       setealmovzxrax,alG_M55733_IG03:ret; Total bytes of code: 24

I bet it lost generic context somewhere during opts..

Querying runtime about current class of field MyList`1[System.__Canon]:arr (declared as System.__Canon[])Field's current class not available[000010] ---XG------                         *  RETURN    int   [000009] ---XG------                         \--*  EQ        int   [000008] #--XG------                            +--*  IND       long  [000002] n--XG------                            |  \--*  IND       ref   [000001] ---X-------                            |     \--*  FIELD_ADDR byref  MyList`1[System.__Canon]:arr[000000] -----------                            |        \--*  LCL_VAR   ref    V00 arg0         [000004] H----------                            \--*  CNS_INT(h) long   0xd1ffab1e class

@stephentoub
Copy link
MemberAuthor

For the variance check

Even if that's fixed for string, though, I imagine the JIT would have a lot more trouble doing it for an arbitrary non-sealed reference type.

@EgorBo
Copy link
Member

For the variance check

Even if that's fixed for string, though, I imagine the JIT would have a lot more trouble doing it for an arbitrary non-sealed reference type.

Sure, but looks like it's should be a general goodness to improve this in JIT too if possible

@stephentoub
Copy link
MemberAuthor

Sure, but looks like it's should be a general goodness to improve this in JIT too if possible

Agreed. Just commenting that this change still improves upon what I imagine the JIT will be able to safely do, unless we build knowledge ofList<T> into it directly.

@jkotas
Copy link
Member

this change still improves upon what I imagine the JIT will be able to safely

Yea, I agree. LGTM.

@EgorBo
Copy link
Member

For the variance check

Even if that's fixed for string, though, I imagine the JIT would have a lot more trouble doing it for an arbitrary non-sealed reference type.

Sure, but looks like it's should be a general goodness to improve this in JIT too if possible

Handled via#96794

stephentouband others added2 commitsJanuary 10, 2024 13:29
…pServices/CollectionsMarshal.csCo-authored-by: Jan Kotas <jkotas@microsoft.com>
@stephentoubstephentoub merged commit4083523 intodotnet:mainJan 11, 2024
@stephentoubstephentoub deleted the shrinkasspan branchJanuary 11, 2024 12:45
tmds pushed a commit to tmds/runtime that referenced this pull requestJan 23, 2024
* Reduce asm size of CollectionsMarshal.AsSpanUsing the span constructor brings with it some branches and code we don't need due to knowledge of `List<T>`'s implementation, in particular that a) it always has an array (even if empty), and b) its array is invariant.Erroneous use of AsSpan while the list is being mutated could have also led to an ArgumentOutOfRangeException, which doesn't make much sense in this context. I've changed it to be an InvalidOperationException about the invalid concurrent use.* Update src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CollectionsMarshal.cs* Update src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CollectionsMarshal.csCo-authored-by: Jan Kotas <jkotas@microsoft.com>---------Co-authored-by: Jan Kotas <jkotas@microsoft.com>
@github-actionsgithub-actionsbot locked and limited conversation to collaboratorsFeb 11, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

@jkotasjkotasjkotas approved these changes

Assignees

@stephentoubstephentoub

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

3 participants

@stephentoub@jkotas@EgorBo

[8]ページ先頭

©2009-2025 Movatter.jp