blob: ed018bb73107486280c1852a7003a4f237bb399a [file] [log] [blame]
Piotr Padlewski84abc742016-07-29 00:27:16 +00001//===-- ImportedFunctionsInliningStats.cpp ----------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// Generating inliner statistics for imported functions, mostly useful for
10// ThinLTO.
11//===----------------------------------------------------------------------===//
12
13#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/IR/Function.h"
16#include "llvm/IR/Module.h"
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/raw_ostream.h"
19#include <algorithm>
20#include <iomanip>
21#include <sstream>
22using namespace llvm;
23
24ImportedFunctionsInliningStatistics::InlineGraphNode &
25ImportedFunctionsInliningStatistics::createInlineGraphNode(const Function &F) {
26
27 auto &ValueLookup = NodesMap[F.getName()];
28 if (!ValueLookup) {
29 ValueLookup = llvm::make_unique<InlineGraphNode>();
30 ValueLookup->Imported = F.getMetadata("thinlto_src_module") != nullptr;
31 }
32 return *ValueLookup;
33}
34
35void ImportedFunctionsInliningStatistics::recordInline(const Function &Caller,
36 const Function &Callee) {
37
38 InlineGraphNode &CallerNode = createInlineGraphNode(Caller);
39 InlineGraphNode &CalleeNode = createInlineGraphNode(Callee);
40 CalleeNode.NumberOfInlines++;
41
42 if (!CallerNode.Imported && !CalleeNode.Imported) {
43 // Direct inline from not imported callee to not imported caller, so we
44 // don't have to add this to graph. It might be very helpful if you wanna
45 // get the inliner statistics in compile step where there are no imported
46 // functions. In this case the graph would be empty.
47 CalleeNode.NumberOfRealInlines++;
48 return;
49 }
50
51 CallerNode.InlinedCallees.push_back(&CalleeNode);
Piotr Padlewski47509f62016-08-02 22:18:47 +000052 if (!CallerNode.Imported) {
53 // We could avoid second lookup, but it would make the code ultra ugly.
54 auto It = NodesMap.find(Caller.getName());
55 assert(It != NodesMap.end() && "The node should be already there.");
56 // Save Caller as a starting node for traversal. The string has to be one
57 // from map because Caller can disappear (and function name with it).
58 NonImportedCallers.push_back(It->first());
59 }
Piotr Padlewski84abc742016-07-29 00:27:16 +000060}
61
62void ImportedFunctionsInliningStatistics::setModuleInfo(const Module &M) {
63 ModuleName = M.getName();
64 for (const auto &F : M.functions()) {
65 AllFunctions++;
66 ImportedFunctions += int(F.getMetadata("thinlto_src_module") != nullptr);
67 }
68}
69static std::string getStatString(const char *Msg, int32_t Fraction, int32_t All,
70 const char *PercentageOfMsg,
71 bool LineEnd = true) {
72 double Result = 0;
73 if (All != 0)
74 Result = 100 * static_cast<double>(Fraction) / All;
75
76 std::stringstream Str;
77 Str << std::setprecision(4) << Msg << ": " << Fraction << " [" << Result
78 << "% of " << PercentageOfMsg << "]";
79 if (LineEnd)
80 Str << "\n";
81 return Str.str();
82}
83
84void ImportedFunctionsInliningStatistics::dump(const bool Verbose) {
85 calculateRealInlines();
86 NonImportedCallers.clear();
87
88 int32_t InlinedImportedFunctionsCount = 0;
89 int32_t InlinedNotImportedFunctionsCount = 0;
90
91 int32_t InlinedImportedFunctionsToImportingModuleCount = 0;
92 int32_t InlinedNotImportedFunctionsToImportingModuleCount = 0;
93
94 const auto SortedNodes = getSortedNodes();
95 std::string Out;
96 Out.reserve(5000);
97 raw_string_ostream Ostream(Out);
98
99 Ostream << "------- Dumping inliner stats for [" << ModuleName
100 << "] -------\n";
101
102 if (Verbose)
103 Ostream << "-- List of inlined functions:\n";
104
105 for (const auto &Node : SortedNodes) {
Piotr Padlewski47509f62016-08-02 22:18:47 +0000106 assert(Node->second->NumberOfInlines >= Node->second->NumberOfRealInlines);
107 if (Node->second->NumberOfInlines == 0)
Piotr Padlewski84abc742016-07-29 00:27:16 +0000108 continue;
109
Piotr Padlewski47509f62016-08-02 22:18:47 +0000110 if (Node->second->Imported) {
Piotr Padlewski84abc742016-07-29 00:27:16 +0000111 InlinedImportedFunctionsCount++;
112 InlinedImportedFunctionsToImportingModuleCount +=
Piotr Padlewski47509f62016-08-02 22:18:47 +0000113 int(Node->second->NumberOfRealInlines > 0);
Piotr Padlewski84abc742016-07-29 00:27:16 +0000114 } else {
115 InlinedNotImportedFunctionsCount++;
116 InlinedNotImportedFunctionsToImportingModuleCount +=
Piotr Padlewski47509f62016-08-02 22:18:47 +0000117 int(Node->second->NumberOfRealInlines > 0);
Piotr Padlewski84abc742016-07-29 00:27:16 +0000118 }
119
120 if (Verbose)
121 Ostream << "Inlined "
Piotr Padlewski47509f62016-08-02 22:18:47 +0000122 << (Node->second->Imported ? "imported " : "not imported ")
123 << "function [" << Node->first() << "]"
124 << ": #inlines = " << Node->second->NumberOfInlines
Piotr Padlewski84abc742016-07-29 00:27:16 +0000125 << ", #inlines_to_importing_module = "
Piotr Padlewski47509f62016-08-02 22:18:47 +0000126 << Node->second->NumberOfRealInlines << "\n";
Piotr Padlewski84abc742016-07-29 00:27:16 +0000127 }
128
129 auto InlinedFunctionsCount =
130 InlinedImportedFunctionsCount + InlinedNotImportedFunctionsCount;
131 auto NotImportedFuncCount = AllFunctions - ImportedFunctions;
132 auto ImportedNotInlinedIntoModule =
133 ImportedFunctions - InlinedImportedFunctionsToImportingModuleCount;
134
135 Ostream << "-- Summary:\n"
136 << "All functions: " << AllFunctions
137 << ", imported functions: " << ImportedFunctions << "\n"
138 << getStatString("inlined functions", InlinedFunctionsCount,
139 AllFunctions, "all functions")
140 << getStatString("imported functions inlined anywhere",
141 InlinedImportedFunctionsCount, ImportedFunctions,
142 "imported functions")
143 << getStatString("imported functions inlined into importing module",
144 InlinedImportedFunctionsToImportingModuleCount,
145 ImportedFunctions, "imported functions",
146 /*LineEnd=*/false)
147 << getStatString(", remaining", ImportedNotInlinedIntoModule,
148 ImportedFunctions, "imported functions")
149 << getStatString("non-imported functions inlined anywhere",
150 InlinedNotImportedFunctionsCount,
151 NotImportedFuncCount, "non-imported functions")
152 << getStatString(
153 "non-imported functions inlined into importing module",
154 InlinedNotImportedFunctionsToImportingModuleCount,
155 NotImportedFuncCount, "non-imported functions");
156 Ostream.flush();
157 dbgs() << Out;
158}
159
160void ImportedFunctionsInliningStatistics::calculateRealInlines() {
161 // Removing duplicated Callers.
162 std::sort(NonImportedCallers.begin(), NonImportedCallers.end());
163 NonImportedCallers.erase(
164 std::unique(NonImportedCallers.begin(), NonImportedCallers.end()),
165 NonImportedCallers.end());
166
167 for (const auto &Name : NonImportedCallers) {
168 auto &Node = *NodesMap[Name];
169 if (!Node.Visited)
170 dfs(Node);
171 }
172}
173
174void ImportedFunctionsInliningStatistics::dfs(InlineGraphNode &GraphNode) {
175 assert(!GraphNode.Visited);
176 GraphNode.Visited = true;
177 for (auto *const InlinedFunctionNode : GraphNode.InlinedCallees) {
178 InlinedFunctionNode->NumberOfRealInlines++;
179 if (!InlinedFunctionNode->Visited)
180 dfs(*InlinedFunctionNode);
181 }
182}
183
184ImportedFunctionsInliningStatistics::SortedNodesTy
185ImportedFunctionsInliningStatistics::getSortedNodes() {
186 SortedNodesTy SortedNodes;
187 SortedNodes.reserve(NodesMap.size());
Piotr Padlewski47509f62016-08-02 22:18:47 +0000188 for (const NodesMapTy::value_type& Node : NodesMap)
189 SortedNodes.push_back(&Node);
Piotr Padlewski84abc742016-07-29 00:27:16 +0000190
191 std::sort(
192 SortedNodes.begin(), SortedNodes.end(),
193 [&](const SortedNodesTy::value_type &Lhs,
194 const SortedNodesTy::value_type &Rhs) {
Piotr Padlewski47509f62016-08-02 22:18:47 +0000195 if (Lhs->second->NumberOfInlines != Rhs->second->NumberOfInlines)
196 return Lhs->second->NumberOfInlines > Rhs->second->NumberOfInlines;
197 if (Lhs->second->NumberOfRealInlines != Rhs->second->NumberOfRealInlines)
198 return Lhs->second->NumberOfRealInlines >
199 Rhs->second->NumberOfRealInlines;
200 return Lhs->first() < Rhs->first();
Piotr Padlewski84abc742016-07-29 00:27:16 +0000201 });
202 return SortedNodes;
203}