Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] perf improvements for <ResolveAssemblie…
Browse files Browse the repository at this point in the history
…s/> (#4236)

When building the SmartHotel360 app, I found that
`<ResolveAssemblies/>` was loading the NuGet `ProjectAssetFile` /
`LockFile` even though it was not used by the task at all. Putting a
`Stopwatch` around the code, I also found it to be somewhat expensive.

I reworked the code to use a `Lazy<T>` for accessing the `LockFile`.
This way it is not actually loaded until it is needed.

I also found several `LogDebugMessage` calls that seemed to be too
much... The `<ResolveAssemblies/>` was emitting hundreds of lines of
logging in the SmartHotel360 app.

I removed two messages such as:

    LogDebugMessage ($"Adding {resolved_assembly} to topAssemblyReferences");
    ...
    LogDebugMessage ("{0}={1}", assemblyName, apiLevel);

The `[Input]` and `[Output]` values for the task and the remaining log
message should be sufficient for understanding what we need from
customer logs:

    LogMessage ("{0}Adding assembly reference for {1}, recursively...", new string (' ', indent), assemblyName);

The results for a build with no changes with the SmartHotel360 app:

    Before:
    320 ms  ResolveAssemblies                          1 calls
    After:
    238 ms  ResolveAssemblies                          1 calls

This saves ~82ms, and since this task runs on every `Build` and
`Install`, it could save ~164ms from the dev-loop.
  • Loading branch information
jonathanpeppers authored Feb 10, 2020
1 parent 8acd915 commit 97d250b
Showing 1 changed file with 19 additions and 11 deletions.
30 changes: 19 additions & 11 deletions src/Xamarin.Android.Build.Tasks/Tasks/ResolveAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,14 @@ void Execute (MetadataResolver resolver)

var assemblies = new Dictionary<string, ITaskItem> (Assemblies.Length);
var topAssemblyReferences = new List<string> (Assemblies.Length);
var logger = new NuGetLogger((s) => {
LogDebugMessage ("{0}", s);
});

LockFile lockFile = null;
if (!string.IsNullOrEmpty (ProjectAssetFile) && File.Exists (ProjectAssetFile)) {
lockFile = LockFileUtilities.GetLockFile (ProjectAssetFile, logger);
}

try {
foreach (var assembly in Assemblies) {
// Add each user assembly and all referenced assemblies (recursive)
string resolved_assembly = resolver.Resolve (assembly.ItemSpec);
bool refAssembly = !string.IsNullOrEmpty (assembly.GetMetadata ("NuGetPackageId")) && resolved_assembly.Contains ($"{Path.DirectorySeparatorChar}ref{Path.DirectorySeparatorChar}");
if (refAssembly || MonoAndroidHelper.IsReferenceAssembly (resolved_assembly)) {
// Resolve "runtime" library
var lockFile = lock_file.Value;
if (lockFile != null)
resolved_assembly = ResolveRuntimeAssemblyForReferenceAssembly (lockFile, assembly.ItemSpec);
if (lockFile == null || resolved_assembly == null) {
Expand All @@ -96,7 +88,6 @@ void Execute (MetadataResolver resolver)
continue;
}
}
LogDebugMessage ($"Adding {resolved_assembly} to topAssemblyReferences");
topAssemblyReferences.Add (resolved_assembly);
resolver.AddSearchDirectory (Path.GetDirectoryName (resolved_assembly));
var taskItem = new TaskItem (assembly) {
Expand Down Expand Up @@ -158,8 +149,26 @@ void Execute (MetadataResolver resolver)

readonly List<string> do_not_package_atts = new List<string> ();
readonly Dictionary<string, int> api_levels = new Dictionary<string, int> ();
readonly Lazy<LockFile> lock_file;
int indent = 2;

public ResolveAssemblies ()
{
lock_file = new Lazy<LockFile> (LoadLockFile);
}

LockFile LoadLockFile ()
{
if (!string.IsNullOrEmpty (ProjectAssetFile) && File.Exists (ProjectAssetFile)) {
LogDebugMessage ($"Loading NuGet LockFile: {ProjectAssetFile}");
var logger = new NuGetLogger ((s) => {
LogDebugMessage ("{0}", s);
});
return LockFileUtilities.GetLockFile (ProjectAssetFile, logger);
}
return null;
}

string ResolveRuntimeAssemblyForReferenceAssembly (LockFile lockFile, string assemblyPath)
{
if (string.IsNullOrEmpty(TargetMoniker))
Expand Down Expand Up @@ -307,7 +316,6 @@ void CheckAssemblyAttributes (AssemblyDefinition assembly, MetadataReader reader
var apiLevel = MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion (version);
if (apiLevel != null) {
var assemblyName = reader.GetString (assembly.Name);
LogDebugMessage ("{0}={1}", assemblyName, apiLevel);
api_levels [assemblyName] = apiLevel.Value;
}
}
Expand Down

0 comments on commit 97d250b

Please sign in to comment.