Memory usage improvements in build (#2626)

* Use a WorkspaceContext in dotnet-build to cache project data across
multiple compilations in a single build action
* Dramatically reduce string and object duplication by introducing a
"Symbol Table" that shares instances of NuGetVersion, NuGetFramework,
VersionRange and string across multiple lock-file parses

Test Results:
* Testing was done by compiling Microsoft.AspNetCore.Mvc (and it's
dependencies) and taking memory snapshots after each compilation in
dotMemory
* We used to allocate ~3MB and deallocate ~2.5MB on EACH compilation in
a single build action. This has been reduced to ~120KB
allocated/deallocated
* After introducing WorkspaceContext, total memory usage spiked from 6MB
across the whole build action to about 13MB, introducing the symbol
table dropped it back to about 5-6MB.
This commit is contained in:
Andrew Stanton-Nurse 2016-04-22 15:01:56 -07:00
parent 80df3688b1
commit ef0ca39da1
42 changed files with 496 additions and 268 deletions

View file

@ -22,6 +22,7 @@ namespace Microsoft.DotNet.Tools.Run
ProjectContext _context;
List<string> _args;
private WorkspaceContext _workspace;
public int Start()
{
@ -60,6 +61,8 @@ namespace Microsoft.DotNet.Tools.Run
Configuration = Constants.DefaultConfiguration;
}
var frameworkContexts = _workspace.GetProjectContexts(Project).Where(c => string.IsNullOrEmpty(c.RuntimeIdentifier));
var rids = PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers();
if (Framework == null)
@ -70,16 +73,14 @@ namespace Microsoft.DotNet.Tools.Run
FrameworkConstants.FrameworkIdentifiers.NetStandardApp,
};
var contexts = ProjectContext.CreateContextForEachFramework(Project, null);
ProjectContext context;
if (contexts.Count() == 1)
if (frameworkContexts.Count() == 1)
{
context = contexts.Single();
context = frameworkContexts.Single();
}
else
{
context = contexts.FirstOrDefault(c => defaultFrameworks.Contains(c.TargetFramework.Framework));
context = frameworkContexts.FirstOrDefault(c => defaultFrameworks.Contains(c.TargetFramework.Framework));
if (context == null)
{
throw new InvalidOperationException($"Couldn't find target to run. Possible causes:" + Environment.NewLine +
@ -88,11 +89,11 @@ namespace Microsoft.DotNet.Tools.Run
}
}
_context = context.CreateRuntimeContext(rids);
_context = _workspace.GetRuntimeContext(context, rids);
}
else
{
_context = ProjectContext.Create(Project, NuGetFramework.Parse(Framework), rids);
_context = _workspace.GetProjectContext(Project, NuGetFramework.Parse(Framework), rids);
}
if (Args == null)
@ -107,6 +108,9 @@ namespace Microsoft.DotNet.Tools.Run
private int RunExecutable()
{
// Set up the workspace
_workspace = WorkspaceContext.Create(ProjectReaderSettings.ReadFromEnvironment(), designTime: false);
CalculateDefaultsForNonAssigned();
// Compile to that directory