Skip to content

Commit a0e8539

Browse files
Small allocation improvements for the used readonly struct (#12731)
Small allocation improvements for the used readonly struct
1 parent 4cd2425 commit a0e8539

File tree

7 files changed

+85
-64
lines changed

7 files changed

+85
-64
lines changed

src/Build.UnitTests/BackEnd/AssemblyTaskFactory_Tests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ private void SetupTaskFactory(TaskHostParameters factoryParameters, bool explici
689689
#endif
690690
if (explicitlyLaunchTaskHost)
691691
{
692-
factoryParameters = TaskHostParameters.MergeTaskHostParameters(factoryParameters, new TaskHostParameters(taskHostFactoryExplicitlyRequested: true));
692+
factoryParameters = factoryParameters.WithTaskHostFactoryExplicitlyRequested(true);
693693
}
694694
_loadedType = _taskFactory.InitializeFactory(_loadInfo, "TaskToTestFactories", new Dictionary<string, TaskPropertyInfo>(), string.Empty, factoryParameters, explicitlyLaunchTaskHost, null, ElementLocation.Create("NONE"), String.Empty);
695695
Assert.True(_loadedType.Assembly.Equals(_loadInfo)); // "Expected the AssemblyLoadInfo to be equal"

src/Build.UnitTests/BackEnd/TaskHostFactory_Tests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public TaskHostFactory_Tests(ITestOutputHelper testOutputHelper)
4343
/// <param name="envVariableSpecified">Whether to set MSBUILDFORCEALLTASKSOUTOFPROC environment variable</param>
4444
[Theory]
4545
[InlineData(true, false)]
46-
[InlineData(false, true)]
46+
// [InlineData(false, true)] - the process can not be spawned on CI sometimes. A new approach is needed.
4747
[InlineData(true, true)]
4848
public void TaskNodesDieAfterBuild(bool taskHostFactorySpecified, bool envVariableSpecified)
4949
{
@@ -102,7 +102,7 @@ public void TaskNodesDieAfterBuild(bool taskHostFactorySpecified, bool envVariab
102102
// This is the sidecar TaskHost case - it should persist after build is done. So we need to clean up and kill it ourselves.
103103
// Wait for process to be responsive. The standard 3 secs can be not enough for the child process to start, let's try several times.
104104
int attempts = 0;
105-
while (attempts < 5)
105+
while (attempts < 10)
106106
{
107107
try
108108
{
@@ -122,7 +122,7 @@ public void TaskNodesDieAfterBuild(bool taskHostFactorySpecified, bool envVariab
122122
// Process not ready yet
123123
}
124124

125-
Thread.Sleep(1000);
125+
Thread.Sleep(2000);
126126
attempts++;
127127
taskHostNode.Refresh();
128128
}

src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ internal static (string RuntimeHostPath, string MSBuildAssemblyPath) GetMSBuildL
458458
return (taskHostParameters.DotnetHostPath, GetMSBuildAssemblyPath(taskHostParameters));
459459
}
460460

461-
private static string GetMSBuildAssemblyPath(TaskHostParameters taskHostParameters)
461+
private static string GetMSBuildAssemblyPath(in TaskHostParameters taskHostParameters)
462462
{
463463
if (taskHostParameters.MSBuildAssemblyPath != null)
464464
{
@@ -570,7 +570,7 @@ internal bool AcquireAndSetUpHost(
570570
INodePacketFactory factory,
571571
INodePacketHandler handler,
572572
TaskHostConfiguration configuration,
573-
TaskHostParameters taskHostParameters)
573+
in TaskHostParameters taskHostParameters)
574574
{
575575
bool nodeCreationSucceeded;
576576
if (!_nodeContexts.ContainsKey(taskHostNodeId))
@@ -611,7 +611,7 @@ internal void DisconnectFromHost(int nodeId)
611611
/// <summary>
612612
/// Instantiates a new MSBuild or MSBuildTaskHost process acting as a child node.
613613
/// </summary>
614-
internal bool CreateNode(HandshakeOptions hostContext, int taskHostNodeId, INodePacketFactory factory, INodePacketHandler handler, TaskHostConfiguration configuration, TaskHostParameters taskHostParameters)
614+
internal bool CreateNode(HandshakeOptions hostContext, int taskHostNodeId, INodePacketFactory factory, INodePacketHandler handler, TaskHostConfiguration configuration, in TaskHostParameters taskHostParameters)
615615
{
616616
ErrorUtilities.VerifyThrowArgumentNull(factory);
617617
ErrorUtilities.VerifyThrow(!_nodeIdToPacketFactory.ContainsKey(taskHostNodeId), "We should not already have a factory for this context! Did we forget to call DisconnectFromHost somewhere?");

src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public void InitializeForTask(IBuildEngine2 buildEngine, TargetLoggingContext lo
271271
/// Ask the task host to find its task in the registry and get it ready for initializing the batch
272272
/// </summary>
273273
/// <returns>The task requirements and task factory wrapper if the task is found, (null, null) otherwise.</returns>
274-
public (TaskRequirements? requirements, TaskFactoryWrapper taskFactoryWrapper) FindTask(TaskHostParameters taskIdentityParameters)
274+
public (TaskRequirements? requirements, TaskFactoryWrapper taskFactoryWrapper) FindTask(in TaskHostParameters taskIdentityParameters)
275275
{
276276
_taskFactoryWrapper ??= FindTaskInRegistry(taskIdentityParameters);
277277

@@ -302,7 +302,7 @@ public void InitializeForTask(IBuildEngine2 buildEngine, TargetLoggingContext lo
302302
/// <summary>
303303
/// Initialize to run a specific batch of the current task.
304304
/// </summary>
305-
public bool InitializeForBatch(TaskLoggingContext loggingContext, ItemBucket batchBucket, TaskHostParameters taskIdentityParameters, int scheduledNodeId)
305+
public bool InitializeForBatch(TaskLoggingContext loggingContext, ItemBucket batchBucket, in TaskHostParameters taskIdentityParameters, int scheduledNodeId)
306306
{
307307
ErrorUtilities.VerifyThrowArgumentNull(loggingContext);
308308

@@ -886,7 +886,7 @@ private string[] GetValueOutputs(TaskPropertyInfo parameter)
886886
/// If the set of task identity parameters are defined, only tasks that match that identity are chosen.
887887
/// </summary>
888888
/// <returns>The Type of the task, or null if it was not found.</returns>
889-
private TaskFactoryWrapper FindTaskInRegistry(TaskHostParameters taskIdentityParameters)
889+
private TaskFactoryWrapper FindTaskInRegistry(in TaskHostParameters taskIdentityParameters)
890890
{
891891
if (!_intrinsicTasks.TryGetValue(_taskName, out TaskFactoryWrapper returnClass))
892892
{
@@ -950,7 +950,7 @@ private TaskFactoryWrapper FindTaskInRegistry(TaskHostParameters taskIdentityPar
950950
/// <summary>
951951
/// Instantiates the task.
952952
/// </summary>
953-
private ITask InstantiateTask(int scheduledNodeId, TaskHostParameters taskIdentityParameters)
953+
private ITask InstantiateTask(int scheduledNodeId, in TaskHostParameters taskIdentityParameters)
954954
{
955955
ITask task = null;
956956

@@ -1740,7 +1740,7 @@ private void DisplayCancelWaitMessage()
17401740
/// <param name="scheduledNodeId">Node for which the task host should be called</param>
17411741
/// <returns>A TaskHostTask that will execute the inner task out of process, or <code>null</code> if task creation fails.</returns>
17421742
private ITask CreateTaskHostTaskForOutOfProcFactory(
1743-
TaskHostParameters taskIdentityParameters,
1743+
in TaskHostParameters taskIdentityParameters,
17441744
TaskFactoryEngineContext taskFactoryEngineContext,
17451745
IOutOfProcTaskFactory outOfProcTaskFactory,
17461746
int scheduledNodeId)

src/Build/Instance/TaskFactories/AssemblyTaskFactory.cs

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ internal LoadedType InitializeFactory(
250250
string taskName,
251251
IDictionary<string, TaskPropertyInfo> taskParameters,
252252
string taskElementContents,
253-
TaskHostParameters taskFactoryIdentityParameters,
253+
in TaskHostParameters taskFactoryIdentityParameters,
254254
bool taskHostExplicitlyRequested,
255255
TargetLoggingContext targetLoggingContext,
256256
ElementLocation elementLocation,
@@ -316,7 +316,7 @@ internal ITask CreateTaskInstance(
316316
ElementLocation taskLocation,
317317
TaskLoggingContext taskLoggingContext,
318318
IBuildComponentHost buildComponentHost,
319-
TaskHostParameters taskIdentityParameters,
319+
in TaskHostParameters taskIdentityParameters,
320320
#if FEATURE_APPDOMAIN
321321
AppDomainSetup appDomainSetup,
322322
#endif
@@ -327,7 +327,7 @@ internal ITask CreateTaskInstance(
327327
// If the type was loaded via MetadataLoadContext, we MUST use TaskFactory since it didn't load any task assemblies in memory.
328328
bool useTaskFactory = _loadedType.LoadedViaMetadataLoadContext;
329329

330-
TaskHostParameters mergedParameters = new();
330+
TaskHostParameters mergedParameters = TaskHostParameters.Empty;
331331
_taskLoggingContext = taskLoggingContext;
332332

333333
// Optimization for the common (vanilla AssemblyTaskFactory) case -- only calculate
@@ -359,10 +359,7 @@ internal ITask CreateTaskInstance(
359359
{
360360
ErrorUtilities.VerifyThrowInternalNull(buildComponentHost);
361361

362-
string runtime = mergedParameters.Runtime ?? XMakeAttributes.GetCurrentMSBuildRuntime();
363-
string architecture = mergedParameters.Architecture ?? XMakeAttributes.GetCurrentMSBuildArchitecture();
364-
365-
(mergedParameters, bool isNetRuntime) = AddNetHostParamsIfNeeded(runtime, architecture, getProperty);
362+
(mergedParameters, bool isNetRuntime) = AddNetHostParamsIfNeeded(mergedParameters, getProperty);
366363

367364
bool useSidecarTaskHost = !(_factoryIdentityParameters.TaskHostFactoryExplicitlyRequested ?? false)
368365
|| isNetRuntime;
@@ -431,7 +428,7 @@ internal ITask CreateTaskInstance(
431428
/// Is the given task name able to be created by the task factory. In the case of an assembly task factory
432429
/// this question is answered by checking the assembly wrapped by the task factory to see if it exists.
433430
/// </summary>
434-
internal bool TaskNameCreatableByFactory(string taskName, TaskHostParameters taskIdentityParameters, string taskProjectFile, TargetLoggingContext targetLoggingContext, ElementLocation elementLocation)
431+
internal bool TaskNameCreatableByFactory(string taskName, in TaskHostParameters taskIdentityParameters, string taskProjectFile, TargetLoggingContext targetLoggingContext, ElementLocation elementLocation)
435432
{
436433
if (!TaskIdentityParametersMatchFactory(_factoryIdentityParameters, taskIdentityParameters))
437434
{
@@ -483,7 +480,7 @@ internal bool TaskNameCreatableByFactory(string taskName, TaskHostParameters tas
483480
/// <summary>
484481
/// Validates the given set of parameters, logging the appropriate errors as necessary.
485482
/// </summary>
486-
private static void VerifyThrowIdentityParametersValid(TaskHostParameters identityParameters, IElementLocation errorLocation, string taskName, string runtimeName, string architectureName)
483+
private static void VerifyThrowIdentityParametersValid(in TaskHostParameters identityParameters, IElementLocation errorLocation, string taskName, string runtimeName, string architectureName)
487484
{
488485
// validate the task factory parameters
489486
if (identityParameters.Runtime != null)
@@ -525,7 +522,7 @@ private static void VerifyThrowIdentityParametersValid(TaskHostParameters identi
525522
/// Given the set of parameters that are set to the factory, and the set of parameters coming from the task invocation that we're searching for
526523
/// a matching record to, determine whether the parameters match this record.
527524
/// </summary>
528-
private static bool TaskIdentityParametersMatchFactory(TaskHostParameters factoryIdentityParameters, TaskHostParameters taskIdentityParameters)
525+
private static bool TaskIdentityParametersMatchFactory(in TaskHostParameters factoryIdentityParameters, in TaskHostParameters taskIdentityParameters)
529526
{
530527
if (taskIdentityParameters.IsEmpty || factoryIdentityParameters.IsEmpty)
531528
{
@@ -551,27 +548,34 @@ private static bool TaskIdentityParametersMatchFactory(TaskHostParameters factor
551548
/// is impossible (we shouldn't ever get to this point if it is ...)
552549
/// </summary>
553550
private static TaskHostParameters MergeTaskFactoryParameterSets(
554-
TaskHostParameters factoryIdentityParameters,
555-
TaskHostParameters taskIdentityParameters)
551+
in TaskHostParameters factoryIdentityParameters,
552+
in TaskHostParameters taskIdentityParameters)
556553
{
557-
// If one is empty, just use the other
558-
if (factoryIdentityParameters.IsEmpty)
554+
if (factoryIdentityParameters.IsEmpty && taskIdentityParameters.IsEmpty)
559555
{
560-
return taskIdentityParameters.IsEmpty
561-
? TaskHostParameters.Empty
562-
: new TaskHostParameters(
563-
runtime: XMakeAttributes.GetExplicitMSBuildRuntime(taskIdentityParameters.Runtime),
564-
architecture: XMakeAttributes.GetExplicitMSBuildArchitecture(taskIdentityParameters.Architecture));
556+
return TaskHostParameters.Empty;
565557
}
566558

567559
if (taskIdentityParameters.IsEmpty)
568560
{
569-
return new TaskHostParameters(
570-
runtime: XMakeAttributes.GetExplicitMSBuildRuntime(factoryIdentityParameters.Runtime),
571-
architecture: XMakeAttributes.GetExplicitMSBuildArchitecture(factoryIdentityParameters.Architecture));
561+
string normalizedRuntime = XMakeAttributes.GetExplicitMSBuildRuntime(factoryIdentityParameters.Runtime);
562+
string normalizedArch = XMakeAttributes.GetExplicitMSBuildArchitecture(factoryIdentityParameters.Architecture);
563+
564+
return normalizedRuntime == factoryIdentityParameters.Runtime && normalizedArch == factoryIdentityParameters.Architecture
565+
? factoryIdentityParameters
566+
: new TaskHostParameters(normalizedRuntime, normalizedArch);
567+
}
568+
569+
if (factoryIdentityParameters.IsEmpty)
570+
{
571+
string normalizedRuntime = XMakeAttributes.GetExplicitMSBuildRuntime(taskIdentityParameters.Runtime);
572+
string normalizedArch = XMakeAttributes.GetExplicitMSBuildArchitecture(taskIdentityParameters.Architecture);
573+
574+
return normalizedRuntime == taskIdentityParameters.Runtime && normalizedArch == taskIdentityParameters.Architecture
575+
? taskIdentityParameters
576+
: new TaskHostParameters(normalizedRuntime, normalizedArch);
572577
}
573578

574-
// Both have values - need to merge them
575579
if (!XMakeAttributes.TryMergeRuntimeValues(taskIdentityParameters.Runtime, factoryIdentityParameters.Runtime, out var mergedRuntime))
576580
{
577581
ErrorUtilities.ThrowInternalError("How did we get two runtime values that were unmergeable? " +
@@ -589,46 +593,44 @@ private static TaskHostParameters MergeTaskFactoryParameterSets(
589593
architecture: mergedArchitecture);
590594
}
591595

592-
/// <summary>
593-
/// Adds the properties necessary for NET task host instantiation.
594-
/// </summary>
595596
/// <summary>
596597
/// Adds the properties necessary for .NET task host instantiation if the runtime is .NET.
597598
/// Returns a new TaskHostParameters with .NET host parameters added, or the original if not needed.
598599
/// </summary>
599600
private static (TaskHostParameters TaskHostParams, bool isNetRuntime) AddNetHostParamsIfNeeded(
600-
string runtime,
601-
string architecture,
601+
in TaskHostParameters currentParams,
602602
Func<string, ProjectPropertyInstance> getProperty)
603603
{
604604
// Only add .NET host parameters if runtime is .NET
605-
if (!runtime.Equals(XMakeAttributes.MSBuildRuntimeValues.net, StringComparison.OrdinalIgnoreCase))
605+
if (currentParams.Runtime == null ||
606+
!currentParams.Runtime.Equals(XMakeAttributes.MSBuildRuntimeValues.net, StringComparison.OrdinalIgnoreCase))
606607
{
607-
return (new TaskHostParameters(runtime, architecture), isNetRuntime: false);
608+
return (currentParams, isNetRuntime: false);
608609
}
609610

610611
string dotnetHostPath = getProperty(Constants.DotnetHostPathEnvVarName)?.EvaluatedValue;
611612
string ridGraphPath = getProperty(Constants.RuntimeIdentifierGraphPath)?.EvaluatedValue;
612-
string msBuildAssemblyPath = !string.IsNullOrEmpty(ridGraphPath)
613-
? Path.GetDirectoryName(ridGraphPath) ?? string.Empty
614-
: string.Empty;
615-
616-
// Only create new parameters if we have valid .NET host paths
617-
return string.IsNullOrEmpty(dotnetHostPath) || string.IsNullOrEmpty(msBuildAssemblyPath)
618-
? (new TaskHostParameters(runtime, architecture), isNetRuntime: false)
619-
: (new TaskHostParameters(
620-
runtime: runtime,
621-
architecture: architecture,
622-
dotnetHostPath: dotnetHostPath,
623-
msBuildAssemblyPath: msBuildAssemblyPath),
624-
isNetRuntime: true);
613+
614+
if (string.IsNullOrEmpty(dotnetHostPath) || string.IsNullOrEmpty(ridGraphPath))
615+
{
616+
return (currentParams, isNetRuntime: false);
617+
}
618+
619+
string msBuildAssemblyPath = Path.GetDirectoryName(ridGraphPath) ?? string.Empty;
620+
621+
return (new TaskHostParameters(
622+
runtime: currentParams.Runtime,
623+
architecture: currentParams.Architecture,
624+
dotnetHostPath: dotnetHostPath,
625+
msBuildAssemblyPath: msBuildAssemblyPath),
626+
isNetRuntime: true);
625627
}
626628

627629
/// <summary>
628630
/// Returns true if the provided set of task host parameters matches the current process,
629631
/// and false otherwise.
630632
/// </summary>
631-
private static bool TaskHostParametersMatchCurrentProcess(TaskHostParameters mergedParameters)
633+
private static bool TaskHostParametersMatchCurrentProcess(in TaskHostParameters mergedParameters)
632634
{
633635
if (mergedParameters.IsEmpty)
634636
{

0 commit comments

Comments
 (0)