<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 28, 2016 at 5:27 PM, Piotr Padlewski via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Author: prazek<br>
Date: Thu Jul 28 19:27:16 2016<br>
New Revision: 277089<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=277089&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=277089&view=rev</a><br>
Log:<br>
Added ThinLTO inlining statistics<br>
<br>
Summary:<br>
copypasta doc of ImportedFunctionsInliningStatistics class<br>
\brief Calculate and dump ThinLTO specific inliner stats.<br>
The main statistics are:<br>
(1) Number of inlined imported functions,<br>
(2) Number of imported functions inlined into importing module (indirect),<br>
(3) Number of non imported functions inlined into importing module<br>
(indirect).<br>
The difference between first and the second is that first stat counts<br>
all performed inlines on imported functions, but the second one only the<br>
functions that have been eventually inlined to a function in the importing<br>
module (by a chain of inlines). Because llvm uses bottom-up inliner, it is<br>
possible to e.g. import function `A`, `B` and then inline `B` to `A`,<br>
and after this `A` might be too big to be inlined into some other function<br>
that calls it. It calculates this statistic by building graph, where<br>
the nodes are functions, and edges are performed inlines and then by marking<br>
the edges starting from not imported function.<br>
<br>
If `Verbose` is set to true, then it also dumps statistics<br>
per each inlined function, sorted by the greatest inlines count like<br>
- number of performed inlines<br>
- number of performed inlines to importing module<br>
<br>
Reviewers: eraman, tejohnson, mehdi_amini<br>
<br>
Subscribers: mehdi_amini, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D22491" rel="noreferrer" target="_blank">https://reviews.llvm.org/D22491</a><br>
<br>
Added:<br>
llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h<br>
llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp<br>
llvm/trunk/test/Transforms/Inline/inline_stats.ll<br>
Modified:<br>
llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h<br>
llvm/trunk/lib/Transforms/IPO/Inliner.cpp<br>
llvm/trunk/lib/Transforms/Utils/CMakeLists.txt<br>
<br>
Modified: llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h?rev=277089&r1=277088&r2=277089&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h?rev=277089&r1=277088&r2=277089&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h (original)<br>
+++ llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h Thu Jul 28 19:27:16 2016<br>
@@ -20,6 +20,7 @@<br>
#include "llvm/Analysis/CallGraphSCCPass.h"<br>
#include "llvm/Analysis/InlineCost.h"<br>
#include "llvm/Analysis/TargetTransformInfo.h"<br>
+#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"<br>
<br>
namespace llvm {<br>
class AssumptionCacheTracker;<br>
@@ -41,6 +42,8 @@ struct Inliner : public CallGraphSCCPass<br>
/// always explicitly call the implementation here.<br>
void getAnalysisUsage(AnalysisUsage &Info) const override;<br>
<br>
+ bool doInitialization(CallGraph &CG) override;<br>
+<br>
// Main run interface method, this implements the interface required by the<br>
// Pass class.<br>
bool runOnSCC(CallGraphSCC &SCC) override;<br>
@@ -78,6 +81,7 @@ private:<br>
protected:<br>
AssumptionCacheTracker *ACT;<br>
ProfileSummaryInfo *PSI;<br>
+ ImportedFunctionsInliningStatistics ImportedFunctionsStats;<br>
};<br>
<br>
} // End llvm namespace<br>
<br>
Added: llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h?rev=277089&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h?rev=277089&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h (added)<br>
+++ llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h Thu Jul 28 19:27:16 2016<br>
@@ -0,0 +1,112 @@<br>
+//===-- ImportedFunctionsInliningStats.h ------------------------*- C++ -*-===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+// Generating inliner statistics for imported functions, mostly useful for<br>
+// ThinLTO.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_TRANSFORMS_UTILS_IMPORTEDFUNCTIONSINLININGSTATISTICS_H<br>
+#define LLVM_TRANSFORMS_UTILS_IMPORTEDFUNCTIONSINLININGSTATISTICS_H<br>
+<br>
+#include "llvm/ADT/SmallVector.h"<br>
+#include "llvm/ADT/StringRef.h"<br>
+#include <string><br>
+#include <unordered_map><br>
+#include <vector><br>
+<br>
+namespace llvm {<br>
+class Module;<br>
+class Function;<br>
+/// \brief Calculate and dump ThinLTO specific inliner stats.<br>
+/// The main statistics are:<br>
+/// (1) Number of inlined imported functions,<br>
+/// (2) Number of imported functions inlined into importing module (indirect),<br>
+/// (3) Number of non imported functions inlined into importing module<br>
+/// (indirect).<br>
+/// The difference between first and the second is that first stat counts<br>
+/// all performed inlines on imported functions, but the second one only the<br>
+/// functions that have been eventually inlined to a function in the importing<br>
+/// module (by a chain of inlines). Because llvm uses bottom-up inliner, it is<br>
+/// possible to e.g. import function `A`, `B` and then inline `B` to `A`,<br>
+/// and after this `A` might be too big to be inlined into some other function<br>
+/// that calls it. It calculates this statistic by building graph, where<br>
+/// the nodes are functions, and edges are performed inlines and then by marking<br>
+/// the edges starting from not imported function.<br>
+///<br>
+/// If `Verbose` is set to true, then it also dumps statistics<br>
+/// per each inlined function, sorted by the greatest inlines count like<br>
+/// - number of performed inlines<br>
+/// - number of performed inlines to importing module<br>
+class ImportedFunctionsInliningStatistics {<br>
+private:<br>
+ /// InlineGraphNode represents node in graph of inlined functions.<br>
+ struct InlineGraphNode {<br>
+ // Default-constructible and movable.<br>
+ InlineGraphNode() = default;<br>
+ InlineGraphNode(InlineGraphNode &&) = default;<br>
+ InlineGraphNode &operator=(InlineGraphNode &&) = default;<br>
+ InlineGraphNode(const InlineGraphNode &) = delete;<br>
+ InlineGraphNode &operator=(const InlineGraphNode &) = delete;<br>
+<br>
+ llvm::SmallVector<InlineGraphNode *, 8> InlinedCallees;<br>
+ /// Incremented every direct inline.<br>
+ int32_t NumberOfInlines = 0;<br>
+ /// Number of inlines into non imported function (possibly indirect via<br>
+ /// intermediate inlines). Computed based on graph search.<br>
+ int32_t NumberOfRealInlines = 0;<br>
+ bool Imported = false;<br>
+ bool Visited = false;<br>
+ };<br>
+<br>
+public:<br>
+ ImportedFunctionsInliningStatistics() = default;<br>
+ ImportedFunctionsInliningStatistics(<br>
+ const ImportedFunctionsInliningStatistics &) = delete;<br>
+<br>
+ /// Set information like AllFunctions, ImportedFunctions, ModuleName.<br>
+ void setModuleInfo(const Module &M);<br>
+ /// Record inline of @param Callee to @param Caller for statistis.<br>
+ void recordInline(const Function &Caller, const Function &Callee);<br>
+ /// Dump stats computed with InlinerStatistics class.<br>
+ /// If @param Verbose is true then separate statistics for every inlined<br>
+ /// function will be printed.<br>
+ void dump(bool Verbose);<br>
+<br>
+private:<br>
+ /// Creates new Node in NodeMap and sets attributes, or returns existed one.<br>
+ InlineGraphNode &createInlineGraphNode(const Function &);<br>
+ void calculateRealInlines();<br>
+ void dfs(InlineGraphNode &GraphNode);<br>
+<br>
+ using NodesMapTy =<br>
+ std::unordered_map<std::string, std::unique_ptr<InlineGraphNode>>;<br></blockquote><div><br></div><div>Since you are now using a map keyed by the function name use a StringMap which is a more efficient way of mapping string keys.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+ using SortedNodesTy =<br>
+ std::vector<std::pair<std::string, std::unique_ptr<InlineGraphNode>>>;<br></blockquote><div><br></div><div>Once the NodesMap is a StringMap, I suppose this vector can hold a StringMapEntry instead of a std::pair. But then you can't clear the NodesMap, note on that below.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+ /// Clears NodesMap and returns vector of elements sorted by<br>
+ /// (-NumberOfInlines, -NumberOfRealInlines, FunctionName).<br>
+ SortedNodesTy getSortedNodes();<br>
+<br>
+private:<br>
+ /// FIXME: Change map keys to std::string/StringRef to avoid using pointers<br>
+ /// to dead functions.<br></blockquote><div><br></div><div>Remove this comment as you implemented that in the committed version.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+ /// This map manage life of all InlineGraphNodes. Unique pointer to<br>
+ /// InlineGraphNode used since the node pointers are also saved in the<br>
+ /// InlinedCallees vector. If it would store InlineGraphNode instead then the<br>
+ /// address of the node would not be invariant.<br>
+ NodesMapTy NodesMap;<br>
+ /// Non external functions that have some other function inlined inside.<br>
+ /// Should not dereference pointers because Functions might be deleted.<br>
+ std::vector<std::string> NonImportedCallers;<br></blockquote><div><br></div><div>Once the NodesMap is a StringMap, this vector can use the StringRef for the key owned by the map (StringMap makes a copy when you insert), instead of another copy of the string.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">+ int AllFunctions = 0; </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">+ int ImportedFunctions = 0;<br>
+ StringRef ModuleName;<br>
+};<br>
+<br>
+} // llvm<br>
+<br>
+#endif // LLVM_TRANSFORMS_UTILS_IMPORTEDFUNCTIONSINLININGSTATISTICS_H<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/Inliner.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Inliner.cpp?rev=277089&r1=277088&r2=277089&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Inliner.cpp?rev=277089&r1=277088&r2=277089&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/Inliner.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/Inliner.cpp Thu Jul 28 19:27:16 2016<br>
@@ -47,6 +47,24 @@ STATISTIC(NumMergedAllocas, "Number of a<br>
// if those would be more profitable and blocked inline steps.<br>
STATISTIC(NumCallerCallersAnalyzed, "Number of caller-callers analyzed");<br>
<br>
+namespace {<br>
+enum class InlinerFunctionImportStatsOpts {<br>
+ No = 0,<br>
+ Basic = 1,<br>
+ Verbose = 2,<br>
+};<br>
+<br>
+cl::opt<InlinerFunctionImportStatsOpts> InlinerFunctionImportStats(<br>
+ "inliner-function-import-stats",<br>
+ cl::init(InlinerFunctionImportStatsOpts::No),<br>
+ cl::values(clEnumValN(InlinerFunctionImportStatsOpts::Basic, "basic",<br>
+ "basic statistics"),<br>
+ clEnumValN(InlinerFunctionImportStatsOpts::Verbose, "verbose",<br>
+ "printing of statistics for each inlined function"),<br>
+ clEnumValEnd),<br>
+ cl::Hidden, cl::desc("Enable inliner stats for imported functions"));<br>
+} // namespace<br>
+<br>
Inliner::Inliner(char &ID) : CallGraphSCCPass(ID), InsertLifetime(true) {}<br>
<br>
Inliner::Inliner(char &ID, bool InsertLifetime)<br>
@@ -75,11 +93,11 @@ InlinedArrayAllocasTy;<br>
/// available from other functions inlined into the caller. If we are able to<br>
/// inline this call site we attempt to reuse already available allocas or add<br>
/// any new allocas to the set if not possible.<br>
-static bool<br>
-InlineCallIfPossible(CallSite CS, InlineFunctionInfo &IFI,<br>
- InlinedArrayAllocasTy &InlinedArrayAllocas,<br>
- int InlineHistory, bool InsertLifetime,<br>
- std::function<AAResults &(Function &)> &AARGetter) {<br>
+static bool InlineCallIfPossible(<br>
+ CallSite CS, InlineFunctionInfo &IFI,<br>
+ InlinedArrayAllocasTy &InlinedArrayAllocas, int InlineHistory,<br>
+ bool InsertLifetime, std::function<AAResults &(Function &)> &AARGetter,<br>
+ ImportedFunctionsInliningStatistics &ImportedFunctionsStats) {<br>
Function *Callee = CS.getCalledFunction();<br>
Function *Caller = CS.getCaller();<br>
<br>
@@ -90,6 +108,9 @@ InlineCallIfPossible(CallSite CS, Inline<br>
if (!InlineFunction(CS, IFI, &AAR, InsertLifetime))<br>
return false;<br>
<br>
+ if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)<br>
+ ImportedFunctionsStats.recordInline(*Caller, *Callee);<br>
+<br>
AttributeFuncs::mergeAttributesForInlining(*Caller, *Callee);<br>
<br>
// Look at all of the allocas that we inlined through this call site. If we<br>
@@ -371,10 +392,15 @@ static bool InlineHistoryIncludes(Functi<br>
return false;<br>
}<br>
<br>
+bool Inliner::doInitialization(CallGraph &CG) {<br>
+ if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)<br>
+ ImportedFunctionsStats.setModuleInfo(CG.getModule());<br>
+ return false; // No changes to CallGraph.<br>
+}<br>
+<br>
bool Inliner::runOnSCC(CallGraphSCC &SCC) {<br>
if (skipSCC(SCC))<br>
return false;<br>
-<br>
return inlineCalls(SCC);<br>
}<br>
<br>
@@ -384,7 +410,8 @@ inlineCallsImpl(CallGraphSCC &SCC, CallG<br>
ProfileSummaryInfo *PSI, TargetLibraryInfo &TLI,<br>
bool InsertLifetime,<br>
std::function<InlineCost(CallSite CS)> GetInlineCost,<br>
- std::function<AAResults &(Function &)> AARGetter) {<br>
+ std::function<AAResults &(Function &)> AARGetter,<br>
+ ImportedFunctionsInliningStatistics &ImportedFunctionsStats) {<br>
SmallPtrSet<Function*, 8> SCCFunctions;<br>
DEBUG(dbgs() << "Inliner visiting SCC:");<br>
for (CallGraphNode *Node : SCC) {<br>
@@ -502,7 +529,8 @@ inlineCallsImpl(CallGraphSCC &SCC, CallG<br>
<br>
// Attempt to inline the function.<br>
if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas,<br>
- InlineHistoryID, InsertLifetime, AARGetter)) {<br>
+ InlineHistoryID, InsertLifetime, AARGetter,<br>
+ ImportedFunctionsStats)) {<br>
emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller, DLoc,<br>
Twine(Callee->getName() +<br>
" will not be inlined into " +<br>
@@ -591,12 +619,15 @@ bool Inliner::inlineCalls(CallGraphSCC &<br>
};<br>
return inlineCallsImpl(SCC, CG, GetAssumptionCache, PSI, TLI, InsertLifetime,<br>
[this](CallSite CS) { return getInlineCost(CS); },<br>
- AARGetter);<br>
+ AARGetter, ImportedFunctionsStats);<br>
}<br>
<br>
/// Remove now-dead linkonce functions at the end of<br>
/// processing to avoid breaking the SCC traversal.<br>
bool Inliner::doFinalization(CallGraph &CG) {<br>
+ if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)<br>
+ ImportedFunctionsStats.dump(InlinerFunctionImportStats ==<br>
+ InlinerFunctionImportStatsOpts::Verbose);<br>
return removeDeadFunctions(CG);<br>
}<br>
<br>
<br>
Modified: llvm/trunk/lib/Transforms/Utils/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CMakeLists.txt?rev=277089&r1=277088&r2=277089&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CMakeLists.txt?rev=277089&r1=277088&r2=277089&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Utils/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Transforms/Utils/CMakeLists.txt Thu Jul 28 19:27:16 2016<br>
@@ -16,6 +16,7 @@ add_llvm_library(LLVMTransformUtils<br>
FunctionImportUtils.cpp<br>
GlobalStatus.cpp<br>
InlineFunction.cpp<br>
+ ImportedFunctionsInliningStatistics.cpp<br>
InstructionNamer.cpp<br>
IntegerDivision.cpp<br>
LCSSA.cpp<br>
<br>
Added: llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp?rev=277089&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp?rev=277089&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp (added)<br>
+++ llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp Thu Jul 28 19:27:16 2016<br>
@@ -0,0 +1,201 @@<br>
+//===-- ImportedFunctionsInliningStats.cpp ----------------------*- C++ -*-===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+// Generating inliner statistics for imported functions, mostly useful for<br>
+// ThinLTO.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"<br>
+#include "llvm/ADT/STLExtras.h"<br>
+#include "llvm/IR/Function.h"<br>
+#include "llvm/IR/Module.h"<br>
+#include "llvm/Support/Debug.h"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+#include <algorithm><br>
+#include <iomanip><br>
+#include <sstream><br>
+using namespace llvm;<br>
+<br>
+ImportedFunctionsInliningStatistics::InlineGraphNode &<br>
+ImportedFunctionsInliningStatistics::createInlineGraphNode(const Function &F) {<br>
+<br>
+ auto &ValueLookup = NodesMap[F.getName()];<br>
+ if (!ValueLookup) {<br>
+ ValueLookup = llvm::make_unique<InlineGraphNode>();<br>
+ ValueLookup->Imported = F.getMetadata("thinlto_src_module") != nullptr;<br>
+ }<br>
+ return *ValueLookup;<br>
+}<br>
+<br>
+void ImportedFunctionsInliningStatistics::recordInline(const Function &Caller,<br>
+ const Function &Callee) {<br>
+<br>
+ InlineGraphNode &CallerNode = createInlineGraphNode(Caller);<br>
+ InlineGraphNode &CalleeNode = createInlineGraphNode(Callee);<br>
+ CalleeNode.NumberOfInlines++;<br>
+<br>
+ if (!CallerNode.Imported && !CalleeNode.Imported) {<br>
+ // Direct inline from not imported callee to not imported caller, so we<br>
+ // don't have to add this to graph. It might be very helpful if you wanna<br>
+ // get the inliner statistics in compile step where there are no imported<br>
+ // functions. In this case the graph would be empty.<br>
+ CalleeNode.NumberOfRealInlines++;<br>
+ return;<br>
+ }<br>
+<br>
+ CallerNode.InlinedCallees.push_back(&CalleeNode);<br>
+ if (!CallerNode.Imported)<br>
+ // Save Caller as a starting node for traversal.<br>
+ NonImportedCallers.push_back(Caller.getName());<br>
+}<br>
+<br>
+void ImportedFunctionsInliningStatistics::setModuleInfo(const Module &M) {<br>
+ ModuleName = M.getName();<br>
+ for (const auto &F : M.functions()) {<br>
+ AllFunctions++;<br>
+ ImportedFunctions += int(F.getMetadata("thinlto_src_module") != nullptr);<br>
+ }<br>
+}<br>
+static std::string getStatString(const char *Msg, int32_t Fraction, int32_t All,<br>
+ const char *PercentageOfMsg,<br>
+ bool LineEnd = true) {<br>
+ double Result = 0;<br>
+ if (All != 0)<br>
+ Result = 100 * static_cast<double>(Fraction) / All;<br>
+<br>
+ std::stringstream Str;<br>
+ Str << std::setprecision(4) << Msg << ": " << Fraction << " [" << Result<br>
+ << "% of " << PercentageOfMsg << "]";<br>
+ if (LineEnd)<br>
+ Str << "\n";<br>
+ return Str.str();<br>
+}<br>
+<br>
+void ImportedFunctionsInliningStatistics::dump(const bool Verbose) {<br>
+ calculateRealInlines();<br>
+ NonImportedCallers.clear();<br>
+<br>
+ int32_t InlinedImportedFunctionsCount = 0;<br>
+ int32_t InlinedNotImportedFunctionsCount = 0;<br>
+<br>
+ int32_t InlinedImportedFunctionsToImportingModuleCount = 0;<br>
+ int32_t InlinedNotImportedFunctionsToImportingModuleCount = 0;<br>
+<br>
+ const auto SortedNodes = getSortedNodes();<br>
+ std::string Out;<br>
+ Out.reserve(5000);<br>
+ raw_string_ostream Ostream(Out);<br>
+<br>
+ Ostream << "------- Dumping inliner stats for [" << ModuleName<br>
+ << "] -------\n";<br>
+<br>
+ if (Verbose)<br>
+ Ostream << "-- List of inlined functions:\n";<br>
+<br>
+ for (const auto &Node : SortedNodes) {<br>
+ assert(Node.second->NumberOfInlines >= Node.second->NumberOfRealInlines);<br>
+ if (Node.second->NumberOfInlines == 0)<br>
+ continue;<br>
+<br>
+ if (Node.second->Imported) {<br>
+ InlinedImportedFunctionsCount++;<br>
+ InlinedImportedFunctionsToImportingModuleCount +=<br>
+ int(Node.second->NumberOfRealInlines > 0);<br>
+ } else {<br>
+ InlinedNotImportedFunctionsCount++;<br>
+ InlinedNotImportedFunctionsToImportingModuleCount +=<br>
+ int(Node.second->NumberOfRealInlines > 0);<br>
+ }<br>
+<br>
+ if (Verbose)<br>
+ Ostream << "Inlined "<br>
+ << (Node.second->Imported ? "imported " : "not imported ")<br>
+ << "function [" << Node.first << "]"<br>
+ << ": #inlines = " << Node.second->NumberOfInlines<br>
+ << ", #inlines_to_importing_module = "<br>
+ << Node.second->NumberOfRealInlines << "\n";<br>
+ }<br>
+<br>
+ auto InlinedFunctionsCount =<br>
+ InlinedImportedFunctionsCount + InlinedNotImportedFunctionsCount;<br>
+ auto NotImportedFuncCount = AllFunctions - ImportedFunctions;<br>
+ auto ImportedNotInlinedIntoModule =<br>
+ ImportedFunctions - InlinedImportedFunctionsToImportingModuleCount;<br>
+<br>
+ Ostream << "-- Summary:\n"<br>
+ << "All functions: " << AllFunctions<br>
+ << ", imported functions: " << ImportedFunctions << "\n"<br>
+ << getStatString("inlined functions", InlinedFunctionsCount,<br>
+ AllFunctions, "all functions")<br>
+ << getStatString("imported functions inlined anywhere",<br>
+ InlinedImportedFunctionsCount, ImportedFunctions,<br>
+ "imported functions")<br>
+ << getStatString("imported functions inlined into importing module",<br>
+ InlinedImportedFunctionsToImportingModuleCount,<br>
+ ImportedFunctions, "imported functions",<br>
+ /*LineEnd=*/false)<br>
+ << getStatString(", remaining", ImportedNotInlinedIntoModule,<br>
+ ImportedFunctions, "imported functions")<br>
+ << getStatString("non-imported functions inlined anywhere",<br>
+ InlinedNotImportedFunctionsCount,<br>
+ NotImportedFuncCount, "non-imported functions")<br>
+ << getStatString(<br>
+ "non-imported functions inlined into importing module",<br>
+ InlinedNotImportedFunctionsToImportingModuleCount,<br>
+ NotImportedFuncCount, "non-imported functions");<br>
+ Ostream.flush();<br>
+ dbgs() << Out;<br>
+}<br>
+<br>
+void ImportedFunctionsInliningStatistics::calculateRealInlines() {<br>
+ // Removing duplicated Callers.<br>
+ std::sort(NonImportedCallers.begin(), NonImportedCallers.end());<br>
+ NonImportedCallers.erase(<br>
+ std::unique(NonImportedCallers.begin(), NonImportedCallers.end()),<br>
+ NonImportedCallers.end());<br>
+<br>
+ for (const auto &Name : NonImportedCallers) {<br>
+ auto &Node = *NodesMap[Name];<br>
+ if (!Node.Visited)<br>
+ dfs(Node);<br>
+ }<br>
+}<br>
+<br>
+void ImportedFunctionsInliningStatistics::dfs(InlineGraphNode &GraphNode) {<br>
+ assert(!GraphNode.Visited);<br>
+ GraphNode.Visited = true;<br>
+ for (auto *const InlinedFunctionNode : GraphNode.InlinedCallees) {<br>
+ InlinedFunctionNode->NumberOfRealInlines++;<br>
+ if (!InlinedFunctionNode->Visited)<br>
+ dfs(*InlinedFunctionNode);<br>
+ }<br>
+}<br>
+<br>
+ImportedFunctionsInliningStatistics::SortedNodesTy<br>
+ImportedFunctionsInliningStatistics::getSortedNodes() {<br>
+ SortedNodesTy SortedNodes;<br>
+ SortedNodes.reserve(NodesMap.size());<br>
+<br>
+ for (auto &&Node : NodesMap)<br>
+ SortedNodes.emplace_back(Node.first, std::move(Node.second));<br>
+<br>
+ NodesMap.clear(); // We don't want to leave nullptrs.<br></blockquote><div><br></div><div>What nullptrs are you concerned about leaving? The unique_ptrs will be destroyed when the ImportedFunctionsInliningStatistics is destroyed. If you change NodesMap to StringMap and use StringMapEntry in SortedNodes you will need to avoid the clear here.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+<br>
+ std::sort(<br>
+ SortedNodes.begin(), SortedNodes.end(),<br>
+ [&](const SortedNodesTy::value_type &Lhs,<br>
+ const SortedNodesTy::value_type &Rhs) {<br>
+ if (Lhs.second->NumberOfInlines != Rhs.second->NumberOfInlines)<br>
+ return Lhs.second->NumberOfInlines > Rhs.second->NumberOfInlines;<br>
+ if (Lhs.second->NumberOfRealInlines != Rhs.second->NumberOfRealInlines)<br>
+ return Lhs.second->NumberOfRealInlines ><br>
+ Rhs.second->NumberOfRealInlines;<br>
+ return Lhs.first < Rhs.first;<br>
+ });<br>
+ return SortedNodes;<br>
+}<br>
<br>
Added: llvm/trunk/test/Transforms/Inline/inline_stats.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/inline_stats.ll?rev=277089&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/inline_stats.ll?rev=277089&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Transforms/Inline/inline_stats.ll (added)<br>
+++ llvm/trunk/test/Transforms/Inline/inline_stats.ll Thu Jul 28 19:27:16 2016<br>
@@ -0,0 +1,87 @@<br>
+; RUN: opt -S -inline -inliner-function-import-stats=basic < %s 2>&1 | FileCheck %s -check-prefix=CHECK-BASIC -check-prefix=CHECK<br>
+; RUN: opt -S -inline -inliner-function-import-stats=verbose < %s 2>&1 | FileCheck %s -check-prefix="CHECK-VERBOSE" -check-prefix=CHECK<br>
+<br>
+; CHECK: ------- Dumping inliner stats for [<stdin>] -------<br>
+; CHECK-BASIC-NOT: -- List of inlined functions:<br>
+; CHECK-BASIC-NOT: -- Inlined not imported function<br>
+; CHECK-VERBOSE: -- List of inlined functions:<br>
+; CHECK-VERBOSE: Inlined not imported function [internal2]: #inlines = 6, #inlines_to_importing_module = 2<br>
+; CHECK-VERBOSE: Inlined imported function [external2]: #inlines = 4, #inlines_to_importing_module = 1<br>
+; CHECK-VERBOSE: Inlined imported function [external1]: #inlines = 3, #inlines_to_importing_module = 2<br>
+; CHECK-VERBOSE: Inlined imported function [external5]: #inlines = 1, #inlines_to_importing_module = 1<br>
+; CHECK-VERBOSE: Inlined imported function [external3]: #inlines = 1, #inlines_to_importing_module = 0<br>
+<br>
+; CHECK: -- Summary:<br>
+; CHECK: All functions: 10, imported functions: 7<br>
+; CHECK: inlined functions: 5 [50% of all functions]<br>
+; CHECK: imported functions inlined anywhere: 4 [57.14% of imported functions]<br>
+; CHECK: imported functions inlined into importing module: 3 [42.86% of imported functions], remaining: 4 [57.14% of imported functions]<br>
+; CHECK: non-imported functions inlined anywhere: 1 [33.33% of non-imported functions]<br>
+; CHECK: non-imported functions inlined into importing module: 1 [33.33% of non-imported functions]<br>
+<br>
+define void @internal() {<br>
+ call fastcc void @external1()<br>
+ call fastcc void @internal2()<br>
+ call coldcc void @external_big()<br>
+ ret void<br>
+}<br>
+<br>
+define void @internal2() alwaysinline {<br>
+ ret void<br>
+}<br>
+<br>
+define void @internal3() {<br>
+ call fastcc void @external1()<br>
+ call fastcc void @external5()<br>
+ ret void<br>
+}<br>
+<br>
+define void @external1() alwaysinline !thinlto_src_module !0 {<br>
+ call fastcc void @internal2()<br>
+ call fastcc void @external2();<br>
+ ret void<br>
+}<br>
+<br>
+define void @external2() alwaysinline !thinlto_src_module !1 {<br>
+ ret void<br>
+}<br>
+<br>
+define void @external3() alwaysinline !thinlto_src_module !1 {<br>
+ ret void<br>
+}<br>
+<br>
+define void @external4() !thinlto_src_module !1 {<br>
+ call fastcc void @external1()<br>
+ call fastcc void @external2()<br>
+ ret void<br>
+}<br>
+<br>
+define void @external5() !thinlto_src_module !1 {<br>
+ ret void<br>
+}<br>
+<br>
+; Assume big piece of code here. This function won't be inlined, so all the<br>
+; inlined function it will have won't affect real inlines.<br>
+define void @external_big() noinline !thinlto_src_module !1 {<br>
+; CHECK-NOT: call fastcc void @internal2()<br>
+ call fastcc void @internal2()<br>
+ call fastcc void @internal2()<br>
+ call fastcc void @internal2()<br>
+ call fastcc void @internal2()<br>
+<br>
+; CHECK-NOT: call fastcc void @external2()<br>
+ call fastcc void @external2()<br>
+ call fastcc void @external2()<br>
+; CHECK-NOT: call fastcc void @external3()<br>
+ call fastcc void @external3()<br>
+ ret void<br>
+}<br>
+<br>
+; It should not be imported, but it should not break anything.<br>
+define void @external_notcalled() !thinlto_src_module !0 {<br>
+ call void @external_notcalled()<br>
+ ret void<br>
+}<br>
+<br>
+!0 = !{!"file.cc"}<br>
+!1 = !{!"other.cc"}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"><span style="font-family:times;font-size:medium"><table cellspacing="0" cellpadding="0"><tbody><tr style="color:rgb(85,85,85);font-family:sans-serif;font-size:small"><td nowrap style="border-top-style:solid;border-top-color:rgb(213,15,37);border-top-width:2px">Teresa Johnson |</td><td nowrap style="border-top-style:solid;border-top-color:rgb(51,105,232);border-top-width:2px"> Software Engineer |</td><td nowrap style="border-top-style:solid;border-top-color:rgb(0,153,57);border-top-width:2px"> <a href="mailto:tejohnson@google.com" target="_blank">tejohnson@google.com</a> |</td><td nowrap style="border-top-style:solid;border-top-color:rgb(238,178,17);border-top-width:2px"> 408-460-2413</td></tr></tbody></table></span></div>
</div></div>