-
Notifications
You must be signed in to change notification settings - Fork 531
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
[Xamarin.Android.Build.Tasks] reduce System.Linq usage in ManifestDocument #9281
[Xamarin.Android.Build.Tasks] reduce System.Linq usage in ManifestDocument #9281
Conversation
…ument 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.
var ull1 = usesLibraryAttr ?? Array.Empty<UsesLibraryAttribute> (); | ||
var ull2 = typeUsesLibraryAttr.AsEnumerable () ?? Array.Empty<UsesLibraryAttribute> (); | ||
var usesLibraryAttrs = ull1.Concat (ull2); | ||
var ucl1 = usesConfigurationAttr ?? Array.Empty<UsesConfigurationAttribute>(); | ||
var ucl2 = typeUsesConfigurationAttr.AsEnumerable () ?? Array.Empty<UsesConfigurationAttribute> (); | ||
var usesConfigurationattrs = ucl1.Concat (ucl2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this made lots of locals before, and we didn't really need them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup looks like this code above was just to concatinate the lists. But you already do that in the new foreach loop replacement.
AddUsesLibraries (application, usesLibraryAttrs, cache); | ||
AddUsesConfigurations (application, usesConfigurationattrs, cache); | ||
AddUsesLibraries (application, usesLibraryAttr, cache); | ||
AddUsesConfigurations (application, usesConfigurationAttr, cache); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just used the original list instead.
void AddUsesConfigurations (XElement application, IEnumerable<UsesConfigurationAttribute> configs, TypeDefinitionCache cache) | ||
void AddUsesConfigurations (XElement application, List<UsesConfigurationAttribute> configs, TypeDefinitionCache cache) | ||
{ | ||
foreach (var uca in configs) | ||
application.Add (uca.ToElement (PackageName, cache)); | ||
} | ||
|
||
void AddUsesLibraries (XElement application, IEnumerable<UsesLibraryAttribute> libraries, TypeDefinitionCache cache) | ||
void AddUsesLibraries (XElement application, List<UsesLibraryAttribute> libraries, TypeDefinitionCache cache) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These might allow the C# compiler to automatically turn the foreach
into for
, if the List<T>
type is known.
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 theManifestDocument
class:Reviewing the code, there was a decent amount of LINQ usage that would create extra allocations for closures, such as:
I unrolled the System.Linq usage, and just used plain
foreach
loops instead.I also found some places that did:
We could just remove these as the
yield return
wouldn't return ifattrs
is empty anyway.After removing this code, I see a small improvement:
This probably saves ~5ms to incremental builds, but seems like a straightforward change.