Skip to content

Commit 29acb2f

Browse files
Reuse crossgen2 logic to lay out methods using PGO data (#114736)
Fixes #114093.
1 parent e207619 commit 29acb2f

File tree

9 files changed

+95
-34
lines changed

9 files changed

+95
-34
lines changed

src/coreclr/tools/Common/Compiler/DependencyAnalysis/SortableDependencyNode.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ namespace ILCompiler.DependencyAnalysis
1313
public abstract partial class SortableDependencyNode : DependencyNodeCore<NodeFactory>, ISortableNode
1414
{
1515
#if !SUPPORT_JIT
16+
// Custom sort order. Used to override the default sorting mechanics.
17+
public int CustomSort = int.MaxValue;
18+
1619
/// <summary>
1720
/// Allows grouping of <see cref="ObjectNode"/> instances such that all nodes in a lower phase
1821
/// will be ordered before nodes in a later phase.
@@ -148,8 +151,6 @@ public int Compare(DependencyNodeCore<NodeFactory> x1, DependencyNodeCore<NodeFa
148151
}
149152
}
150153

151-
static partial void ApplyCustomSort(SortableDependencyNode x, SortableDependencyNode y, ref int result);
152-
153154
[MethodImpl(MethodImplOptions.AggressiveInlining)]
154155
public static int CompareImpl(SortableDependencyNode x, SortableDependencyNode y, CompilerComparer comparer)
155156
{
@@ -158,8 +159,7 @@ public static int CompareImpl(SortableDependencyNode x, SortableDependencyNode y
158159

159160
if (phaseX == phaseY)
160161
{
161-
int customSort = 0;
162-
ApplyCustomSort(x, y, ref customSort);
162+
int customSort = x.CustomSort.CompareTo(y.CustomSort);
163163
if (customSort != 0)
164164
return customSort;
165165

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/SortableDependencyNodeCompilerSpecific.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunFileLayoutOptimizer.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,20 @@
88
using Internal.TypeSystem;
99

1010
using ILCompiler.DependencyAnalysis;
11+
#if READYTORUN
1112
using ILCompiler.DependencyAnalysis.ReadyToRun;
13+
#endif
1214
using ILCompiler.DependencyAnalysisFramework;
1315
using System.Linq;
1416
using System.Collections.Immutable;
1517
using System.Text;
1618
using System.Reflection.Metadata.Ecma335;
1719
using ILCompiler.PettisHansenSort;
1820

21+
#if !READYTORUN
22+
using MethodWithGCInfo = ILCompiler.DependencyAnalysis.MethodCodeNode;
23+
#endif
24+
1925
namespace ILCompiler
2026
{
2127
public enum ReadyToRunMethodLayoutAlgorithm
@@ -24,7 +30,9 @@ public enum ReadyToRunMethodLayoutAlgorithm
2430
ExclusiveWeight,
2531
HotCold,
2632
HotWarmCold,
33+
#if READYTORUN
2734
CallFrequency,
35+
#endif
2836
PettisHansen,
2937
Random,
3038
}
@@ -79,11 +87,13 @@ public ImmutableArray<DependencyNodeCore<NodeFactory>> ApplyProfilerGuidedMethod
7987
foreach (var methodNode in sortedMethodsList)
8088
{
8189
methodNode.CustomSort = sortOrder;
90+
#if READYTORUN
8291
MethodColdCodeNode methodColdCodeNode = methodNode.ColdCodeNode;
8392
if (methodColdCodeNode != null)
8493
{
8594
methodColdCodeNode.CustomSort = sortOrder + sortedMethodsList.Count;
8695
}
96+
#endif
8797
sortOrder++;
8898
}
8999

@@ -164,9 +174,11 @@ int ComputeHotWarmColdRegion(MethodWithGCInfo method)
164174
};
165175
break;
166176

177+
#if READYTORUN
167178
case ReadyToRunMethodLayoutAlgorithm.CallFrequency:
168179
methods = MethodCallFrequencySort(methods);
169180
break;
181+
#endif
170182

171183
case ReadyToRunMethodLayoutAlgorithm.PettisHansen:
172184
methods = PettisHansenSort(methods);
@@ -216,6 +228,7 @@ public CallerCalleeCount(MethodDesc caller, MethodDesc callee, int count)
216228
}
217229
}
218230

231+
#if READYTORUN
219232
/// <summary>
220233
/// Use callchain profile information to generate method ordering. We place
221234
/// callers and callees by traversing the caller-callee pairs in the callchain
@@ -268,6 +281,7 @@ private List<MethodWithGCInfo> MethodCallFrequencySort(List<MethodWithGCInfo> me
268281
Debug.Assert(outputMethods.Count == methodsToPlace.Count);
269282
return outputMethods;
270283
}
284+
#endif
271285

272286
/// <summary>
273287
/// Sort methods with Pettis-Hansen using call graph data from profile.
@@ -303,7 +317,9 @@ private List<MethodWithGCInfo> PettisHansenSort(List<MethodWithGCInfo> methodsTo
303317

304318
if (!any)
305319
{
320+
#if READYTORUN
306321
_logger.Writer.WriteLine("Warning: no call graph data was found or a .mibc file was not specified. Skipping Pettis Hansen method ordering.");
322+
#endif
307323
return methodsToPlace;
308324
}
309325

src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@
242242
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\VirtualResolutionFixupSignature.cs" />
243243
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\Win32ResourcesNode.cs" />
244244
<Compile Include="Compiler\DependencyAnalysis\ReadyToRunSymbolNodeFactory.cs" />
245-
<Compile Include="Compiler\DependencyAnalysis\SortableDependencyNodeCompilerSpecific.cs" />
246245
<Compile Include="Compiler\DependencyAnalysis\TypeAndMethod.cs" />
247246
<Compile Include="Compiler\IRootingServiceProvider.cs" />
248247
<Compile Include="Compiler\ReadyToRunCompilationModuleGroupBase.cs" />

src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public sealed class RyuJitCompilation : Compilation
2525
private readonly ConditionalWeakTable<Thread, CorInfoImpl> _corinfos = new ConditionalWeakTable<Thread, CorInfoImpl>();
2626
internal readonly RyuJitCompilationOptions _compilationOptions;
2727
private readonly ProfileDataManager _profileDataManager;
28+
private readonly ReadyToRunFileLayoutOptimizer _fileLayoutOptimizer;
2829
private readonly MethodImportationErrorProvider _methodImportationErrorProvider;
2930
private readonly ReadOnlyFieldPolicy _readOnlyFieldPolicy;
3031
private readonly int _parallelism;
@@ -44,6 +45,8 @@ internal RyuJitCompilation(
4445
MethodImportationErrorProvider errorProvider,
4546
ReadOnlyFieldPolicy readOnlyFieldPolicy,
4647
RyuJitCompilationOptions options,
48+
ReadyToRunMethodLayoutAlgorithm methodLayoutAlgorithm,
49+
ReadyToRunFileLayoutAlgorithm fileLayoutAlgorithm,
4750
int parallelism)
4851
: base(dependencyGraph, nodeFactory, roots, ilProvider, debugInformationProvider, inliningPolicy, logger)
4952
{
@@ -57,6 +60,8 @@ internal RyuJitCompilation(
5760
_readOnlyFieldPolicy = readOnlyFieldPolicy;
5861

5962
_parallelism = parallelism;
63+
64+
_fileLayoutOptimizer = new ReadyToRunFileLayoutOptimizer(logger, methodLayoutAlgorithm, fileLayoutAlgorithm, profileDataManager, nodeFactory);
6065
}
6166

6267
public ProfileDataManager ProfileData => _profileDataManager;
@@ -89,6 +94,8 @@ protected override void CompileInternal(string outputFile, ObjectDumper dumper)
8994
_dependencyGraph.ComputeMarkedNodes();
9095
var nodes = _dependencyGraph.MarkedNodeList;
9196

97+
nodes = _fileLayoutOptimizer.ApplyProfilerGuidedMethodSort(nodes);
98+
9299
NodeFactory.SetMarkingComplete();
93100

94101
ObjectWritingOptions options = default;

src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilationBuilder.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public sealed class RyuJitCompilationBuilder : CompilationBuilder
1717
// These need to provide reasonable defaults so that the user can optionally skip
1818
// calling the Use/Configure methods and still get something reasonable back.
1919
private KeyValuePair<string, string>[] _ryujitOptions = Array.Empty<KeyValuePair<string, string>>();
20+
private ReadyToRunMethodLayoutAlgorithm _methodLayoutAlgorithm;
21+
private ReadyToRunFileLayoutAlgorithm _fileLayoutAlgorithm;
2022
private ILProvider _ilProvider = new NativeAotILProvider();
2123
private ProfileDataManager _profileDataManager;
2224
private string _jitPath;
@@ -39,6 +41,13 @@ public RyuJitCompilationBuilder UseJitPath(string jitPath)
3941
return this;
4042
}
4143

44+
public RyuJitCompilationBuilder FileLayoutAlgorithms(ReadyToRunMethodLayoutAlgorithm methodLayoutAlgorithm, ReadyToRunFileLayoutAlgorithm fileLayoutAlgorithm)
45+
{
46+
_methodLayoutAlgorithm = methodLayoutAlgorithm;
47+
_fileLayoutAlgorithm = fileLayoutAlgorithm;
48+
return this;
49+
}
50+
4251
public override CompilationBuilder UseBackendOptions(IEnumerable<string> options)
4352
{
4453
var builder = default(ArrayBuilder<KeyValuePair<string, string>>);
@@ -126,7 +135,21 @@ public override ICompilation ToCompilation()
126135

127136
JitConfigProvider.Initialize(_context.Target, jitFlagBuilder.ToArray(), _ryujitOptions, _jitPath);
128137
DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory, new ObjectNode.ObjectNodeComparer(CompilerComparer.Instance));
129-
return new RyuJitCompilation(graph, factory, _compilationRoots, _ilProvider, _debugInformationProvider, _logger, _inliningPolicy ?? _compilationGroup, _instructionSetSupport, _profileDataManager, _methodImportationErrorProvider, _readOnlyFieldPolicy, options, _parallelism);
138+
return new RyuJitCompilation(graph,
139+
factory,
140+
_compilationRoots,
141+
_ilProvider,
142+
_debugInformationProvider,
143+
_logger,
144+
_inliningPolicy ?? _compilationGroup,
145+
_instructionSetSupport,
146+
_profileDataManager,
147+
_methodImportationErrorProvider,
148+
_readOnlyFieldPolicy,
149+
options,
150+
_methodLayoutAlgorithm,
151+
_fileLayoutAlgorithm,
152+
_parallelism);
130153
}
131154
}
132155
}

