dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.92k stars 526 forks source link

[Xamarin.Android.Build.Tasks] reduce System.Linq usage in ManifestDocument #9281

Closed jonathanpeppers closed 2 weeks ago

jonathanpeppers commented 2 weeks ago

Profiling an incremental build of a dotnet new maui project with a XAML change, one thing I saw was time spent in <GenerateJavaStubs/> MSBuild task, and the ManifestDocument class:

67.57ms (1.80%) xamarin.android.build.tasks!Xamarin.Android.Tasks.ManifestDocument.Merge(class Microsoft.Build.Utilities.TaskLoggingHel
19.99ms (0.53%) xamarin.android.build.tasks!Xamarin.Android.Tasks.ManifestDocument.CreateApplicationElement(class System.Xml.Linq.XEleme...

Reviewing the code, there was a decent amount of LINQ usage that would create extra allocations for closures, such as:

var properties =
    Assemblies.SelectMany (path => PropertyAttribute.FromCustomAttributeProvider (Resolver.GetAssembly (path), cache))

I unrolled the System.Linq usage, and just used plain foreach loops instead.

I also found some places that did:

if (!attrs.Any ())
    yield break;

We could just remove these as the yield return wouldn't return if attrs is empty anyway.

After removing this code, I see a small improvement:

62.56ms (1.80%) xamarin.android.build.tasks!Xamarin.Android.Tasks.ManifestDocument.Merge(class Microsoft.Build.Utilities.TaskLoggingHe...
16.03ms (0.46%) xamarin.android.build.tasks!Xamarin.Android.Tasks.ManifestDocument.CreateApplicationElement(class System.Xml.Linq.XEleme...

This probably saves ~5ms to incremental builds, but seems like a straightforward change.