Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Convert small atomic fallbacks to managed - #99011

Merged
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked
Mar 22, 2024
Merged

Convert small atomic fallbacks to managed#99011
jkotas merged 10 commits into
dotnet:mainfrom
MichalPetryka:managed-interlocked

Conversation

@MichalPetryka

@MichalPetrykaMichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
Contributor

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

@ghostghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 27, 2024
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @mangod9
See info in area-owners.md if you want to be subscribed.

Issue Details

Makes the non-intrinsic implementations of Exchange/CompareExchange for small types be implemented as loops using 32b variants instead of calling into native code.

I'm not sure what's the performance difference here as the only platforms that should use those will be RISC-V and Mono (ARM32 is handled with #97792 and LoongArch64 seems trivial to do but I have no way to test it).

I've based the idea for the implementation on the fact that Linux Kernel and Libatomic use such 32b operations for their fallbacks (I took no code from those however as they're both GPL).
The approach also relies on an implementation detail of the GCs with that it'll keep refs backtracked to 4B aligned and in the same object to avoid pinning.

I'm not 100% sure whether doing this in managed makes sense here since it's a lot of code, but it also removed all the C++ paths from 3 runtimes.
cc @jkotas

Author:MichalPetryka
Assignees:-
Labels:

area-System.Threading, needs-area-label

Milestone:-

@filipnavarafilipnavara added community-contribution Indicates that the PR has been added by a community member and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 27, 2024
/// <returns>The original value of <paramref name="location1"/>.</returns>
/// <exception cref="NullReferenceException">The address of location1 is a null pointer.</exception>
[Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is AggressiveInlining here just a copy&paste? It does not sound like a good idea to aggressively inline all this.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this should be similar in size to what native compilers emit for RISC-V and they do inline that.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One benefit to inlining this is that with #99130 it lets the JIT fold most of the bit operations here when passed a ref to a static field.

@jkotas

Copy link
Copy Markdown
Member

I think it is fine to do this for CoreCLR/NativeAOT. As you have said, it is just a fallback that should be only used during platform bring up. We effectively require JIT to expand these inline for best perf.

I am not sure about Mono. @vargaz@AlekseyTs Thoughts?

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

@jkotas

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

cc @gbalykov@HJLeee@wscho77@clamp03@JongHeonChoi@t-mustafin@viewizard

@MichalPetryka

MichalPetryka commented Feb 27, 2024

Copy link
Copy Markdown
ContributorAuthor
exit code 139 means SIGSEGV Illegal memory access. Deref invalid pointer, overrunning buffer, stack overflow etc. Core dumped.

Seems like Mono crashes with this implementation, could somebody say if the implementation assumptions are invalid there or if there's some bug instead?

MichalPetryka added a commit to MichalPetryka/runtime that referenced this pull request Feb 27, 2024
@jkotas

Copy link
Copy Markdown
Member

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

You may want to temporarily enable the fallback implementation for CoreCLR and see whether it passes all tests.

It's currently tested with ARM32 and it asserts which I've fixed in #99019.
I've ran it locally on X64 beforehand and it passed for me (even with GCStress, which would actually be nice to run here).

@clamp03

Copy link
Copy Markdown
Member

It'd be nice if somebody from the Samsung RISC-V team could benchmark this on a RISC-V device to see the performance difference.

I am out of office. @bartlomiejko Could your team can check the performance difference?

@MichalPetryka

MichalPetryka commented Mar 2, 2024

Copy link
Copy Markdown
ContributorAuthor

All failures here seem unrelated, this seems to be only waiting for a review of the assumptions on Mono I think.
EDIT: I've also added some more tests for asserts I've seen locally but that should be fixed with #99019.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

Seems like there's still some assert here:

Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe
ERROR:
Assert failure(PID 26748 [0x0000687c], Thread: 36716 [0x8f6c]): Assertion failed 'CoercedConstantValue<size_t>(vn) != 0' in 'InterlockedDisasm:Cas(int):ubyte' during 'Do value numbering' (IL size 18; hash 0x0e503796; FullOpts)
File: H:\Projects\dotnet\runtime\src\coreclr\jit\valuenum.cpp:1630
Image: H:\Projects\dotnet\runtime\artifacts\bin\coreclr\windows.x64.Checked\CoreRun.exe

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

there's still some assert

Fixed now with #100060.

I am not sure about Mono.

I guess we still need somebody from the Mono team to check this?

@hamarb123hamarb123 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove Unsafe.AsPointer uses

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Co-authored-by: Hamish Arblaster <hamarb123@gmail.com>

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mono LGTM

@MichalPetryka I would leave the small ops in atomic.h - they are generally useful. Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

I would leave the small ops in atomic.h - they are generally useful.

I could do that but I think they're simple enough that they could be readded when needed.

Also it might be worthwhile to open a follow-up issue for mono to add intrinsics for these operations in the JIT and interpreter.

#93488

Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
Comment threadsrc/libraries/System.Private.CoreLib/src/System/Threading/Interlocked.cs Outdated
@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

@jkotas does the musl arm assert here seem related to the changes here for you?
image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

@mangod9

Copy link
Copy Markdown
Member

@jkotas does the musl arm assert here seem related to the changes here for you? image

_ASSERTE((GetComponentSize() <= 2) || IsArray());

This is a known issue logged here: #86273

@MichalPetryka

Copy link
Copy Markdown
ContributorAuthor

This seems ready to merge I think but it'll slightly conflict with #100021 so I'm not sure which one should go in first cc @jkotas

@jkotas

Copy link
Copy Markdown
Member

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@jkotas
jkotas merged commit da95abd into dotnet:mainMar 22, 2024
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Apr 21, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Threadingcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

11 participants

@MichalPetryka@jkotas@clamp03@bartlomiejko@tomeksowi@EgorBo@mangod9@lambdageek@tannergooding@hamarb123@filipnavara