src/coreclr/tools/aot/ILCompiler.RyuJit/ILCompiler.RyuJit.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
binaries are up to date and which are stale. -->
1616
<GenerateDependencyFile>false</GenerateDependencyFile>
1717
<Configurations>Debug;Release;Checked</Configurations>
18+
<RunAnalyzers>false</RunAnalyzers>
1819
</PropertyGroup>
1920

2021
<ItemGroup>
@@ -98,5 +99,9 @@
9899

99100
<Compile Include="..\ILCompiler.ReadyToRun\Compiler\ProfileData.cs" Link="Pgo\ProfileData.cs" />
100101

102+
<Compile Include="..\ILCompiler.ReadyToRun\Compiler\PettisHansenSort\CallGraphNode.cs" Link="Compiler\PettisHansenSort\CallGraphNode.cs" />
103+
<Compile Include="..\ILCompiler.ReadyToRun\Compiler\PettisHansenSort\DisjointSetForest.cs" Link="Compiler\PettisHansenSort\DisjointSetForest.cs" />
104+
<Compile Include="..\ILCompiler.ReadyToRun\Compiler\PettisHansenSort\PettisHansen.cs" Link="Compiler\PettisHansenSort\PettisHansen.cs" />
105+
<Compile Include="..\ILCompiler.ReadyToRun\Compiler\ReadyToRunFileLayoutOptimizer.cs" Link="Compiler\ReadyToRunFileLayoutOptimizer.cs" />
101106
</ItemGroup>
102107
</Project>

