Skip to content

Commit

Permalink
[msbuild] Make the level of parallelism configurable in all tasks tha…
Browse files Browse the repository at this point in the history
…t call Parallel.ForEach. Fixes xamarin#20210.

This deduplicates some code, and also ensures we specifiy a max limit to the
level of parallelism. This fixes an issue in the AOTCompile and ScnTool tasks,
where we'd have no limit, launching as many subprocesses as tasks there are to
execute. In particular for the AOTCompile task, this can put a rather heavy
burden on build machines, slowing everything down to a crawl.

Fixes xamarin#20210.
  • Loading branch information
rolfbjarne committed Mar 5, 2024
1 parent 8cfbe6f commit 318b285
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 22 deletions.
1 change: 1 addition & 0 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,7 @@
Assemblies="@(_AssembliesToAOT)"
AOTCompilerPath="$(_XamarinAOTCompiler)"
InputDirectory="$(_AOTInputDirectory)"
MaxDegreeOfParallelism="$(AotCompileMaxDegreeOfParallelism)"
MinimumOSVersion="$(_MinimumOSVersion)"
OutputDirectory="$(_AOTOutputDirectory)\%(_AssembliesToAOT.Arch)"
SdkDevPath="$(_SdkDevPath)"
Expand Down
4 changes: 2 additions & 2 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/AOTCompile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#nullable enable

