* Enable parallelism in Crossgen2 and add flags for it in SuperIlc.
* Use fluent api pattern in ReadyToRunCodegenCompilationBuilder for resilient, IBC tuning, and parallelism flags.
public bool UseFramework { get; set; }
public bool Release { get; set; }
public bool LargeBubble { get; set; }
+ public int Crossgen2Parallelism { get; set; }
public int CompilationTimeoutMinutes { get; set; }
public int ExecutionTimeoutMinutes { get; set; }
public DirectoryInfo[] ReferencePath { get; set; }
UseFramework(),
Release(),
LargeBubble(),
+ Crossgen2Parallelism(),
ReferencePath(),
IssuesPath(),
CompilationTimeoutMinutes(),
UseFramework(),
Release(),
LargeBubble(),
+ Crossgen2Parallelism(),
ReferencePath(),
IssuesPath(),
CompilationTimeoutMinutes(),
Option LargeBubble() =>
new Option(new[] { "--large-bubble" }, "Assume all input files as part of one version bubble", new Argument<bool>());
+ Option Crossgen2Parallelism() =>
+ new Option(new[] { "--crossgen2-parallelism" }, "Max number of threads to use in Crossgen2 (default = logical processor count)", new Argument<int>());
+
Option IssuesPath() =>
new Option(new[] { "--issues-path", "-ip" }, "Path to issues.targets", new Argument<FileInfo[]>() { Arity = ArgumentArity.ZeroOrMore });
public CpaotRunner(BuildOptions options, IEnumerable<string> referencePaths)
: base(options, referencePaths)
- { }
+ {
+ // Set SuperIlc parallelism to a low enough value that ensures that each Crossgen2 invocation gets to use its parallelism
+ if (options.DegreeOfParallelism == 0)
+ options.DegreeOfParallelism = 2;
+ }
protected override ProcessParameters ExecutionProcess(IEnumerable<string> modules, IEnumerable<string> folders, bool noEtw)
{
yield return "--inputbubble";
}
+ if (_options.Crossgen2Parallelism != 0)
+ {
+ yield return $"--parallelism={_options.Crossgen2Parallelism}";
+ }
+
foreach (var reference in ComputeManagedAssemblies.GetManagedAssembliesInFolder(Path.GetDirectoryName(assemblyFileName)))
{
yield return $"-r:{reference}";
using System.Reflection.PortableExecutable;
using System.Runtime.CompilerServices;
using System.Threading;
+using System.Threading.Tasks;
using Internal.IL;
using Internal.IL.Stubs;
private readonly JitConfigProvider _jitConfigProvider;
/// <summary>
+ /// We only need one CorInfoImpl per thread, and we don't want to unnecessarily construct them
+ /// because their construction takes a significant amount of time.
+ /// </summary>
+ private readonly ConditionalWeakTable<Thread, CorInfoImpl> _corInfoImpls;
+
+ /// <summary>
/// Name of the compilation input MSIL file.
/// </summary>
private readonly string _inputFilePath;
private bool _resilient;
+ private int _parallelism;
+
public new ReadyToRunCodegenNodeFactory NodeFactory { get; }
public ReadyToRunSymbolNodeFactory SymbolNodeFactory { get; }
JitConfigProvider configProvider,
string inputFilePath,
IEnumerable<ModuleDesc> modulesBeingInstrumented,
- bool resilient)
+ bool resilient,
+ int parallelism)
: base(dependencyGraph, nodeFactory, roots, ilProvider, devirtualizationManager, modulesBeingInstrumented, logger)
{
_resilient = resilient;
+ _parallelism = parallelism;
NodeFactory = nodeFactory;
SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory);
_jitConfigProvider = configProvider;
_inputFilePath = inputFilePath;
+ _corInfoImpls = new ConditionalWeakTable<Thread, CorInfoImpl>();
CorInfoImpl.RegisterJITModule(configProvider);
}
{
using (PerfEventSource.StartStopEvents.JitEvents())
{
- ConditionalWeakTable<Thread, CorInfoImpl> cwt = new ConditionalWeakTable<Thread, CorInfoImpl>();
- foreach (DependencyNodeCore<NodeFactory> dependency in obj)
+ ParallelOptions options = new ParallelOptions
+ {
+ MaxDegreeOfParallelism = _parallelism
+ };
+ Parallel.ForEach(obj, options, dependency =>
{
MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
MethodDesc method = methodCodeNodeNeedingCode.Method;
{
using (PerfEventSource.StartStopEvents.JitMethodEvents())
{
- CorInfoImpl corInfoImpl = cwt.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
+ CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
corInfoImpl.CompileMethod(methodCodeNodeNeedingCode);
}
}
{
Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
}
- }
+ });
}
if (_methodILCache.Count > 1000)
{
private readonly string _inputFilePath;
private readonly EcmaModule _inputModule;
- private readonly bool _ibcTuning;
- private readonly bool _resilient;
+ private bool _ibcTuning;
+ private bool _resilient;
+ private int _parallelism;
private string _jitPath;
// These need to provide reasonable defaults so that the user can optionally skip
private KeyValuePair<string, string>[] _ryujitOptions = Array.Empty<KeyValuePair<string, string>>();
private ILProvider _ilProvider = new ReadyToRunILProvider();
- public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group, string inputFilePath, bool ibcTuning, bool resilient)
+ public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group, string inputFilePath)
: base(context, group, new CoreRTNameMangler())
{
_inputFilePath = inputFilePath;
- _ibcTuning = ibcTuning;
- _resilient = resilient;
-
_inputModule = context.GetModuleFromPath(_inputFilePath);
// R2R field layout needs compilation group information
return this;
}
+ public ReadyToRunCodegenCompilationBuilder UseIbcTuning(bool ibcTuning)
+ {
+ _ibcTuning = ibcTuning;
+ return this;
+ }
+
+ public ReadyToRunCodegenCompilationBuilder UseResilience(bool resilient)
+ {
+ _resilient = resilient;
+ return this;
+ }
+
+ public ReadyToRunCodegenCompilationBuilder UseParallelism(int parallelism)
+ {
+ _parallelism = parallelism;
+ return this;
+ }
+
+
public override ICompilation ToCompilation()
{
ModuleTokenResolver moduleTokenResolver = new ModuleTokenResolver(_compilationGroup, _context);
jitConfig,
_inputFilePath,
new ModuleDesc[] { _inputModule },
- _resilient);
+ _resilient,
+ _parallelism);
}
}
}
public bool Tuning { get; set; }
public bool Partial { get; set; }
public bool Resilient { get; set; }
+ public int Parallelism { get; set; }
+
public string SingleMethodTypeName { get; set; }
public string SingleMethodName { get; set; }
// We don't need to override arity here as 255 is the maximum number of generic arguments
Argument = new Argument<string[]>()
},
+ new Option(new[] { "--parallelism" }, "Maximum number of threads to use during compilation")
+ {
+ Argument = new Argument<int>(() => Environment.ProcessorCount)
+ },
};
}
}
inputFilePath = input.Value;
break;
}
- CompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(typeSystemContext, compilationGroup, inputFilePath,
- ibcTuning: _commandLineOptions.Tuning,
- resilient: _commandLineOptions.Resilient);
-
+ ReadyToRunCodegenCompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(typeSystemContext, compilationGroup, inputFilePath);
string compilationUnitPrefix = "";
builder.UseCompilationUnitPrefix(compilationUnitPrefix);
DependencyTrackingLevel.None : (_commandLineOptions.GenerateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
builder
+ .UseIbcTuning(_commandLineOptions.Tuning)
+ .UseResilience(_commandLineOptions.Resilient)
+ .UseParallelism(_commandLineOptions.Parallelism)
.UseILProvider(ilProvider)
.UseJitPath(_commandLineOptions.JitPath)
.UseBackendOptions(_commandLineOptions.CodegenOptions)