Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allocations: Unroll AdditionalFile extension method #7652

Merged
merged 8 commits into from
Jul 26, 2023

Conversation

martin-strecker-sonarsource
Copy link
Contributor

@martin-strecker-sonarsource martin-strecker-sonarsource commented Jul 24, 2023

Fixes #7440

Tested with Akka.Net in a dotnet build context in a SQ EE SonaryWay run.

This change safes

  • 5GB of string allocations caused by calls to Path.GetFileName
  • 3GB of delegate allocations for the FirstOrDefault lambda argument
  • 1,1 GB for the capture class for the filename parameter.

The total memory allocations are down to 32,5 GB from 41,7GB = 9,2 GB savings (22%)

The number of issues reported stayed the same (3514 warnings).

Before
image

After
image

&& path.EndsWith(fileName, StringComparison.OrdinalIgnoreCase))
{
// The character before the filename (if there is a character) must be a directory separator
if (path.Length - fileName.Length - 1 is >= 0 and var separatorPosition
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is a test case for this: The additional file ends with SonarLint.xml but is named FooBarSonarLint.xml.

public void HotspotConfiguration_GivenDifferentFileName_WillNotFinishInitialization()
{
var sut = new HotspotConfiguration(ruleLoaderMock.Object);
Initialize(sut, "FooBarSonarLint.xml", "fake SonarLintXml content");
ruleLoaderMock.Verify(r => r.GetEnabledRules(It.IsAny<string>()), Times.Never);
}

Comment on lines 48 to 49
&& separator != Path.DirectorySeparatorChar
&& separator != Path.AltDirectorySeparatorChar)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should not take any assumptions about the path separator because AdditionalFiles is just a csc.exe command line parameter that was calculated by MSBuild.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is what Path.GetFileName does. The span is ToStringed by the method we call
https://github.com/dotnet/runtime/blob/2c4b4c0831d1d9f505ff5d3055c38bb41646021b/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs#L236-L248

        public static ReadOnlySpan<char> GetFileName(ReadOnlySpan<char> path)
        {
            int root = GetPathRoot(path).Length;

            // We don't want to cut off "C:\file.txt:stream" (i.e. should be "file.txt:stream")
            // but we *do* want "C:Foo" => "Foo". This necessitates checking for the root.

            int i = PathInternal.DirectorySeparatorChar == PathInternal.AltDirectorySeparatorChar ?
                path.LastIndexOf(PathInternal.DirectorySeparatorChar) :
                path.LastIndexOfAny(PathInternal.DirectorySeparatorChar, PathInternal.AltDirectorySeparatorChar);

            return path.Slice(i < root ? root : i + 1);
        }

Copy link
Contributor

Choose a reason for hiding this comment

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

LGTM

…xtensions.cs

Co-authored-by: Cristian Ambrosini <114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Copy link
Contributor

@pavel-mikula-sonarsource pavel-mikula-sonarsource left a comment

Choose a reason for hiding this comment

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

LGTM conceptually. I've left some readability comments

@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

Comment on lines +38 to +39
// HotPath: This code path needs to be allocation free. Don't use Linq.
foreach (var additionalText in options.AdditionalFiles) // Uses the struct enumerator of ImmutableArray

Choose a reason for hiding this comment

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

💡 We would typically document this in Roslyn with the following attribute on the method:

[PerformanceSensitive(
    "https://github.com/SonarSource/sonar-dotnet/issues/7440",
    AllowCaptures = false,
    AllowGenericEnumeration = false)]

Choose a reason for hiding this comment

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

It should be possible to use this attribute if you install the Microsoft.CodeAnalysis.PerformanceSensitiveAnalyzers package

Choose a reason for hiding this comment

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

Currently we don't have analyzer enforcement for the constraints of the attribute, but we hope to provide it in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you @sharwell for the hint.
I added #7690 to our backlog. We will discuss this internally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allocations: Unroll AdditionalFile extension method
4 participants