src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ internal sealed class ILCompilerRootCommand : RootCommand
2727
new("--optimize-time", "--Ot") { Description = "Enable optimizations, favor code speed" };
2828
public Option<string[]> MibcFilePaths { get; } =
2929
new("--mibc", "-m") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Mibc file(s) for profile guided optimization" };
30+
public Option<ReadyToRunMethodLayoutAlgorithm> MethodLayout { get; } =
31+
new("--method-layout") { CustomParser = MakeReadyToRunMethodLayoutAlgorithm, DefaultValueFactory = MakeReadyToRunMethodLayoutAlgorithm, Description = "Layout algorithm used by profile-driven optimization for arranging methods in a file.", HelpName = "arg" };
32+
public Option<ReadyToRunFileLayoutAlgorithm> FileLayout { get; } =
33+
new("--file-layout") { CustomParser = MakeReadyToRunFileLayoutAlgorithm, DefaultValueFactory = MakeReadyToRunFileLayoutAlgorithm, Description = "Layout algorithm used by profile-driven optimization for arranging non-method contents in a file.", HelpName = "arg" };
3034
public Option<string[]> SatelliteFilePaths { get; } =
3135
new("--satellite") { DefaultValueFactory = _ => Array.Empty<string>(), Description = "Satellite assemblies associated with inputs/references" };
3236
public Option<bool> EnableDebugInfo { get; } =
@@ -187,6 +191,8 @@ public ILCompilerRootCommand(string[] args) : base(".NET Native IL Compiler")
187191
Options.Add(OptimizeSpace);
188192
Options.Add(OptimizeTime);
189193
Options.Add(MibcFilePaths);
194+
Options.Add(MethodLayout);
195+
Options.Add(FileLayout);
190196
Options.Add(SatelliteFilePaths);
191197
Options.Add(EnableDebugInfo);
192198
Options.Add(UseDwarf5);
@@ -411,6 +417,36 @@ private static int MakeParallelism(ArgumentResult result)
411417
return parallelism;
412418
}
413419