namespace Xamarin.MacDev.Tasks {
public class AOTCompile : XamarinTask, ITaskCallback, ICancelableTask {
public class AOTCompile : XamarinParallelTask, ITaskCallback, ICancelableTask {
public ITaskItem [] AotArguments { get; set; } = Array.Empty<ITaskItem> ();

[Required]
Expand Down Expand Up @@ -314,7 +314,7 @@ public override bool Execute ()
listOfArguments.Add (new (arguments, input));
}

Parallel.ForEach (listOfArguments, (arg) => {
ForEach (listOfArguments, (arg) => {
ExecuteAsync (AOTCompilerPath, arg.Arguments, sdkDevPath: SdkDevPath, showErrorIfFailure: false /* we show our own error below */)
.ContinueWith ((v) => {
if (v.Result.ExitCode != 0)
Expand Down
18 changes: 2 additions & 16 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/Codesign.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#nullable disable

namespace Xamarin.MacDev.Tasks {
public class Codesign : XamarinTask, ITaskCallback, ICancelableTask {
public class Codesign : XamarinParallelTask, ITaskCallback, ICancelableTask {
const string ToolName = "codesign";
const string MacOSDirName = "MacOS";
const string CodeSignatureDirName = "_CodeSignature";
Expand Down Expand Up @@ -55,10 +55,6 @@ public class Codesign : XamarinTask, ITaskCallback, ICancelableTask {
// Can also be specified per resource using the 'CodesignDeep' metadata (yes, the naming difference is correct and due to historical reasons)
public bool IsAppExtension { get; set; }

// How many codesign tasks we execute in parallel. Default is number of processors / 2.
// Contrary to many of the other codesigning properties, this can not be set per resource.
public string MaxDegreeOfParallelism { get; set; }

// Can also be specified per resource using the 'CodesignUseHardenedRuntime' metadata
public bool UseHardenedRuntime { get; set; }

Expand Down Expand Up @@ -105,16 +101,6 @@ string GetCodesignAllocate (ITaskItem item)
return GetNonEmptyStringOrFallback (item, "CodesignAllocate", CodesignAllocate, "CodesignAllocate", required: true);
}

int GetMaxDegreeOfParallelism ()
{
if (!string.IsNullOrEmpty (MaxDegreeOfParallelism)) {
if (int.TryParse (MaxDegreeOfParallelism, out var max))
return max;
Log.LogWarning (MSBStrings.W7121 /* Unable to parse the value '{0}' for the property 'MaxDegreeOfParallelism'. Falling back to the default value (number of processors / 2). */, MaxDegreeOfParallelism);
}
return Math.Max (Environment.ProcessorCount / 2, 1);
}

// 'sortedItems' is sorted by length of path, longest first.
bool NeedsCodesign (ITaskItem [] sortedItems, int index, string stampFileContents)
{
Expand Down Expand Up @@ -482,7 +468,7 @@ bool ExecuteUnsafe ()

for (var b = 0; b < buckets.Count; b++) {
var bucket = buckets [b];
Parallel.ForEach (bucket, new ParallelOptions { MaxDegreeOfParallelism = GetMaxDegreeOfParallelism () }, (item) => {
ForEach (bucket, (item) => {
Sign (item);
var files = GetCodesignedFiles (item.Item);
Expand Down
4 changes: 2 additions & 2 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/ScnTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using Xamarin.Utils;

namespace Xamarin.MacDev.Tasks {
public class ScnTool : XamarinTask {
public class ScnTool : XamarinParallelTask {
#region Inputs

[Required]
Expand Down Expand Up @@ -95,7 +95,7 @@ public override bool Execute ()
bundleResources.Add (bundleResource);
}

Parallel.ForEach (listOfArguments, (arg) => {
ForEach (listOfArguments, (arg) => {
ExecuteAsync ("xcrun", arg.Arguments, sdkDevPath: SdkDevPath).Wait ();
});

Expand Down
4 changes: 2 additions & 2 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/SymbolStrip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#nullable enable

namespace Xamarin.MacDev.Tasks {
public class SymbolStrip : XamarinTask, ITaskCallback {
public class SymbolStrip : XamarinParallelTask, ITaskCallback {
#region Inputs

[Required]
Expand Down Expand Up @@ -60,7 +60,7 @@ public override bool Execute ()
if (ShouldExecuteRemotely ())
return new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;

Parallel.ForEach (Executable, new ParallelOptions { MaxDegreeOfParallelism = Math.Max (Environment.ProcessorCount / 2, 1) }, (item) => {
ForEach (Executable, (item) => {
ExecuteStrip (item);
});

Expand Down
33 changes: 33 additions & 0 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/XamarinParallelTask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Xamarin.Localization.MSBuild;
using Xamarin.Utils;

#nullable enable

namespace Xamarin.MacDev.Tasks {
public abstract class XamarinParallelTask : XamarinTask {
// How many tasks we execute in parallel. Default is number of processors / 2.
public string MaxDegreeOfParallelism { get; set; } = string.Empty;

int GetMaxDegreeOfParallelism ()
{
if (!string.IsNullOrEmpty (MaxDegreeOfParallelism)) {
if (int.TryParse (MaxDegreeOfParallelism, out var max))
return max;
Log.LogWarning (MSBStrings.W7121 /* Unable to parse the value '{0}' for the property 'MaxDegreeOfParallelism'. Falling back to the default value (number of processors / 2). */, MaxDegreeOfParallelism);
}
return Math.Max (Environment.ProcessorCount / 2, 1);
}

protected void ForEach<TSource> (IEnumerable<TSource> source, Action<TSource> body)
{
var options = new ParallelOptions { MaxDegreeOfParallelism = GetMaxDegreeOfParallelism () };
Parallel.ForEach (source, options, body);
}
}
}
2 changes: 2 additions & 0 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
Condition="'$(IsMacEnabled)' == 'true'"
DeviceSpecificIntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)"
IsWatchApp="$(IsWatchApp)"
MaxDegreeOfParallelism="$(ColladaMaxDegreeOfParallelism)"
ProjectDir="$(MSBuildProjectDirectory)"
ResourcePrefix="$(_ResourcePrefix)"
SdkPlatform="$(_SdkPlatform)"
Expand Down Expand Up @@ -2771,6 +2772,7 @@ Copyright (C) 2018 Microsoft. All rights reserved.
Condition="'$(IsMacEnabled)' == 'true'"
Executable="$(_AppContainerDir)%(_NativeStripItems.Identity)"
Kind="%(_NativeStripItems.Kind)"
MaxDegreeOfParallelism="$(SymbolStripMaxDegreeOfParallelism)"
SymbolFile="%(_NativeStripItems.SymbolFile)"
/>

Expand Down

0 comments on commit 318b285

Please sign in to comment.