Skip to content

Conversation

@jasonmalinowski
Copy link
Member

@jasonmalinowski jasonmalinowski commented Oct 10, 2022

When generators are running in the Visual Studio IDE, there's some overhead to having to manage a project that actually has generated output. It requires us to maintain two Roslyn Compilation objects, each which have their own symbol information. These interop generators are producing a file that's effectively empty (just an comment on the top), and since they're installed in all .NET 7.0 applications, they are the reason we'll be having to manage more memory than before. Since the fix is simple enough to only generate the output if necessary, we should do so.

This also will help with telemetry, since we have telemetry that lets us tracking in the wild which generators are producing how many files; if we're always producing exactly one file we won't know how many sessions out there are actually using this generator in a meaningful way.

Fixes #76298

@ghost
Copy link

ghost commented Oct 10, 2022

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

Issue Details

When generators are running in the Visual Studio IDE, there's some overhead to having to manage a project that actually has generated output. It requires us to maintain two Roslyn Compilation objects, each which have their own symbol information. These interop generators are producing a file that's effectively empty (just an comment on the top), and since they're installed in all .NET 7.0 applications, they are the reason we'll be having to manage more memory than before. Since the fix is simple enough to only generate the output if necessary, we should do so.

This also will help with telemetry, since we have telemetry that lets us tracking in the wild which generators are producing how many files; if we're always producing exactly one file we won't know how many sessions out there are actually using this generator in a meaningful way.

Author: jasonmalinowski
Assignees: jasonmalinowski
Labels:

area-System.Runtime.InteropServices

Milestone: -

Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT left a comment

Choose a reason for hiding this comment

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

Thanks!

@jasonmalinowski jasonmalinowski marked this pull request as draft October 10, 2022 19:23
@AaronRobinsonMSFT
Copy link
Member

@pavelsavara I think we might also need a fix in the JavaScript interop source generator, right?

@jasonmalinowski
Copy link
Member Author

@AaronRobinsonMSFT: as far as I can tell, this is a common helper used for everything, but unless there's another copy somewhere else I don't know about?

@jasonmalinowski
Copy link
Member Author

Marking as draft since I presume this broke some tests, but I don't know where they are yet.

Copy link
Member

@jkoritzinsky jkoritzinsky left a comment

Choose a reason for hiding this comment

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

LGTM. I believe the JS generator uses the same extension methods to build out the generated sources, so this should cover the JS generators as well.

@jasonmalinowski
Copy link
Member Author

@jkoritzinsky @AaronRobinsonMSFT I assumed this would have broken a test somewhere but I guess there's no negative test asserting no files are produced if nothing is needed. Where should one be added?

@AaronRobinsonMSFT
Copy link
Member

I guess there's no negative test asserting no files are produced if nothing is needed

Likely not. I think the most appropriate place would be after the following tests or integrated into them. These are confirming we compile even though unsafe isn't enabled on the project. You could add a bool that indicates if a file should be generated. @elinor-fung do you have any thoughts on location?

public static IEnumerable<object[]> CodeSnippetsToCompileToValidateAllowUnsafeBlocks()
{
yield return new object[] { ID(), CodeSnippets.TrivialClassDeclarations, TestTargetFramework.Net, true };
{
string source = @"
using System.Runtime.InteropServices;
public class Basic { }
";
yield return new object[] { ID(), source, TestTargetFramework.Standard, false };
yield return new object[] { ID(), source, TestTargetFramework.Framework, false };
yield return new object[] { ID(), source, TestTargetFramework.Net, false };
}
}
[Theory]
[MemberData(nameof(CodeSnippetsToCompileToValidateAllowUnsafeBlocks))]
public async Task ValidateRequireAllowUnsafeBlocksDiagnosticNoTrigger(string id, string source, TestTargetFramework framework, bool allowUnsafe)
{
TestUtils.Use(id);
Compilation comp = await TestUtils.CreateCompilation(source, framework, allowUnsafe: allowUnsafe);
TestUtils.AssertPreSourceGeneratorCompilation(comp);
var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.LibraryImportGenerator());
Assert.Empty(generatorDiags);
TestUtils.AssertPostSourceGeneratorCompilation(newComp);
}

@elinor-fung
Copy link
Member

I think integrating with the one Aaron pointed at makes sense. I would:

  • Remove the case with CodeSnippets.TrivialClassDeclarations and allowUnsafe=true
    • This is already covered by ValidateSnippets
  • Rename to something like ValidateNoLibraryImport and then always create the compilation with allowUnsafe=false and add a check that no source is generated.

When generators are running in the Visual Studio IDE, there's some
overhead to having to manage a project that actually has generated
output. It requires us to maintain two Roslyn Compilation objects,
each which have their own symbol information. These interop generators
are producing a file that's effectively empty (just an <auto-generated>
comment on the top), and since they're installed in all .NET 7.0
applications, they are the reason we'll be having to manage more memory
than before. Since the fix is simple enough to only generate the output
if necessary, we should do so.

This also will help with telemetry, since we have telemetry that lets us
tracking in the wild which generators are producing how many files;
if we're always producing exactly one file we won't know how many
sessions out there are actually using this generator in a meaningful
way.
@jasonmalinowski
Copy link
Member Author

@jkoritzinsky @AaronRobinsonMSFT @elinor-fung Test added, so this would need a small re-review. Otherwise I think it's ready to go?

@AaronRobinsonMSFT AaronRobinsonMSFT self-requested a review October 17, 2022 19:15
@AaronRobinsonMSFT AaronRobinsonMSFT merged commit ba99b91 into dotnet:main Oct 18, 2022
@AaronRobinsonMSFT
Copy link
Member

/backport to release/7.0

@github-actions
Copy link
Contributor

Started backporting to release/7.0: https://github.com/dotnet/runtime/actions/runs/3277608142

@jasonmalinowski jasonmalinowski deleted the avoid-generating-nearly-empty-files branch November 3, 2022 23:20
@ghost ghost locked as resolved and limited conversation to collaborators Dec 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The interop source generators generate an empty file if unused.

4 participants