1b842725cSMichael J. Spencer //===- CallGraphSort.cpp --------------------------------------------------===//
2b842725cSMichael J. Spencer //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b842725cSMichael J. Spencer //
7b842725cSMichael J. Spencer //===----------------------------------------------------------------------===//
8b842725cSMichael J. Spencer ///
9b842725cSMichael J. Spencer /// Implementation of Call-Chain Clustering from: Optimizing Function Placement
10b842725cSMichael J. Spencer /// for Large-Scale Data-Center Applications
11b842725cSMichael J. Spencer /// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf
12b842725cSMichael J. Spencer ///
13b842725cSMichael J. Spencer /// The goal of this algorithm is to improve runtime performance of the final
14b842725cSMichael J. Spencer /// executable by arranging code sections such that page table and i-cache
15b842725cSMichael J. Spencer /// misses are minimized.
16b842725cSMichael J. Spencer ///
17b842725cSMichael J. Spencer /// Definitions:
18b842725cSMichael J. Spencer /// * Cluster
19b842725cSMichael J. Spencer ///   * An ordered list of input sections which are layed out as a unit. At the
20b842725cSMichael J. Spencer ///     beginning of the algorithm each input section has its own cluster and
21b842725cSMichael J. Spencer ///     the weight of the cluster is the sum of the weight of all incomming
22b842725cSMichael J. Spencer ///     edges.
23b842725cSMichael J. Spencer /// * Call-Chain Clustering (C³) Heuristic
24b842725cSMichael J. Spencer ///   * Defines when and how clusters are combined. Pick the highest weighted
25b842725cSMichael J. Spencer ///     input section then add it to its most likely predecessor if it wouldn't
26b842725cSMichael J. Spencer ///     penalize it too much.
27b842725cSMichael J. Spencer /// * Density
28b842725cSMichael J. Spencer ///   * The weight of the cluster divided by the size of the cluster. This is a
29b842725cSMichael J. Spencer ///     proxy for the ammount of execution time spent per byte of the cluster.
30b842725cSMichael J. Spencer ///
31b842725cSMichael J. Spencer /// It does so given a call graph profile by the following:
32b842725cSMichael J. Spencer /// * Build a weighted call graph from the call graph profile
33b842725cSMichael J. Spencer /// * Sort input sections by weight
34b842725cSMichael J. Spencer /// * For each input section starting with the highest weight
35b842725cSMichael J. Spencer ///   * Find its most likely predecessor cluster
36b842725cSMichael J. Spencer ///   * Check if the combined cluster would be too large, or would have too low
37b842725cSMichael J. Spencer ///     a density.
38b842725cSMichael J. Spencer ///   * If not, then combine the clusters.
39b842725cSMichael J. Spencer /// * Sort non-empty clusters by density
40b842725cSMichael J. Spencer ///
41b842725cSMichael J. Spencer //===----------------------------------------------------------------------===//
42b842725cSMichael J. Spencer 
43b842725cSMichael J. Spencer #include "CallGraphSort.h"
44b842725cSMichael J. Spencer #include "OutputSections.h"
45b842725cSMichael J. Spencer #include "SymbolTable.h"
46b842725cSMichael J. Spencer #include "Symbols.h"
47b842725cSMichael J. Spencer 
48b842725cSMichael J. Spencer using namespace llvm;
49b842725cSMichael J. Spencer using namespace lld;
50b842725cSMichael J. Spencer using namespace lld::elf;
51b842725cSMichael J. Spencer 
52b842725cSMichael J. Spencer namespace {
53b842725cSMichael J. Spencer struct Edge {
54b842725cSMichael J. Spencer   int From;
55b842725cSMichael J. Spencer   uint64_t Weight;
56b842725cSMichael J. Spencer };
57b842725cSMichael J. Spencer 
58b842725cSMichael J. Spencer struct Cluster {
593d354081SRui Ueyama   Cluster(int Sec, size_t S) : Sections{Sec}, Size(S) {}
60b842725cSMichael J. Spencer 
61b842725cSMichael J. Spencer   double getDensity() const {
62b842725cSMichael J. Spencer     if (Size == 0)
63b842725cSMichael J. Spencer       return 0;
64b842725cSMichael J. Spencer     return double(Weight) / double(Size);
65b842725cSMichael J. Spencer   }
66b842725cSMichael J. Spencer 
67b842725cSMichael J. Spencer   std::vector<int> Sections;
68b842725cSMichael J. Spencer   size_t Size = 0;
69b842725cSMichael J. Spencer   uint64_t Weight = 0;
70b842725cSMichael J. Spencer   uint64_t InitialWeight = 0;
71f0eedbceSGeorge Rimar   Edge BestPred = {-1, 0};
72b842725cSMichael J. Spencer };
73b842725cSMichael J. Spencer 
74b842725cSMichael J. Spencer class CallGraphSort {
75b842725cSMichael J. Spencer public:
76b842725cSMichael J. Spencer   CallGraphSort();
77b842725cSMichael J. Spencer 
78b842725cSMichael J. Spencer   DenseMap<const InputSectionBase *, int> run();
79b842725cSMichael J. Spencer 
80b842725cSMichael J. Spencer private:
81b842725cSMichael J. Spencer   std::vector<Cluster> Clusters;
82b842725cSMichael J. Spencer   std::vector<const InputSectionBase *> Sections;
83b842725cSMichael J. Spencer 
84b842725cSMichael J. Spencer   void groupClusters();
85b842725cSMichael J. Spencer };
86b842725cSMichael J. Spencer 
87b842725cSMichael J. Spencer // Maximum ammount the combined cluster density can be worse than the original
88b842725cSMichael J. Spencer // cluster to consider merging.
89b842725cSMichael J. Spencer constexpr int MAX_DENSITY_DEGRADATION = 8;
90b842725cSMichael J. Spencer 
91b842725cSMichael J. Spencer // Maximum cluster size in bytes.
92b842725cSMichael J. Spencer constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
93b842725cSMichael J. Spencer } // end anonymous namespace
94b842725cSMichael J. Spencer 
95*68b9f45fSRui Ueyama using SectionPair =
96*68b9f45fSRui Ueyama     std::pair<const InputSectionBase *, const InputSectionBase *>;
973d354081SRui Ueyama 
98b842725cSMichael J. Spencer // Take the edge list in Config->CallGraphProfile, resolve symbol names to
99b842725cSMichael J. Spencer // Symbols, and generate a graph between InputSections with the provided
100b842725cSMichael J. Spencer // weights.
101b842725cSMichael J. Spencer CallGraphSort::CallGraphSort() {
1023d354081SRui Ueyama   MapVector<SectionPair, uint64_t> &Profile = Config->CallGraphProfile;
103b842725cSMichael J. Spencer   DenseMap<const InputSectionBase *, int> SecToCluster;
104b842725cSMichael J. Spencer 
105b842725cSMichael J. Spencer   auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
106b842725cSMichael J. Spencer     auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size()));
107b842725cSMichael J. Spencer     if (Res.second) {
108b842725cSMichael J. Spencer       Sections.push_back(IS);
109b842725cSMichael J. Spencer       Clusters.emplace_back(Clusters.size(), IS->getSize());
110b842725cSMichael J. Spencer     }
111b842725cSMichael J. Spencer     return Res.first->second;
112b842725cSMichael J. Spencer   };
113b842725cSMichael J. Spencer 
114b842725cSMichael J. Spencer   // Create the graph.
1153d354081SRui Ueyama   for (std::pair<SectionPair, uint64_t> &C : Profile) {
116b842725cSMichael J. Spencer     const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl);
117b842725cSMichael J. Spencer     const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl);
118b842725cSMichael J. Spencer     uint64_t Weight = C.second;
119b842725cSMichael J. Spencer 
120b842725cSMichael J. Spencer     // Ignore edges between input sections belonging to different output
121b842725cSMichael J. Spencer     // sections.  This is done because otherwise we would end up with clusters
122b842725cSMichael J. Spencer     // containing input sections that can't actually be placed adjacently in the
123b842725cSMichael J. Spencer     // output.  This messes with the cluster size and density calculations.  We
124b842725cSMichael J. Spencer     // would also end up moving input sections in other output sections without
125b842725cSMichael J. Spencer     // moving them closer to what calls them.
126b842725cSMichael J. Spencer     if (FromSB->getOutputSection() != ToSB->getOutputSection())
127b842725cSMichael J. Spencer       continue;
128b842725cSMichael J. Spencer 
129b842725cSMichael J. Spencer     int From = GetOrCreateNode(FromSB);
130b842725cSMichael J. Spencer     int To = GetOrCreateNode(ToSB);
131b842725cSMichael J. Spencer 
132b842725cSMichael J. Spencer     Clusters[To].Weight += Weight;
133b842725cSMichael J. Spencer 
134b842725cSMichael J. Spencer     if (From == To)
135b842725cSMichael J. Spencer       continue;
136b842725cSMichael J. Spencer 
137f0eedbceSGeorge Rimar     // Remember the best edge.
138f0eedbceSGeorge Rimar     Cluster &ToC = Clusters[To];
139f0eedbceSGeorge Rimar     if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) {
140f0eedbceSGeorge Rimar       ToC.BestPred.From = From;
141f0eedbceSGeorge Rimar       ToC.BestPred.Weight = Weight;
142f0eedbceSGeorge Rimar     }
143b842725cSMichael J. Spencer   }
144b842725cSMichael J. Spencer   for (Cluster &C : Clusters)
145b842725cSMichael J. Spencer     C.InitialWeight = C.Weight;
146b842725cSMichael J. Spencer }
147b842725cSMichael J. Spencer 
148b842725cSMichael J. Spencer // It's bad to merge clusters which would degrade the density too much.
149b842725cSMichael J. Spencer static bool isNewDensityBad(Cluster &A, Cluster &B) {
150b842725cSMichael J. Spencer   double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size);
1513d354081SRui Ueyama   return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION;
152b842725cSMichael J. Spencer }
153b842725cSMichael J. Spencer 
154b842725cSMichael J. Spencer static void mergeClusters(Cluster &Into, Cluster &From) {
155b842725cSMichael J. Spencer   Into.Sections.insert(Into.Sections.end(), From.Sections.begin(),
156b842725cSMichael J. Spencer                        From.Sections.end());
157b842725cSMichael J. Spencer   Into.Size += From.Size;
158b842725cSMichael J. Spencer   Into.Weight += From.Weight;
159b842725cSMichael J. Spencer   From.Sections.clear();
160b842725cSMichael J. Spencer   From.Size = 0;
161b842725cSMichael J. Spencer   From.Weight = 0;
162b842725cSMichael J. Spencer }
163b842725cSMichael J. Spencer 
164b842725cSMichael J. Spencer // Group InputSections into clusters using the Call-Chain Clustering heuristic
165b842725cSMichael J. Spencer // then sort the clusters by density.
166b842725cSMichael J. Spencer void CallGraphSort::groupClusters() {
167b842725cSMichael J. Spencer   std::vector<int> SortedSecs(Clusters.size());
168b842725cSMichael J. Spencer   std::vector<Cluster *> SecToCluster(Clusters.size());
169b842725cSMichael J. Spencer 
170a5cf8da1SGeorge Rimar   for (size_t I = 0; I < Clusters.size(); ++I) {
171a5cf8da1SGeorge Rimar     SortedSecs[I] = I;
172a5cf8da1SGeorge Rimar     SecToCluster[I] = &Clusters[I];
173b842725cSMichael J. Spencer   }
174b842725cSMichael J. Spencer 
175b842725cSMichael J. Spencer   std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
176b842725cSMichael J. Spencer     return Clusters[B].getDensity() < Clusters[A].getDensity();
177b842725cSMichael J. Spencer   });
178b842725cSMichael J. Spencer 
179b842725cSMichael J. Spencer   for (int SI : SortedSecs) {
180b842725cSMichael J. Spencer     // Clusters[SI] is the same as SecToClusters[SI] here because it has not
181b842725cSMichael J. Spencer     // been merged into another cluster yet.
182b842725cSMichael J. Spencer     Cluster &C = Clusters[SI];
183b842725cSMichael J. Spencer 
184f0eedbceSGeorge Rimar     // Don't consider merging if the edge is unlikely.
185f0eedbceSGeorge Rimar     if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight)
186b842725cSMichael J. Spencer       continue;
187b842725cSMichael J. Spencer 
188f0eedbceSGeorge Rimar     Cluster *PredC = SecToCluster[C.BestPred.From];
189b842725cSMichael J. Spencer     if (PredC == &C)
190b842725cSMichael J. Spencer       continue;
191b842725cSMichael J. Spencer 
192b842725cSMichael J. Spencer     if (C.Size + PredC->Size > MAX_CLUSTER_SIZE)
193b842725cSMichael J. Spencer       continue;
194b842725cSMichael J. Spencer 
195b842725cSMichael J. Spencer     if (isNewDensityBad(*PredC, C))
196b842725cSMichael J. Spencer       continue;
197b842725cSMichael J. Spencer 
198b842725cSMichael J. Spencer     // NOTE: Consider using a disjoint-set to track section -> cluster mapping
199b842725cSMichael J. Spencer     // if this is ever slow.
200b842725cSMichael J. Spencer     for (int SI : C.Sections)
201b842725cSMichael J. Spencer       SecToCluster[SI] = PredC;
202b842725cSMichael J. Spencer 
203b842725cSMichael J. Spencer     mergeClusters(*PredC, C);
204b842725cSMichael J. Spencer   }
205b842725cSMichael J. Spencer 
206b842725cSMichael J. Spencer   // Remove empty or dead nodes. Invalidates all cluster indices.
20797df22f1SGeorge Rimar   llvm::erase_if(Clusters, [](const Cluster &C) {
208b842725cSMichael J. Spencer     return C.Size == 0 || C.Sections.empty();
20997df22f1SGeorge Rimar   });
210b842725cSMichael J. Spencer 
211b842725cSMichael J. Spencer   // Sort by density.
212de83cbf3SGeorge Rimar   std::stable_sort(Clusters.begin(), Clusters.end(),
213b842725cSMichael J. Spencer                    [](const Cluster &A, const Cluster &B) {
214b842725cSMichael J. Spencer                      return A.getDensity() > B.getDensity();
215b842725cSMichael J. Spencer                    });
216b842725cSMichael J. Spencer }
217b842725cSMichael J. Spencer 
218b842725cSMichael J. Spencer DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
219b842725cSMichael J. Spencer   groupClusters();
220b842725cSMichael J. Spencer 
221b842725cSMichael J. Spencer   // Generate order.
2223d354081SRui Ueyama   DenseMap<const InputSectionBase *, int> OrderMap;
223b842725cSMichael J. Spencer   ssize_t CurOrder = 1;
224b842725cSMichael J. Spencer 
225b842725cSMichael J. Spencer   for (const Cluster &C : Clusters)
226b842725cSMichael J. Spencer     for (int SecIndex : C.Sections)
227b842725cSMichael J. Spencer       OrderMap[Sections[SecIndex]] = CurOrder++;
228b842725cSMichael J. Spencer 
229432030e8SRui Ueyama   if (!Config->PrintSymbolOrder.empty()) {
230432030e8SRui Ueyama     std::error_code EC;
231432030e8SRui Ueyama     raw_fd_ostream OS(Config->PrintSymbolOrder, EC, sys::fs::F_None);
232432030e8SRui Ueyama     if (EC) {
233432030e8SRui Ueyama       error("cannot open " + Config->PrintSymbolOrder + ": " + EC.message());
234432030e8SRui Ueyama       return OrderMap;
235432030e8SRui Ueyama     }
236432030e8SRui Ueyama 
237432030e8SRui Ueyama     // Print the symbols ordered by C3, in the order of increasing CurOrder
238432030e8SRui Ueyama     // Instead of sorting all the OrderMap, just repeat the loops above.
239432030e8SRui Ueyama     for (const Cluster &C : Clusters)
240432030e8SRui Ueyama       for (int SecIndex : C.Sections)
241432030e8SRui Ueyama         // Search all the symbols in the file of the section
242432030e8SRui Ueyama         // and find out a Defined symbol with name that is within the section.
243432030e8SRui Ueyama         for (Symbol *Sym: Sections[SecIndex]->File->getSymbols())
244432030e8SRui Ueyama           if (!Sym->isSection()) // Filter out section-type symbols here.
245432030e8SRui Ueyama             if (auto *D = dyn_cast<Defined>(Sym))
246432030e8SRui Ueyama               if (Sections[SecIndex] == D->Section)
247432030e8SRui Ueyama                 OS << Sym->getName() << "\n";
248432030e8SRui Ueyama   }
249432030e8SRui Ueyama 
250b842725cSMichael J. Spencer   return OrderMap;
251b842725cSMichael J. Spencer }
252b842725cSMichael J. Spencer 
253b842725cSMichael J. Spencer // Sort sections by the profile data provided by -callgraph-profile-file
254b842725cSMichael J. Spencer //
255b842725cSMichael J. Spencer // This first builds a call graph based on the profile data then merges sections
256b842725cSMichael J. Spencer // according to the C³ huristic. All clusters are then sorted by a density
257b842725cSMichael J. Spencer // metric to further improve locality.
258b842725cSMichael J. Spencer DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() {
259b842725cSMichael J. Spencer   return CallGraphSort().run();
260b842725cSMichael J. Spencer }
261