420+
private static ReadyToRunMethodLayoutAlgorithm MakeReadyToRunMethodLayoutAlgorithm(ArgumentResult result)
421+
{
422+
if (result.Tokens.Count == 0)
423+
return ReadyToRunMethodLayoutAlgorithm.DefaultSort;
424+
425+
return result.Tokens[0].Value.ToLowerInvariant() switch
426+
{
427+
"defaultsort" => ReadyToRunMethodLayoutAlgorithm.DefaultSort,
428+
"exclusiveweight" => ReadyToRunMethodLayoutAlgorithm.ExclusiveWeight,
429+
"hotcold" => ReadyToRunMethodLayoutAlgorithm.HotCold,
430+
"hotwarmcold" => ReadyToRunMethodLayoutAlgorithm.HotWarmCold,
431+
"pettishansen" => ReadyToRunMethodLayoutAlgorithm.PettisHansen,
432+
"random" => ReadyToRunMethodLayoutAlgorithm.Random,
433+
_ => throw new CommandLineException(result.Tokens[0].Value)
434+
};
435+
}
436+
437+
private static ReadyToRunFileLayoutAlgorithm MakeReadyToRunFileLayoutAlgorithm(ArgumentResult result)
438+
{
439+
if (result.Tokens.Count == 0)
440+
return ReadyToRunFileLayoutAlgorithm.DefaultSort;
441+
442+
return result.Tokens[0].Value.ToLowerInvariant() switch
443+
{
444+
"defaultsort" => ReadyToRunFileLayoutAlgorithm.DefaultSort,
445+
"methodorder" => ReadyToRunFileLayoutAlgorithm.MethodOrder,
446+
_ => throw new CommandLineException(result.Tokens[0].Value)
447+
};
448+
}
449+
414450
#if DEBUG
415451
private static bool DumpReproArguments(CodeGenerationFailedException ex)
416452
{

src/coreclr/tools/aot/ILCompiler/Program.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,10 @@ public int Run()
348348
// Compile
349349
//
350350

351-
var builder = new RyuJitCompilationBuilder(typeSystemContext, compilationGroup);
352-
353351
string compilationUnitPrefix = multiFile ? Path.GetFileNameWithoutExtension(outputFilePath) : "";
354-
builder.UseCompilationUnitPrefix(compilationUnitPrefix);
352+
var builder = new RyuJitCompilationBuilder(typeSystemContext, compilationGroup)
353+
.FileLayoutAlgorithms(Get(_command.MethodLayout), Get(_command.FileLayout))
354+
.UseCompilationUnitPrefix(compilationUnitPrefix);
355355

356356
string[] mibcFilePaths = Get(_command.MibcFilePaths);
357357
if (mibcFilePaths.Length > 0)

0 commit comments

Comments
 (0)