xref: /llvm-project/bolt/lib/Passes/ReorderFunctions.cpp (revision aa9cc721e58f086ba6a3f9711fefdb61a184f786)
12f09f445SMaksim Panchenko //===- bolt/Passes/ReorderFunctions.cpp - Function reordering pass --------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements ReorderFunctions class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "bolt/Passes/ReorderFunctions.h"
14a34c753fSRafael Auler #include "bolt/Passes/HFSort.h"
15287508cdSAmir Ayupov #include "bolt/Utils/Utils.h"
16287508cdSAmir Ayupov #include "llvm/ADT/STLExtras.h"
17a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
18b402487bSspupyrev #include "llvm/Transforms/Utils/CodeLayout.h"
19a34c753fSRafael Auler #include <fstream>
20a34c753fSRafael Auler 
21a34c753fSRafael Auler #define DEBUG_TYPE "hfsort"
22a34c753fSRafael Auler 
23a34c753fSRafael Auler using namespace llvm;
24a34c753fSRafael Auler 
25a34c753fSRafael Auler namespace opts {
26a34c753fSRafael Auler 
27a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
28a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity;
29a34c753fSRafael Auler extern cl::opt<uint32_t> RandomSeed;
30a34c753fSRafael Auler 
31*aa9cc721SPeter Waller extern size_t padFunctionBefore(const bolt::BinaryFunction &Function);
32*aa9cc721SPeter Waller extern size_t padFunctionAfter(const bolt::BinaryFunction &Function);
33a34c753fSRafael Auler 
349058503dSspupyrev extern cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions;
352b642926SAmir Ayupov cl::opt<bolt::ReorderFunctions::ReorderType> ReorderFunctions(
362b642926SAmir Ayupov     "reorder-functions",
37a34c753fSRafael Auler     cl::desc("reorder and cluster functions (works only with relocations)"),
38a34c753fSRafael Auler     cl::init(bolt::ReorderFunctions::RT_NONE),
392b642926SAmir Ayupov     cl::values(clEnumValN(bolt::ReorderFunctions::RT_NONE, "none",
40a34c753fSRafael Auler                           "do not reorder functions"),
412b642926SAmir Ayupov                clEnumValN(bolt::ReorderFunctions::RT_EXEC_COUNT, "exec-count",
42a34c753fSRafael Auler                           "order by execution count"),
432b642926SAmir Ayupov                clEnumValN(bolt::ReorderFunctions::RT_HFSORT, "hfsort",
44a34c753fSRafael Auler                           "use hfsort algorithm"),
452b642926SAmir Ayupov                clEnumValN(bolt::ReorderFunctions::RT_HFSORT_PLUS, "hfsort+",
469058503dSspupyrev                           "use cache-directed sort"),
47287fcd38Sspupyrev                clEnumValN(bolt::ReorderFunctions::RT_CDSORT, "cdsort",
48b402487bSspupyrev                           "use cache-directed sort"),
49a34c753fSRafael Auler                clEnumValN(bolt::ReorderFunctions::RT_PETTIS_HANSEN,
502b642926SAmir Ayupov                           "pettis-hansen", "use Pettis-Hansen algorithm"),
512b642926SAmir Ayupov                clEnumValN(bolt::ReorderFunctions::RT_RANDOM, "random",
52a34c753fSRafael Auler                           "reorder functions randomly"),
532b642926SAmir Ayupov                clEnumValN(bolt::ReorderFunctions::RT_USER, "user",
54a34c753fSRafael Auler                           "use function order specified by -function-order")),
559058503dSspupyrev     cl::ZeroOrMore, cl::cat(BoltOptCategory),
569058503dSspupyrev     cl::callback([](const bolt::ReorderFunctions::ReorderType &option) {
579058503dSspupyrev       if (option == bolt::ReorderFunctions::RT_HFSORT_PLUS) {
589058503dSspupyrev         errs() << "BOLT-WARNING: '-reorder-functions=hfsort+' is deprecated,"
599058503dSspupyrev                << " please use '-reorder-functions=cdsort' instead\n";
609058503dSspupyrev         ReorderFunctions = bolt::ReorderFunctions::RT_CDSORT;
619058503dSspupyrev       }
629058503dSspupyrev     }));
63a34c753fSRafael Auler 
64b92436efSFangrui Song static cl::opt<bool> ReorderFunctionsUseHotSize(
65b92436efSFangrui Song     "reorder-functions-use-hot-size",
66b92436efSFangrui Song     cl::desc("use a function's hot size when doing clustering"), cl::init(true),
67a34c753fSRafael Auler     cl::cat(BoltOptCategory));
68a34c753fSRafael Auler 
692b642926SAmir Ayupov static cl::opt<std::string> FunctionOrderFile(
702b642926SAmir Ayupov     "function-order",
71a34c753fSRafael Auler     cl::desc("file containing an ordered list of functions to use for function "
72a34c753fSRafael Auler              "reordering"),
73a34c753fSRafael Auler     cl::cat(BoltOptCategory));
74a34c753fSRafael Auler 
752b642926SAmir Ayupov static cl::opt<std::string> GenerateFunctionOrderFile(
762b642926SAmir Ayupov     "generate-function-order",
77a34c753fSRafael Auler     cl::desc("file to dump the ordered list of functions to use for function "
78a34c753fSRafael Auler              "reordering"),
79a34c753fSRafael Auler     cl::cat(BoltOptCategory));
80a34c753fSRafael Auler 
812b642926SAmir Ayupov static cl::opt<std::string> LinkSectionsFile(
822b642926SAmir Ayupov     "generate-link-sections",
83a34c753fSRafael Auler     cl::desc("generate a list of function sections in a format suitable for "
84a34c753fSRafael Auler              "inclusion in a linker script"),
85a34c753fSRafael Auler     cl::cat(BoltOptCategory));
86a34c753fSRafael Auler 
87a34c753fSRafael Auler static cl::opt<bool>
88a34c753fSRafael Auler     UseEdgeCounts("use-edge-counts",
89a34c753fSRafael Auler                   cl::desc("use edge count data when doing clustering"),
90b92436efSFangrui Song                   cl::init(true), cl::cat(BoltOptCategory));
91a34c753fSRafael Auler 
922b642926SAmir Ayupov static cl::opt<bool> CgFromPerfData(
932b642926SAmir Ayupov     "cg-from-perf-data",
94a34c753fSRafael Auler     cl::desc("use perf data directly when constructing the call graph"
95a34c753fSRafael Auler              " for stale functions"),
962b642926SAmir Ayupov     cl::init(true), cl::ZeroOrMore, cl::cat(BoltOptCategory));
97a34c753fSRafael Auler 
98b92436efSFangrui Song static cl::opt<bool> CgIgnoreRecursiveCalls(
99b92436efSFangrui Song     "cg-ignore-recursive-calls",
100a34c753fSRafael Auler     cl::desc("ignore recursive calls when constructing the call graph"),
101b92436efSFangrui Song     cl::init(true), cl::cat(BoltOptCategory));
102a34c753fSRafael Auler 
1032b642926SAmir Ayupov static cl::opt<bool> CgUseSplitHotSize(
1042b642926SAmir Ayupov     "cg-use-split-hot-size",
105a34c753fSRafael Auler     cl::desc("use hot/cold data on basic blocks to determine hot sizes for "
106a34c753fSRafael Auler              "call graph functions"),
1072b642926SAmir Ayupov     cl::init(false), cl::ZeroOrMore, cl::cat(BoltOptCategory));
108a34c753fSRafael Auler 
109a34c753fSRafael Auler } // namespace opts
110a34c753fSRafael Auler 
111a34c753fSRafael Auler namespace llvm {
112a34c753fSRafael Auler namespace bolt {
113a34c753fSRafael Auler 
114a34c753fSRafael Auler using NodeId = CallGraph::NodeId;
115a34c753fSRafael Auler using Arc = CallGraph::Arc;
116a34c753fSRafael Auler using Node = CallGraph::Node;
117a34c753fSRafael Auler 
11852cf0711SAmir Ayupov void ReorderFunctions::reorder(BinaryContext &BC,
11952cf0711SAmir Ayupov                                std::vector<Cluster> &&Clusters,
120a34c753fSRafael Auler                                std::map<uint64_t, BinaryFunction> &BFs) {
121a34c753fSRafael Auler   std::vector<uint64_t> FuncAddr(Cg.numNodes()); // Just for computing stats
122a34c753fSRafael Auler   uint64_t TotalSize = 0;
123a34c753fSRafael Auler   uint32_t Index = 0;
124a34c753fSRafael Auler 
125a34c753fSRafael Auler   // Set order of hot functions based on clusters.
126a34c753fSRafael Auler   for (const Cluster &Cluster : Clusters) {
127a34c753fSRafael Auler     for (const NodeId FuncId : Cluster.targets()) {
128a34c753fSRafael Auler       Cg.nodeIdToFunc(FuncId)->setIndex(Index++);
129a34c753fSRafael Auler       FuncAddr[FuncId] = TotalSize;
130a34c753fSRafael Auler       TotalSize += Cg.size(FuncId);
131a34c753fSRafael Auler     }
132a34c753fSRafael Auler   }
133a34c753fSRafael Auler 
134fd960495SVladislav Khmelevsky   // Assign valid index for functions with valid profile.
135fd960495SVladislav Khmelevsky   for (auto &It : BFs) {
136fd960495SVladislav Khmelevsky     BinaryFunction &BF = It.second;
137fd960495SVladislav Khmelevsky     if (!BF.hasValidIndex() && BF.hasValidProfile())
138fd960495SVladislav Khmelevsky       BF.setIndex(Index++);
139fd960495SVladislav Khmelevsky   }
140fd960495SVladislav Khmelevsky 
141a34c753fSRafael Auler   if (opts::ReorderFunctions == RT_NONE)
142a34c753fSRafael Auler     return;
143a34c753fSRafael Auler 
14452cf0711SAmir Ayupov   printStats(BC, Clusters, FuncAddr);
14586b47f14SAmir Ayupov }
14686b47f14SAmir Ayupov 
14752cf0711SAmir Ayupov void ReorderFunctions::printStats(BinaryContext &BC,
14852cf0711SAmir Ayupov                                   const std::vector<Cluster> &Clusters,
14986b47f14SAmir Ayupov                                   const std::vector<uint64_t> &FuncAddr) {
150a34c753fSRafael Auler   if (opts::Verbosity == 0) {
151a34c753fSRafael Auler #ifndef NDEBUG
152a34c753fSRafael Auler     if (!DebugFlag || !isCurrentDebugType("hfsort"))
153a34c753fSRafael Auler       return;
154a34c753fSRafael Auler #else
155a34c753fSRafael Auler     return;
156a34c753fSRafael Auler #endif
157a34c753fSRafael Auler   }
158a34c753fSRafael Auler 
159a34c753fSRafael Auler   bool PrintDetailed = opts::Verbosity > 1;
160a34c753fSRafael Auler #ifndef NDEBUG
161a34c753fSRafael Auler   PrintDetailed |=
162a34c753fSRafael Auler       (DebugFlag && isCurrentDebugType("hfsort") && opts::Verbosity > 0);
163a34c753fSRafael Auler #endif
16486b47f14SAmir Ayupov   uint64_t TotalSize = 0;
165a34c753fSRafael Auler   uint64_t CurPage = 0;
166a34c753fSRafael Auler   uint64_t Hotfuncs = 0;
167a34c753fSRafael Auler   double TotalDistance = 0;
168a34c753fSRafael Auler   double TotalCalls = 0;
169a34c753fSRafael Auler   double TotalCalls64B = 0;
170a34c753fSRafael Auler   double TotalCalls4KB = 0;
171a34c753fSRafael Auler   double TotalCalls2MB = 0;
172f92ab6afSAmir Ayupov   if (PrintDetailed)
17352cf0711SAmir Ayupov     BC.outs() << "BOLT-INFO: Function reordering page layout\n"
174a34c753fSRafael Auler               << "BOLT-INFO: ============== page 0 ==============\n";
17586b47f14SAmir Ayupov   for (const Cluster &Cluster : Clusters) {
176f92ab6afSAmir Ayupov     if (PrintDetailed)
17752cf0711SAmir Ayupov       BC.outs() << format(
17840c2e0faSMaksim Panchenko           "BOLT-INFO: -------- density = %.3lf (%u / %u) --------\n",
179a34c753fSRafael Auler           Cluster.density(), Cluster.samples(), Cluster.size());
180a34c753fSRafael Auler 
181a34c753fSRafael Auler     for (NodeId FuncId : Cluster.targets()) {
182a34c753fSRafael Auler       if (Cg.samples(FuncId) > 0) {
183a34c753fSRafael Auler         Hotfuncs++;
184a34c753fSRafael Auler 
185f92ab6afSAmir Ayupov         if (PrintDetailed)
18652cf0711SAmir Ayupov           BC.outs() << "BOLT-INFO: hot func " << *Cg.nodeIdToFunc(FuncId)
18752cf0711SAmir Ayupov                     << " (" << Cg.size(FuncId) << ")\n";
188a34c753fSRafael Auler 
189a34c753fSRafael Auler         uint64_t Dist = 0;
190a34c753fSRafael Auler         uint64_t Calls = 0;
191a34c753fSRafael Auler         for (NodeId Dst : Cg.successors(FuncId)) {
192a34c753fSRafael Auler           if (FuncId == Dst) // ignore recursive calls in stats
193a34c753fSRafael Auler             continue;
194a34c753fSRafael Auler           const Arc &Arc = *Cg.findArc(FuncId, Dst);
195a34c753fSRafael Auler           const auto D = std::abs(FuncAddr[Arc.dst()] -
196a34c753fSRafael Auler                                   (FuncAddr[FuncId] + Arc.avgCallOffset()));
197a34c753fSRafael Auler           const double W = Arc.weight();
198f92ab6afSAmir Ayupov           if (D < 64 && PrintDetailed && opts::Verbosity > 2)
19952cf0711SAmir Ayupov             BC.outs() << "BOLT-INFO: short (" << D << "B) call:\n"
20052cf0711SAmir Ayupov                       << "BOLT-INFO:   Src: " << *Cg.nodeIdToFunc(FuncId)
20152cf0711SAmir Ayupov                       << "\n"
202a34c753fSRafael Auler                       << "BOLT-INFO:   Dst: " << *Cg.nodeIdToFunc(Dst) << "\n"
203a34c753fSRafael Auler                       << "BOLT-INFO:   Weight = " << W << "\n"
2042b642926SAmir Ayupov                       << "BOLT-INFO:   AvgOffset = " << Arc.avgCallOffset()
2052b642926SAmir Ayupov                       << "\n";
206a34c753fSRafael Auler           Calls += W;
2072b642926SAmir Ayupov           if (D < 64)
2082b642926SAmir Ayupov             TotalCalls64B += W;
2092b642926SAmir Ayupov           if (D < 4096)
2102b642926SAmir Ayupov             TotalCalls4KB += W;
2112b642926SAmir Ayupov           if (D < (2 << 20))
2122b642926SAmir Ayupov             TotalCalls2MB += W;
213a34c753fSRafael Auler           Dist += Arc.weight() * D;
214f92ab6afSAmir Ayupov           if (PrintDetailed)
21552cf0711SAmir Ayupov             BC.outs() << format("BOLT-INFO: arc: %u [@%lu+%.1lf] -> %u [@%lu]: "
216a34c753fSRafael Auler                                 "weight = %.0lf, callDist = %f\n",
2172b642926SAmir Ayupov                                 Arc.src(), FuncAddr[Arc.src()],
2182b642926SAmir Ayupov                                 Arc.avgCallOffset(), Arc.dst(),
2192b642926SAmir Ayupov                                 FuncAddr[Arc.dst()], Arc.weight(), D);
220a34c753fSRafael Auler         }
221a34c753fSRafael Auler         TotalCalls += Calls;
222a34c753fSRafael Auler         TotalDistance += Dist;
223a34c753fSRafael Auler         TotalSize += Cg.size(FuncId);
224a34c753fSRafael Auler 
225a34c753fSRafael Auler         if (PrintDetailed) {
22652cf0711SAmir Ayupov           BC.outs() << format("BOLT-INFO: start = %6u : avgCallDist = %lu : ",
22740c2e0faSMaksim Panchenko                               TotalSize, Calls ? Dist / Calls : 0)
228a34c753fSRafael Auler                     << Cg.nodeIdToFunc(FuncId)->getPrintName() << '\n';
229a34c753fSRafael Auler           const uint64_t NewPage = TotalSize / HugePageSize;
230a34c753fSRafael Auler           if (NewPage != CurPage) {
231a34c753fSRafael Auler             CurPage = NewPage;
23252cf0711SAmir Ayupov             BC.outs() << format(
23340c2e0faSMaksim Panchenko                 "BOLT-INFO: ============== page %u ==============\n", CurPage);
234a34c753fSRafael Auler           }
235a34c753fSRafael Auler         }
236a34c753fSRafael Auler       }
237a34c753fSRafael Auler     }
238a34c753fSRafael Auler   }
23952cf0711SAmir Ayupov   BC.outs() << "BOLT-INFO: Function reordering stats\n"
240a34c753fSRafael Auler             << format("BOLT-INFO:  Number of hot functions: %u\n"
241a34c753fSRafael Auler                       "BOLT-INFO:  Number of clusters: %lu\n",
242a34c753fSRafael Auler                       Hotfuncs, Clusters.size())
243a34c753fSRafael Auler             << format("BOLT-INFO:  Final average call distance = %.1lf "
244a34c753fSRafael Auler                       "(%.0lf / %.0lf)\n",
24552cf0711SAmir Ayupov                       TotalCalls ? TotalDistance / TotalCalls : 0,
24652cf0711SAmir Ayupov                       TotalDistance, TotalCalls)
247a34c753fSRafael Auler             << format("BOLT-INFO:  Total Calls = %.0lf\n", TotalCalls);
248f92ab6afSAmir Ayupov   if (TotalCalls)
24952cf0711SAmir Ayupov     BC.outs()
25052cf0711SAmir Ayupov         << format("BOLT-INFO:  Total Calls within 64B = %.0lf (%.2lf%%)\n",
251a34c753fSRafael Auler                   TotalCalls64B, 100 * TotalCalls64B / TotalCalls)
252a34c753fSRafael Auler         << format("BOLT-INFO:  Total Calls within 4KB = %.0lf (%.2lf%%)\n",
253a34c753fSRafael Auler                   TotalCalls4KB, 100 * TotalCalls4KB / TotalCalls)
254a34c753fSRafael Auler         << format("BOLT-INFO:  Total Calls within 2MB = %.0lf (%.2lf%%)\n",
255a34c753fSRafael Auler                   TotalCalls2MB, 100 * TotalCalls2MB / TotalCalls);
256a34c753fSRafael Auler }
257a34c753fSRafael Auler 
25813d60ce2SAmir Ayupov Error ReorderFunctions::readFunctionOrderFile(
25913d60ce2SAmir Ayupov     std::vector<std::string> &FunctionNames) {
260a34c753fSRafael Auler   std::ifstream FuncsFile(opts::FunctionOrderFile, std::ios::in);
26113d60ce2SAmir Ayupov   if (!FuncsFile)
26213d60ce2SAmir Ayupov     return createFatalBOLTError(Twine("Ordered functions file \"") +
26313d60ce2SAmir Ayupov                                 Twine(opts::FunctionOrderFile) +
26413d60ce2SAmir Ayupov                                 Twine("\" can't be opened."));
26513d60ce2SAmir Ayupov 
266a34c753fSRafael Auler   std::string FuncName;
267f92ab6afSAmir Ayupov   while (std::getline(FuncsFile, FuncName))
268a34c753fSRafael Auler     FunctionNames.push_back(FuncName);
26913d60ce2SAmir Ayupov   return Error::success();
270a34c753fSRafael Auler }
271a34c753fSRafael Auler 
272a5f3d1a8SAmir Ayupov Error ReorderFunctions::runOnFunctions(BinaryContext &BC) {
273a34c753fSRafael Auler   auto &BFs = BC.getBinaryFunctions();
274a34c753fSRafael Auler   if (opts::ReorderFunctions != RT_NONE &&
275a34c753fSRafael Auler       opts::ReorderFunctions != RT_EXEC_COUNT &&
276a34c753fSRafael Auler       opts::ReorderFunctions != RT_USER) {
277ac830664SFabian Parzefall     Cg = buildCallGraph(
278ac830664SFabian Parzefall         BC,
279a34c753fSRafael Auler         [](const BinaryFunction &BF) {
280a34c753fSRafael Auler           if (!BF.hasProfile())
281a34c753fSRafael Auler             return true;
282a34c753fSRafael Auler           if (BF.getState() != BinaryFunction::State::CFG)
283a34c753fSRafael Auler             return true;
284a34c753fSRafael Auler           return false;
285a34c753fSRafael Auler         },
286a34c753fSRafael Auler         opts::CgFromPerfData,
287ac830664SFabian Parzefall         /*IncludeSplitCalls=*/false, opts::ReorderFunctionsUseHotSize,
288ac830664SFabian Parzefall         opts::CgUseSplitHotSize, opts::UseEdgeCounts,
289a34c753fSRafael Auler         opts::CgIgnoreRecursiveCalls);
290a34c753fSRafael Auler     Cg.normalizeArcWeights();
291a34c753fSRafael Auler   }
292a34c753fSRafael Auler 
293a34c753fSRafael Auler   std::vector<Cluster> Clusters;
294a34c753fSRafael Auler 
295a34c753fSRafael Auler   switch (opts::ReorderFunctions) {
296a34c753fSRafael Auler   case RT_NONE:
297a34c753fSRafael Auler     break;
2982b642926SAmir Ayupov   case RT_EXEC_COUNT: {
299a34c753fSRafael Auler     std::vector<BinaryFunction *> SortedFunctions(BFs.size());
30072e5b14fSAmir Ayupov     llvm::transform(llvm::make_second_range(BFs), SortedFunctions.begin(),
30172e5b14fSAmir Ayupov                     [](BinaryFunction &BF) { return &BF; });
3029460ebd1Sspupyrev     llvm::stable_sort(SortedFunctions,
3039460ebd1Sspupyrev                       [&](const BinaryFunction *A, const BinaryFunction *B) {
304a34c753fSRafael Auler                         if (A->isIgnored())
305a34c753fSRafael Auler                           return false;
3069460ebd1Sspupyrev                         if (B->isIgnored())
3079460ebd1Sspupyrev                           return true;
308*aa9cc721SPeter Waller                         const size_t PadA = opts::padFunctionBefore(*A) +
309*aa9cc721SPeter Waller                                             opts::padFunctionAfter(*A);
310*aa9cc721SPeter Waller                         const size_t PadB = opts::padFunctionBefore(*B) +
311*aa9cc721SPeter Waller                                             opts::padFunctionAfter(*B);
312a34c753fSRafael Auler                         if (!PadA || !PadB) {
313a34c753fSRafael Auler                           if (PadA)
314a34c753fSRafael Auler                             return true;
315a34c753fSRafael Auler                           if (PadB)
316a34c753fSRafael Auler                             return false;
317a34c753fSRafael Auler                         }
3189460ebd1Sspupyrev                         if (!A->hasProfile())
3199460ebd1Sspupyrev                           return false;
3209460ebd1Sspupyrev                         if (!B->hasProfile())
3219460ebd1Sspupyrev                           return true;
3229460ebd1Sspupyrev                         return A->getExecutionCount() > B->getExecutionCount();
323a34c753fSRafael Auler                       });
3249460ebd1Sspupyrev     uint32_t Index = 0;
325f92ab6afSAmir Ayupov     for (BinaryFunction *BF : SortedFunctions)
3269460ebd1Sspupyrev       if (BF->hasProfile()) {
327a34c753fSRafael Auler         BF->setIndex(Index++);
3289460ebd1Sspupyrev         LLVM_DEBUG(if (opts::Verbosity > 1) {
3299460ebd1Sspupyrev           dbgs() << "BOLT-INFO: hot func " << BF->getPrintName() << " ("
3309460ebd1Sspupyrev                  << BF->getExecutionCount() << ")\n";
3319460ebd1Sspupyrev         });
3329460ebd1Sspupyrev       }
3332b642926SAmir Ayupov   } break;
334a34c753fSRafael Auler   case RT_HFSORT:
335a34c753fSRafael Auler     Clusters = clusterize(Cg);
336a34c753fSRafael Auler     break;
337287fcd38Sspupyrev   case RT_CDSORT: {
338b402487bSspupyrev     // It is required that the sum of incoming arc weights is not greater
339b402487bSspupyrev     // than the number of samples for every function. Ensuring the call graph
340b402487bSspupyrev     // obeys the property before running the algorithm.
341b402487bSspupyrev     Cg.adjustArcWeights();
342b402487bSspupyrev 
343b402487bSspupyrev     // Initialize CFG nodes and their data
344b402487bSspupyrev     std::vector<uint64_t> FuncSizes;
345b402487bSspupyrev     std::vector<uint64_t> FuncCounts;
3466b8d04c2SFangrui Song     std::vector<codelayout::EdgeCount> CallCounts;
347b402487bSspupyrev     std::vector<uint64_t> CallOffsets;
348b402487bSspupyrev     for (NodeId F = 0; F < Cg.numNodes(); ++F) {
349b402487bSspupyrev       FuncSizes.push_back(Cg.size(F));
350b402487bSspupyrev       FuncCounts.push_back(Cg.samples(F));
351b402487bSspupyrev       for (NodeId Succ : Cg.successors(F)) {
352b402487bSspupyrev         const Arc &Arc = *Cg.findArc(F, Succ);
3536b8d04c2SFangrui Song         CallCounts.push_back({F, Succ, uint64_t(Arc.weight())});
354b402487bSspupyrev         CallOffsets.push_back(uint64_t(Arc.avgCallOffset()));
355b402487bSspupyrev       }
356b402487bSspupyrev     }
357b402487bSspupyrev 
358b402487bSspupyrev     // Run the layout algorithm.
3596b8d04c2SFangrui Song     std::vector<uint64_t> Result = codelayout::computeCacheDirectedLayout(
3606b8d04c2SFangrui Song         FuncSizes, FuncCounts, CallCounts, CallOffsets);
361b402487bSspupyrev 
362b402487bSspupyrev     // Create a single cluster from the computed order of hot functions.
363299ec3c2Sspupyrev     std::vector<CallGraph::NodeId> NodeOrder(Result.begin(), Result.end());
364299ec3c2Sspupyrev     Clusters.emplace_back(Cluster(NodeOrder, Cg));
365b402487bSspupyrev   } break;
366a34c753fSRafael Auler   case RT_PETTIS_HANSEN:
367a34c753fSRafael Auler     Clusters = pettisAndHansen(Cg);
368a34c753fSRafael Auler     break;
369a34c753fSRafael Auler   case RT_RANDOM:
370a34c753fSRafael Auler     std::srand(opts::RandomSeed);
371a34c753fSRafael Auler     Clusters = randomClusters(Cg);
372a34c753fSRafael Auler     break;
3732b642926SAmir Ayupov   case RT_USER: {
374287508cdSAmir Ayupov     // Build LTOCommonNameMap
375287508cdSAmir Ayupov     StringMap<std::vector<uint64_t>> LTOCommonNameMap;
376287508cdSAmir Ayupov     for (const BinaryFunction &BF : llvm::make_second_range(BFs))
377287508cdSAmir Ayupov       for (StringRef Name : BF.getNames())
378287508cdSAmir Ayupov         if (std::optional<StringRef> LTOCommonName = getLTOCommonName(Name))
379287508cdSAmir Ayupov           LTOCommonNameMap[*LTOCommonName].push_back(BF.getAddress());
380287508cdSAmir Ayupov 
381a34c753fSRafael Auler     uint32_t Index = 0;
382e2007405SAmir Ayupov     uint32_t InvalidEntries = 0;
38313d60ce2SAmir Ayupov     std::vector<std::string> FunctionNames;
38413d60ce2SAmir Ayupov     if (Error E = readFunctionOrderFile(FunctionNames))
38513d60ce2SAmir Ayupov       return Error(std::move(E));
38613d60ce2SAmir Ayupov 
38713d60ce2SAmir Ayupov     for (const std::string &Function : FunctionNames) {
388a34c753fSRafael Auler       std::vector<uint64_t> FuncAddrs;
389a34c753fSRafael Auler 
390a34c753fSRafael Auler       BinaryData *BD = BC.getBinaryDataByName(Function);
391a34c753fSRafael Auler       if (!BD) {
392287508cdSAmir Ayupov         // If we can't find the main symbol name, look for alternates.
393a34c753fSRafael Auler         uint32_t LocalID = 1;
3941bf531a5SKazu Hirata         while (true) {
3952b642926SAmir Ayupov           const std::string FuncName = Function + "/" + std::to_string(LocalID);
396a34c753fSRafael Auler           BD = BC.getBinaryDataByName(FuncName);
397a34c753fSRafael Auler           if (BD)
398a34c753fSRafael Auler             FuncAddrs.push_back(BD->getAddress());
399a34c753fSRafael Auler           else
400a34c753fSRafael Auler             break;
401a34c753fSRafael Auler           LocalID++;
402a34c753fSRafael Auler         }
403287508cdSAmir Ayupov         // Strip LTO suffixes
404287508cdSAmir Ayupov         if (std::optional<StringRef> CommonName = getLTOCommonName(Function))
4054e585e51SKazu Hirata           if (LTOCommonNameMap.contains(*CommonName))
406287508cdSAmir Ayupov             llvm::append_range(FuncAddrs, LTOCommonNameMap[*CommonName]);
407a34c753fSRafael Auler       } else {
408a34c753fSRafael Auler         FuncAddrs.push_back(BD->getAddress());
409a34c753fSRafael Auler       }
410a34c753fSRafael Auler 
411a34c753fSRafael Auler       if (FuncAddrs.empty()) {
412e2007405SAmir Ayupov         if (opts::Verbosity >= 1)
41352cf0711SAmir Ayupov           BC.errs() << "BOLT-WARNING: Reorder functions: can't find function "
414e2007405SAmir Ayupov                     << "for " << Function << "\n";
415e2007405SAmir Ayupov         ++InvalidEntries;
416a34c753fSRafael Auler         continue;
417a34c753fSRafael Auler       }
418a34c753fSRafael Auler 
419a34c753fSRafael Auler       for (const uint64_t FuncAddr : FuncAddrs) {
420a34c753fSRafael Auler         const BinaryData *FuncBD = BC.getBinaryDataAtAddress(FuncAddr);
421a34c753fSRafael Auler         assert(FuncBD);
422a34c753fSRafael Auler 
423a34c753fSRafael Auler         BinaryFunction *BF = BC.getFunctionForSymbol(FuncBD->getSymbol());
424a34c753fSRafael Auler         if (!BF) {
425e2007405SAmir Ayupov           if (opts::Verbosity >= 1)
42652cf0711SAmir Ayupov             BC.errs() << "BOLT-WARNING: Reorder functions: can't find function "
427e2007405SAmir Ayupov                       << "for " << Function << "\n";
428e2007405SAmir Ayupov           ++InvalidEntries;
429a34c753fSRafael Auler           break;
430a34c753fSRafael Auler         }
431f92ab6afSAmir Ayupov         if (!BF->hasValidIndex())
432a34c753fSRafael Auler           BF->setIndex(Index++);
433f92ab6afSAmir Ayupov         else if (opts::Verbosity > 0)
43452cf0711SAmir Ayupov           BC.errs() << "BOLT-WARNING: Duplicate reorder entry for " << Function
435e2007405SAmir Ayupov                     << "\n";
436a34c753fSRafael Auler       }
437a34c753fSRafael Auler     }
438e2007405SAmir Ayupov     if (InvalidEntries)
43952cf0711SAmir Ayupov       BC.errs() << "BOLT-WARNING: Reorder functions: can't find functions for "
440e2007405SAmir Ayupov                 << InvalidEntries << " entries in -function-order list\n";
4412b642926SAmir Ayupov   } break;
4429058503dSspupyrev 
4439058503dSspupyrev   default:
4449058503dSspupyrev     llvm_unreachable("unexpected layout type");
445a34c753fSRafael Auler   }
446a34c753fSRafael Auler 
44752cf0711SAmir Ayupov   reorder(BC, std::move(Clusters), BFs);
448a34c753fSRafael Auler 
449076bd22fSShatianWang   BC.HasFinalizedFunctionOrder = true;
450076bd22fSShatianWang 
451a34c753fSRafael Auler   std::unique_ptr<std::ofstream> FuncsFile;
452a34c753fSRafael Auler   if (!opts::GenerateFunctionOrderFile.empty()) {
45340c2e0faSMaksim Panchenko     FuncsFile = std::make_unique<std::ofstream>(opts::GenerateFunctionOrderFile,
454a34c753fSRafael Auler                                                 std::ios::out);
455a34c753fSRafael Auler     if (!FuncsFile) {
45652cf0711SAmir Ayupov       BC.errs() << "BOLT-ERROR: ordered functions file "
457a34c753fSRafael Auler                 << opts::GenerateFunctionOrderFile << " cannot be opened\n";
458fa7dd491SAmir Ayupov       return createFatalBOLTError("");
459a34c753fSRafael Auler     }
460a34c753fSRafael Auler   }
461a34c753fSRafael Auler 
462a34c753fSRafael Auler   std::unique_ptr<std::ofstream> LinkSectionsFile;
463a34c753fSRafael Auler   if (!opts::LinkSectionsFile.empty()) {
464a34c753fSRafael Auler     LinkSectionsFile =
46540c2e0faSMaksim Panchenko         std::make_unique<std::ofstream>(opts::LinkSectionsFile, std::ios::out);
466a34c753fSRafael Auler     if (!LinkSectionsFile) {
46752cf0711SAmir Ayupov       BC.errs() << "BOLT-ERROR: link sections file " << opts::LinkSectionsFile
46840c2e0faSMaksim Panchenko                 << " cannot be opened\n";
469fa7dd491SAmir Ayupov       return createFatalBOLTError("");
470a34c753fSRafael Auler     }
471a34c753fSRafael Auler   }
472a34c753fSRafael Auler 
473a34c753fSRafael Auler   if (FuncsFile || LinkSectionsFile) {
474a34c753fSRafael Auler     std::vector<BinaryFunction *> SortedFunctions(BFs.size());
47572e5b14fSAmir Ayupov     llvm::transform(llvm::make_second_range(BFs), SortedFunctions.begin(),
47672e5b14fSAmir Ayupov                     [](BinaryFunction &BF) { return &BF; });
477a34c753fSRafael Auler 
478a34c753fSRafael Auler     // Sort functions by index.
4794d2bc0adSEnna1     llvm::stable_sort(SortedFunctions, compareBinaryFunctionByIndex);
480a34c753fSRafael Auler 
481a34c753fSRafael Auler     for (const BinaryFunction *Func : SortedFunctions) {
482a34c753fSRafael Auler       if (!Func->hasValidIndex())
483a34c753fSRafael Auler         break;
484a34c753fSRafael Auler       if (Func->isPLTFunction())
485a34c753fSRafael Auler         continue;
486a34c753fSRafael Auler 
487a34c753fSRafael Auler       if (FuncsFile)
488a34c753fSRafael Auler         *FuncsFile << Func->getOneName().str() << '\n';
489a34c753fSRafael Auler 
490a34c753fSRafael Auler       if (LinkSectionsFile) {
491a34c753fSRafael Auler         const char *Indent = "";
492a34c753fSRafael Auler         std::vector<StringRef> AllNames = Func->getNames();
493d2c87699SAmir Ayupov         llvm::sort(AllNames);
494a34c753fSRafael Auler         for (StringRef Name : AllNames) {
495a34c753fSRafael Auler           const size_t SlashPos = Name.find('/');
496a34c753fSRafael Auler           if (SlashPos != std::string::npos) {
497a34c753fSRafael Auler             // Avoid duplicates for local functions.
498a34c753fSRafael Auler             if (Name.find('/', SlashPos + 1) != std::string::npos)
499a34c753fSRafael Auler               continue;
500a34c753fSRafael Auler             Name = Name.substr(0, SlashPos);
501a34c753fSRafael Auler           }
502a34c753fSRafael Auler           *LinkSectionsFile << Indent << ".text." << Name.str() << '\n';
503a34c753fSRafael Auler           Indent = " ";
504a34c753fSRafael Auler         }
505a34c753fSRafael Auler       }
506a34c753fSRafael Auler     }
507a34c753fSRafael Auler 
508a34c753fSRafael Auler     if (FuncsFile) {
509a34c753fSRafael Auler       FuncsFile->close();
51052cf0711SAmir Ayupov       BC.outs() << "BOLT-INFO: dumped function order to "
511a34c753fSRafael Auler                 << opts::GenerateFunctionOrderFile << '\n';
512a34c753fSRafael Auler     }
513a34c753fSRafael Auler 
514a34c753fSRafael Auler     if (LinkSectionsFile) {
515a34c753fSRafael Auler       LinkSectionsFile->close();
51652cf0711SAmir Ayupov       BC.outs() << "BOLT-INFO: dumped linker section order to "
517a34c753fSRafael Auler                 << opts::LinkSectionsFile << '\n';
518a34c753fSRafael Auler     }
519a34c753fSRafael Auler   }
520a5f3d1a8SAmir Ayupov   return Error::success();
521a34c753fSRafael Auler }
522a34c753fSRafael Auler 
523a34c753fSRafael Auler } // namespace bolt
524a34c753fSRafael Auler } // namespace llvm
525