Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, '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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, '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 > 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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, '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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, '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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, '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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz
, '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

Disable EventSource generator in design-time builds - #50741

Merged
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign
Apr 6, 2021
Merged

Disable EventSource generator in design-time builds#50741
stephentoub merged 1 commit into
dotnet:mainfrom
stephentoub:esgdesign

Conversation

@stephentoub

Copy link
Copy Markdown
Member

cc: @sharwell, @chsienki, @benaadams

I think we can get away with this for the EventSource generator, as the values it generates shouldn't be needed while working in the project. But I expect we won't be as lucky with the DllImportGenerator cc: @jkoritzinsky, @AaronRobinsonMSFT. @chsienki, is there a recommendation for how to avoid the impact here for such a generator? My understanding is you're working on a replacement set of APIs, but that we'll need to switch over to using them wholesale in order to get the benefits? Do you know when they'll be available?

@ghost

ghost commented Apr 5, 2021

Copy link
Copy Markdown

I couldn't figure out the best area label to add to this PR. If you have write-permissions please help me learn by adding exactly one area label.

@sharwellsharwell 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.

This is the approach that works for <Analyzer> references; someone with project system experience should verify that the same approach using <ProjectReference> would not be problematic.

@stephentoub

Copy link
Copy Markdown
MemberAuthor

I'm going to merge this. Typing in VS while working in Corelib.csproj is currently painful.

@stephentoub
stephentoub merged commit 29c911e into dotnet:mainApr 6, 2021
@stephentoub
stephentoub deleted the esgdesign branch April 6, 2021 02:35
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

@stephentoub This is unfortunate. I hope there are simply issues with the source generator impl rather than the overall design.

@elinor-fung and @jkoritzinsky I'm going to add an IDE integration validation step to #43060.

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

@AaronRobinsonMSFT in the SG V1 API, it is very difficult to avoid observable typing lag (read: no known solution exists) when both of the following conditions are met, regardless of how fast the source generator itself is:

  1. The project is large
  2. The source generator uses a syntax receiver

I suggested @stephentoub be added to the working group for the SG V2 API, as I do not believe the P/Invoke source generator will be possible to sidestep either of the above, and the workaround in this PR is likely to not work.

@stephentoub

stephentoub commented Apr 6, 2021

Copy link
Copy Markdown
MemberAuthor

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good. cc: @ericstj

@chsienki, when is the new API that addresses this going to be ready to consume? In time to rewrite in-box source generators to use it in .NET 6? Is there an issue tracking it?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@AaronRobinsonMSFT

Copy link
Copy Markdown
Member

This needs to be factored in for any of us considering shipping source generators in .NET 6. The experience right now is not good.

Thankfully the Interop source generator will not be shipping publicly for .NET 6 - only for product build. However, we will want to ensure the product development loop isn't negative profoundly impacted. It sounds like a post-.NET 6 solution is likely so we will be able to consume that prior to an official beta for non-runtime consumption.

@chsienki

Copy link
Copy Markdown
Member

@stephentoub We're targeting a preview for 16.10, but it'll require the user to opt-in until the APIs reach stable.

The issue tracking it is here dotnet/roslyn#51257 although it's not very well defined to be honest (I'll try and go through and create some more granular issues that link to that one for tracking).

Unsure if the timing is going to work for rewriting the inbox generators for the .NET 6 timeline, although we'd obviously like to do so.

@jaredpar

Copy link
Copy Markdown
Member

Anyone have a good explanation of

  1. The actual perf problem that was hit here?
  2. Why they feel the new APIs are going to address that problem?

@sharwell

sharwell commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

The actual perf problem that was hit here?

The generator driver is allocating 14GB/min in GeneratorDriver.RunGenerators because we don't have any way to incrementally update the result for a source generator that uses a syntax receiver. The vast majority of these allocations are deserializing trees that moved to temporary storage since the whole solution doesn't fit in address space at the same time.

Why they feel the new APIs are going to address that problem?

The new pipeline API will allow an O(solution size) algorithm to reduce to an O(document size) algorithm for syntax receivers that have document granularity. In addition, the document needed for incremental update is much more likely to already be in memory because it's the document currently open in the editor.

@jaredpar

Copy link
Copy Markdown
Member

There are plenty of syntax receiver based generators out there that do not exhibit this problem. The receiver here is doing little more than walking the syntax tree which is done many, many times across Roslyn in the IDE. Can you elaborate more on what pattern this generator is using that is causing this behavior?

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality. And yes moving to the new APIs would "fix" the problem because it avoids the work. At the same time my suspicion is that is more masking the existing problem vs. fixing it.

@sharwell

Copy link
Copy Markdown
Contributor

Can you elaborate more on what pattern this generator is using that is causing this behavior?

It's not walking a syntax tree, it's walking every syntax tree. In a large solution like this, the trees don't all fit in process address space at the same time, so a full walk across all the trees will cause many to get moved to temporary storage and others to be read back in. In a project small enough to hold all trees in the process address space without Gen 2 GC forcing them out, most of the allocations go away.

@benaadams

benaadams commented Apr 6, 2021

Copy link
Copy Markdown
Member

Looking at the generator I see a few potential issues, definitely some allocations that could be avoided if they switched to type equality vs. name equality.

Only does a name equality check if the class has an attribute with length 32 or length 23; which should be infrequent?

// Only clasess
if(syntaxNodeisClassDeclarationSyntaxclassDeclaration)
{
// Check if has EventSource attribute before adding to candidates
// as we don't want to add every class in the project
foreach(AttributeListSyntax?calinclassDeclaration.AttributeLists)
{
foreach(AttributeSyntax?caincal.Attributes)
{
// Check if Span length matches before allocating the string to check more
intlength=ca.Name.Span.Length;
if(length!=EventSourceAttribute.Length&&length!=EventSourceAttributeShort.Length)
{
continue;
}

@jaredpar

Copy link
Copy Markdown
Member

Right so this is not a problem with the generator itself but more than the IDE hasn't yet move the generator infrastructure out of process. Hence you're still limited to the 32 bit address space in VS

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

@sharwell

Copy link
Copy Markdown
Contributor

Why is the IDE pulling them all into memory at the same time here? Yes the generator is caching a subset of the trees but not enough to hit the constraints you are mentioning. I would assume the trees are brought in sequentially here, or in parallel, but not clear why everything is being held in memory at once.

It's not pulling them all in at the same time. It's pulling them in as part of a background update, but it leads to significant churn. Items loaded early in one pass are released by the time the pass ends, which means they need to be reloaded during the next pass. When they are reloaded in the next pass, items at the end of the previous pass are released to make room, and those items then need to be reloaded.

The overhead could be reduced if ISyntaxReceiver had an equivalent that only needed the SyntaxTree, since the generator could avoid realizing the syntax tree if the text hash didn't change.

@ghostghost locked as resolved and limited conversation to collaborators May 7, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@stephentoub@AaronRobinsonMSFT@sharwell@chsienki@jaredpar@benaadams@karelz