LLVM  14.0.0git
ImportedFunctionsInliningStatistics.cpp
Go to the documentation of this file.
1 //===-- ImportedFunctionsInliningStats.cpp ----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // Generating inliner statistics for imported functions, mostly useful for
9 // ThinLTO.
10 //===----------------------------------------------------------------------===//
11 
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/IR/Function.h"
15 #include "llvm/IR/Module.h"
17 #include "llvm/Support/Debug.h"
19 #include <algorithm>
20 #include <iomanip>
21 #include <sstream>
22 #include <string>
23 
24 using namespace llvm;
25 
27  "inliner-function-import-stats",
30  "basic statistics"),
32  "printing of statistics for each inlined function")),
33  cl::Hidden, cl::desc("Enable inliner stats for imported functions"));
34 
35 ImportedFunctionsInliningStatistics::InlineGraphNode &
36 ImportedFunctionsInliningStatistics::createInlineGraphNode(const Function &F) {
37 
38  auto &ValueLookup = NodesMap[F.getName()];
39  if (!ValueLookup) {
40  ValueLookup = std::make_unique<InlineGraphNode>();
41  ValueLookup->Imported = F.hasMetadata("thinlto_src_module");
42  }
43  return *ValueLookup;
44 }
45 
47  const Function &Callee) {
48 
49  InlineGraphNode &CallerNode = createInlineGraphNode(Caller);
50  InlineGraphNode &CalleeNode = createInlineGraphNode(Callee);
51  CalleeNode.NumberOfInlines++;
52 
53  if (!CallerNode.Imported && !CalleeNode.Imported) {
54  // Direct inline from not imported callee to not imported caller, so we
55  // don't have to add this to graph. It might be very helpful if you wanna
56  // get the inliner statistics in compile step where there are no imported
57  // functions. In this case the graph would be empty.
58  CalleeNode.NumberOfRealInlines++;
59  return;
60  }
61 
62  CallerNode.InlinedCallees.push_back(&CalleeNode);
63  if (!CallerNode.Imported) {
64  // We could avoid second lookup, but it would make the code ultra ugly.
65  auto It = NodesMap.find(Caller.getName());
66  assert(It != NodesMap.end() && "The node should be already there.");
67  // Save Caller as a starting node for traversal. The string has to be one
68  // from map because Caller can disappear (and function name with it).
69  NonImportedCallers.push_back(It->first());
70  }
71 }
72 
74  ModuleName = M.getName();
75  for (const auto &F : M.functions()) {
76  if (F.isDeclaration())
77  continue;
78  AllFunctions++;
79  ImportedFunctions += int(F.hasMetadata("thinlto_src_module"));
80  }
81 }
82 static std::string getStatString(const char *Msg, int32_t Fraction, int32_t All,
83  const char *PercentageOfMsg,
84  bool LineEnd = true) {
85  double Result = 0;
86  if (All != 0)
87  Result = 100 * static_cast<double>(Fraction) / All;
88 
89  std::stringstream Str;
90  Str << std::setprecision(4) << Msg << ": " << Fraction << " [" << Result
91  << "% of " << PercentageOfMsg << "]";
92  if (LineEnd)
93  Str << "\n";
94  return Str.str();
95 }
96 
98  calculateRealInlines();
99  NonImportedCallers.clear();
100 
101  int32_t InlinedImportedFunctionsCount = 0;
102  int32_t InlinedNotImportedFunctionsCount = 0;
103 
104  int32_t InlinedImportedFunctionsToImportingModuleCount = 0;
105  int32_t InlinedNotImportedFunctionsToImportingModuleCount = 0;
106 
107  const auto SortedNodes = getSortedNodes();
108  std::string Out;
109  Out.reserve(5000);
110  raw_string_ostream Ostream(Out);
111 
112  Ostream << "------- Dumping inliner stats for [" << ModuleName
113  << "] -------\n";
114 
115  if (Verbose)
116  Ostream << "-- List of inlined functions:\n";
117 
118  for (const auto &Node : SortedNodes) {
119  assert(Node->second->NumberOfInlines >= Node->second->NumberOfRealInlines);
120  if (Node->second->NumberOfInlines == 0)
121  continue;
122 
123  if (Node->second->Imported) {
124  InlinedImportedFunctionsCount++;
125  InlinedImportedFunctionsToImportingModuleCount +=
126  int(Node->second->NumberOfRealInlines > 0);
127  } else {
128  InlinedNotImportedFunctionsCount++;
129  InlinedNotImportedFunctionsToImportingModuleCount +=
130  int(Node->second->NumberOfRealInlines > 0);
131  }
132 
133  if (Verbose)
134  Ostream << "Inlined "
135  << (Node->second->Imported ? "imported " : "not imported ")
136  << "function [" << Node->first() << "]"
137  << ": #inlines = " << Node->second->NumberOfInlines
138  << ", #inlines_to_importing_module = "
139  << Node->second->NumberOfRealInlines << "\n";
140  }
141 
142  auto InlinedFunctionsCount =
143  InlinedImportedFunctionsCount + InlinedNotImportedFunctionsCount;
144  auto NotImportedFuncCount = AllFunctions - ImportedFunctions;
145  auto ImportedNotInlinedIntoModule =
146  ImportedFunctions - InlinedImportedFunctionsToImportingModuleCount;
147 
148  Ostream << "-- Summary:\n"
149  << "All functions: " << AllFunctions
150  << ", imported functions: " << ImportedFunctions << "\n"
151  << getStatString("inlined functions", InlinedFunctionsCount,
152  AllFunctions, "all functions")
153  << getStatString("imported functions inlined anywhere",
154  InlinedImportedFunctionsCount, ImportedFunctions,
155  "imported functions")
156  << getStatString("imported functions inlined into importing module",
157  InlinedImportedFunctionsToImportingModuleCount,
158  ImportedFunctions, "imported functions",
159  /*LineEnd=*/false)
160  << getStatString(", remaining", ImportedNotInlinedIntoModule,
161  ImportedFunctions, "imported functions")
162  << getStatString("non-imported functions inlined anywhere",
163  InlinedNotImportedFunctionsCount,
164  NotImportedFuncCount, "non-imported functions")
165  << getStatString(
166  "non-imported functions inlined into importing module",
167  InlinedNotImportedFunctionsToImportingModuleCount,
168  NotImportedFuncCount, "non-imported functions");
169  Ostream.flush();
170  dbgs() << Out;
171 }
172 
173 void ImportedFunctionsInliningStatistics::calculateRealInlines() {
174  // Removing duplicated Callers.
175  llvm::sort(NonImportedCallers);
176  NonImportedCallers.erase(
177  std::unique(NonImportedCallers.begin(), NonImportedCallers.end()),
178  NonImportedCallers.end());
179 
180  for (const auto &Name : NonImportedCallers) {
181  auto &Node = *NodesMap[Name];
182  if (!Node.Visited)
183  dfs(Node);
184  }
185 }
186 
187 void ImportedFunctionsInliningStatistics::dfs(InlineGraphNode &GraphNode) {
188  assert(!GraphNode.Visited);
189  GraphNode.Visited = true;
190  for (auto *const InlinedFunctionNode : GraphNode.InlinedCallees) {
191  InlinedFunctionNode->NumberOfRealInlines++;
192  if (!InlinedFunctionNode->Visited)
193  dfs(*InlinedFunctionNode);
194  }
195 }
196 
197 ImportedFunctionsInliningStatistics::SortedNodesTy
198 ImportedFunctionsInliningStatistics::getSortedNodes() {
199  SortedNodesTy SortedNodes;
200  SortedNodes.reserve(NodesMap.size());
201  for (const NodesMapTy::value_type &Node : NodesMap)
202  SortedNodes.push_back(&Node);
203 
204  llvm::sort(SortedNodes, [&](const SortedNodesTy::value_type &Lhs,
205  const SortedNodesTy::value_type &Rhs) {
206  if (Lhs->second->NumberOfInlines != Rhs->second->NumberOfInlines)
207  return Lhs->second->NumberOfInlines > Rhs->second->NumberOfInlines;
208  if (Lhs->second->NumberOfRealInlines != Rhs->second->NumberOfRealInlines)
209  return Lhs->second->NumberOfRealInlines >
210  Rhs->second->NumberOfRealInlines;
211  return Lhs->first() < Rhs->first();
212  });
213  return SortedNodes;
214 }
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::Function
Definition: Function.h:61
llvm::raw_string_ostream
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:623
llvm::InlinerFunctionImportStatsOpts::Verbose
@ Verbose
llvm::ImportedFunctionsInliningStatistics::setModuleInfo
void setModuleInfo(const Module &M)
Set information like AllFunctions, ImportedFunctions, ModuleName.
Definition: ImportedFunctionsInliningStatistics.cpp:73
llvm::cl::Hidden
@ Hidden
Definition: CommandLine.h:143
llvm::StringMap::end
iterator end()
Definition: StringMap.h:205
Module.h
llvm::StringMap< std::unique_ptr< InlineGraphNode > >::value_type
StringMapEntry< std::unique_ptr< InlineGraphNode > > value_type
Definition: StringMap.h:198
STLExtras.h
llvm::StringMap::find
iterator find(StringRef Key)
Definition: StringMap.h:218
F
#define F(x, y, z)
Definition: MD5.cpp:56
InlinerFunctionImportStats
cl::opt< InlinerFunctionImportStatsOpts > InlinerFunctionImportStats("inliner-function-import-stats", cl::init(InlinerFunctionImportStatsOpts::No), cl::values(clEnumValN(InlinerFunctionImportStatsOpts::Basic, "basic", "basic statistics"), clEnumValN(InlinerFunctionImportStatsOpts::Verbose, "verbose", "printing of statistics for each inlined function")), cl::Hidden, cl::desc("Enable inliner stats for imported functions"))
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
CommandLine.h
ImportedFunctionsInliningStatistics.h
llvm::InlinerFunctionImportStatsOpts::No
@ No
int
Clang compiles this i1 i64 store i64 i64 store i64 i64 store i64 i64 store i64 align Which gets codegen d xmm0 movaps rbp movaps rbp movaps rbp movaps rbp rbp rbp rbp rbp It would be better to have movq s of instead of the movaps s LLVM produces ret int
Definition: README.txt:536
llvm::raw_ostream::flush
void flush()
Definition: raw_ostream.h:186
llvm::cl::opt
Definition: CommandLine.h:1422
llvm::cl::values
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
Definition: CommandLine.h:699
llvm::cl::init
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
llvm::StringMapImpl::size
unsigned size() const
Definition: StringMap.h:93
if
if(llvm_vc STREQUAL "") set(fake_version_inc "$
Definition: CMakeLists.txt:14
clEnumValN
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
Definition: CommandLine.h:674
getStatString
static std::string getStatString(const char *Msg, int32_t Fraction, int32_t All, const char *PercentageOfMsg, bool LineEnd=true)
Definition: ImportedFunctionsInliningStatistics.cpp:82
Callee
amdgpu Simplify well known AMD library false FunctionCallee Callee
Definition: AMDGPULibCalls.cpp:206
llvm::ImportedFunctionsInliningStatistics::recordInline
void recordInline(const Function &Caller, const Function &Callee)
Record inline of.
Definition: ImportedFunctionsInliningStatistics.cpp:46
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:52
Function.h
llvm::sort
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1488
llvm::unique
auto unique(Range &&R, Predicate P)
Definition: STLExtras.h:1700
llvm::InlinerFunctionImportStatsOpts::Basic
@ Basic
llvm::cl::desc
Definition: CommandLine.h:414
raw_ostream.h
Debug.h
llvm::ImportedFunctionsInliningStatistics::dump
void dump(bool Verbose)
Dump stats computed with InlinerStatistics class.
Definition: ImportedFunctionsInliningStatistics.cpp:97