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

Calls in SetWarningProperties() have allocation overhead due to multiple enumeration #13151

Closed
Erarndt opened this issue Jan 12, 2024 · 1 comment · Fixed by NuGet/NuGet.Client#5592
Assignees
Labels
Category:Quality Week Issues that should be considered for quality week PerfWins Priority:2 Issues for the current backlog. Tenet:Performance Performance issues Type:DCR Design Change Request
Milestone

Comments

@Erarndt
Copy link

Erarndt commented Jan 12, 2024

SetWarningProperties() has the following implementation:

private static void SetWarningProperties(IObjectWriter writer, ProjectRestoreMetadata msbuildMetadata)
{
    if (msbuildMetadata.ProjectWideWarningProperties != null &&
        (msbuildMetadata.ProjectWideWarningProperties.AllWarningsAsErrors ||
         msbuildMetadata.ProjectWideWarningProperties.NoWarn.Count > 0 ||
         msbuildMetadata.ProjectWideWarningProperties.WarningsAsErrors.Count > 0))
    {
        writer.WriteObjectStart("warningProperties");

        SetValueIfTrue(writer, "allWarningsAsErrors", msbuildMetadata.ProjectWideWarningProperties.AllWarningsAsErrors);

        if (msbuildMetadata.ProjectWideWarningProperties.NoWarn.Count > 0)
        {
            SetArrayValue(writer, "noWarn", msbuildMetadata
               .ProjectWideWarningProperties
               .NoWarn
               .ToArray()
               .OrderBy(c => c)
               .Select(c => c.GetName())
               .Where(c => !string.IsNullOrEmpty(c)));
        }

        if (msbuildMetadata.ProjectWideWarningProperties.WarningsAsErrors.Count > 0)
        {
            SetArrayValue(writer, "warnAsError", msbuildMetadata
                .ProjectWideWarningProperties
                .WarningsAsErrors
                .ToArray()
                .OrderBy(c => c)
                .Select(c => c.GetName())
                .Where(c => !string.IsNullOrEmpty(c)));
        }

        if (msbuildMetadata.ProjectWideWarningProperties.WarningsNotAsErrors.Count > 0)
        {
            SetArrayValue(writer, "warnNotAsError", msbuildMetadata
                .ProjectWideWarningProperties
                .WarningsNotAsErrors
                .ToArray()
                .OrderBy(c => c)
                .Select(c => c.GetName())
                .Where(c => !string.IsNullOrEmpty(c)));
        }

        writer.WriteObjectEnd();
    }
}

There are three calls to SetArrayValue() that get passed a chain of Linq calls. SetArrayValue() has this implementation:

private static void SetArrayValue(IObjectWriter writer, string name, IEnumerable<string> values)
{
    if (values != null && values.Any())
    {
        writer.WriteNameArray(name, values);
    }
}

The intent is that the array is only written if values is not empty. A consequence of the current implementation is that there is some non-trivial work that is duplicated since there is multiple enumeration happening:

image

From the trace you can see that the Any() call requires us to repeat all the work after the ToArray() call until the enumerator gets an item. For OrderBy() this requires consuming the entire enumerable and allocating the intermediate arrays that will hold the sorted items. The code should be restructured to avoid the multiple enumeration.

@Erarndt Erarndt changed the title Calls in SetWarningProperties90 have allocation overhead due to multiple enumeration Calls in SetWarningProperties() have allocation overhead due to multiple enumeration Jan 12, 2024
@ghost
Copy link

ghost commented Jan 13, 2024

Issue is missing Type label, remember to add a Type label

@ghost ghost added the missing-required-type The required type label is missing. label Jan 13, 2024
@jeffkl jeffkl added Priority:2 Issues for the current backlog. Type:DCR Design Change Request Tenet:Performance Performance issues Category:Quality Week Issues that should be considered for quality week and removed missing-required-type The required type label is missing. labels Jan 18, 2024
@kartheekp-ms kartheekp-ms added this to the 6.10 milestone May 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category:Quality Week Issues that should be considered for quality week PerfWins Priority:2 Issues for the current backlog. Tenet:Performance Performance issues Type:DCR Design Change Request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants