Skip to content

Commit 97d250b

Browse files
[Xamarin.Android.Build.Tasks] perf improvements for <ResolveAssemblies/> (dotnet#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.
1 parent 8acd915 commit 97d250b

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

src/Xamarin.Android.Build.Tasks/Tasks/ResolveAssemblies.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,22 +72,14 @@ void Execute (MetadataResolver resolver)
7272

7373
var assemblies = new Dictionary<string, ITaskItem> (Assemblies.Length);
7474
var topAssemblyReferences = new List<string> (Assemblies.Length);
75-
var logger = new NuGetLogger((s) => {
76-
LogDebugMessage ("{0}", s);
77-
});
78-
79-
LockFile lockFile = null;
80-
if (!string.IsNullOrEmpty (ProjectAssetFile) && File.Exists (ProjectAssetFile)) {
81-
lockFile = LockFileUtilities.GetLockFile (ProjectAssetFile, logger);
82-
}
83-
8475
try {
8576
foreach (var assembly in Assemblies) {
8677
// Add each user assembly and all referenced assemblies (recursive)
8778
string resolved_assembly = resolver.Resolve (assembly.ItemSpec);
8879
bool refAssembly = !string.IsNullOrEmpty (assembly.GetMetadata ("NuGetPackageId")) && resolved_assembly.Contains ($"{Path.DirectorySeparatorChar}ref{Path.DirectorySeparatorChar}");
8980
if (refAssembly || MonoAndroidHelper.IsReferenceAssembly (resolved_assembly)) {
9081
// Resolve "runtime" library
82+
var lockFile = lock_file.Value;
9183
if (lockFile != null)
9284
resolved_assembly = ResolveRuntimeAssemblyForReferenceAssembly (lockFile, assembly.ItemSpec);
9385
if (lockFile == null || resolved_assembly == null) {
@@ -96,7 +88,6 @@ void Execute (MetadataResolver resolver)
9688
continue;
9789
}
9890
}
99-
LogDebugMessage ($"Adding {resolved_assembly} to topAssemblyReferences");
10091
topAssemblyReferences.Add (resolved_assembly);
10192
resolver.AddSearchDirectory (Path.GetDirectoryName (resolved_assembly));
10293
var taskItem = new TaskItem (assembly) {
@@ -158,8 +149,26 @@ void Execute (MetadataResolver resolver)
158149

159150
readonly List<string> do_not_package_atts = new List<string> ();
160151
readonly Dictionary<string, int> api_levels = new Dictionary<string, int> ();
152+
readonly Lazy<LockFile> lock_file;
161153
int indent = 2;
162154

155+
public ResolveAssemblies ()
156+
{
157+
lock_file = new Lazy<LockFile> (LoadLockFile);
158+
}
159+
160+
LockFile LoadLockFile ()
161+
{
162+
if (!string.IsNullOrEmpty (ProjectAssetFile) && File.Exists (ProjectAssetFile)) {
163+
LogDebugMessage ($"Loading NuGet LockFile: {ProjectAssetFile}");
164+
var logger = new NuGetLogger ((s) => {
165+
LogDebugMessage ("{0}", s);
166+
});
167+
return LockFileUtilities.GetLockFile (ProjectAssetFile, logger);
168+
}
169+
return null;
170+
}
171+
163172
string ResolveRuntimeAssemblyForReferenceAssembly (LockFile lockFile, string assemblyPath)
164173
{
165174
if (string.IsNullOrEmpty(TargetMoniker))
@@ -307,7 +316,6 @@ void CheckAssemblyAttributes (AssemblyDefinition assembly, MetadataReader reader
307316
var apiLevel = MonoAndroidHelper.SupportedVersions.GetApiLevelFromFrameworkVersion (version);
308317
if (apiLevel != null) {
309318
var assemblyName = reader.GetString (assembly.Name);
310-
LogDebugMessage ("{0}={1}", assemblyName, apiLevel);
311319
api_levels [assemblyName] = apiLevel.Value;
312320
}
313321
}

0 commit comments

Comments
 (0)