[llvm] r277089 - Added ThinLTO inlining statistics
Mike Aizatsky via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 29 11:30:42 PDT 2016
Piotr,
I think you broke the build:
http://lab.llvm.org:8011/builders/sanitizer-windows/builds/26495
C:\PROGRA~2\MICROS~1.0\VC\bin\AMD64_~1\cl.exe /nologo /TP
-DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE
-D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE
-D_CRT_SECURE_NO_WARNINGS -D_DEBUG_POINTER_IMPL="" -D_HAS_EXCEPTIONS=0
-D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-Ilib\Transforms\Utils
-IC:\b\slave\sanitizer-windows\llvm\lib\Transforms\Utils -Iinclude
-IC:\b\slave\sanitizer-windows\llvm\include /DWIN32 /D_WINDOWS /W4
-wd4141 -wd4146 -wd4180 -wd4244 -wd4258 -wd4267 -wd4291 -wd4345
-wd4351 -wd4355 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624
-wd4722 -wd4800 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510
-wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611
-wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4324 -w14062
-we4238 /Zc:inline /Oi /Zc:rvalueCast /MD /O2 /Ob2 -UNDEBUG /EHs-c-
/GR- /showIncludes
/Folib\Transforms\Utils\CMakeFiles\LLVMTransformUtils.dir\ImportedFunctionsInliningStatistics.cpp.obj
/Fdlib\Transforms\Utils\CMakeFiles\LLVMTransformUtils.dir\ /FS -c
C:\b\slave\sanitizer-windows\llvm\lib\Transforms\Utils\ImportedFunctionsInliningStatistics.cpp
C:\b\slave\sanitizer-windows\llvm\include\llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h(51)
: error C2610: 'llvm::ImportedFunctionsInliningStatistics::InlineGraphNode::InlineGraphNode(llvm::ImportedFunctionsInliningStatistics::InlineGraphNode
&&)' : is not a special member function which can be defaulted
C:\b\slave\sanitizer-windows\llvm\include\llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h(52)
: error C2610: 'llvm::ImportedFunctionsInliningStatistics::InlineGraphNode
&llvm::ImportedFunctionsInliningStatistics::InlineGraphNode::operator
=(llvm::ImportedFunctionsInliningStatistics::InlineGraphNode &&)' : is
not a special member function which can be defaulted
On Fri, Jul 29, 2016 at 6:31 AM Teresa Johnson via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> On Thu, Jul 28, 2016 at 5:27 PM, Piotr Padlewski via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: prazek
>> Date: Thu Jul 28 19:27:16 2016
>> New Revision: 277089
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=277089&view=rev
>> Log:
>> Added ThinLTO inlining statistics
>>
>> Summary:
>> copypasta doc of ImportedFunctionsInliningStatistics class
>> \brief Calculate and dump ThinLTO specific inliner stats.
>> The main statistics are:
>> (1) Number of inlined imported functions,
>> (2) Number of imported functions inlined into importing module
>> (indirect),
>> (3) Number of non imported functions inlined into importing module
>> (indirect).
>> The difference between first and the second is that first stat counts
>> all performed inlines on imported functions, but the second one only the
>> functions that have been eventually inlined to a function in the
>> importing
>> module (by a chain of inlines). Because llvm uses bottom-up inliner, it
>> is
>> possible to e.g. import function `A`, `B` and then inline `B` to `A`,
>> and after this `A` might be too big to be inlined into some other
>> function
>> that calls it. It calculates this statistic by building graph, where
>> the nodes are functions, and edges are performed inlines and then by
>> marking
>> the edges starting from not imported function.
>>
>> If `Verbose` is set to true, then it also dumps statistics
>> per each inlined function, sorted by the greatest inlines count like
>> - number of performed inlines
>> - number of performed inlines to importing module
>>
>> Reviewers: eraman, tejohnson, mehdi_amini
>>
>> Subscribers: mehdi_amini, llvm-commits
>>
>> Differential Revision: https://reviews.llvm.org/D22491
>>
>> Added:
>>
>> llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h
>>
>> llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp
>> llvm/trunk/test/Transforms/Inline/inline_stats.ll
>> Modified:
>> llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h
>> llvm/trunk/lib/Transforms/IPO/Inliner.cpp
>> llvm/trunk/lib/Transforms/Utils/CMakeLists.txt
>>
>> Modified: llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h?rev=277089&r1=277088&r2=277089&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h (original)
>> +++ llvm/trunk/include/llvm/Transforms/IPO/InlinerPass.h Thu Jul 28
>> 19:27:16 2016
>> @@ -20,6 +20,7 @@
>> #include "llvm/Analysis/CallGraphSCCPass.h"
>> #include "llvm/Analysis/InlineCost.h"
>> #include "llvm/Analysis/TargetTransformInfo.h"
>> +#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"
>>
>> namespace llvm {
>> class AssumptionCacheTracker;
>> @@ -41,6 +42,8 @@ struct Inliner : public CallGraphSCCPass
>> /// always explicitly call the implementation here.
>> void getAnalysisUsage(AnalysisUsage &Info) const override;
>>
>> + bool doInitialization(CallGraph &CG) override;
>> +
>> // Main run interface method, this implements the interface required
>> by the
>> // Pass class.
>> bool runOnSCC(CallGraphSCC &SCC) override;
>> @@ -78,6 +81,7 @@ private:
>> protected:
>> AssumptionCacheTracker *ACT;
>> ProfileSummaryInfo *PSI;
>> + ImportedFunctionsInliningStatistics ImportedFunctionsStats;
>> };
>>
>> } // End llvm namespace
>>
>> Added:
>> llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h?rev=277089&view=auto
>>
>> ==============================================================================
>> ---
>> llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h
>> (added)
>> +++
>> llvm/trunk/include/llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h
>> Thu Jul 28 19:27:16 2016
>> @@ -0,0 +1,112 @@
>> +//===-- ImportedFunctionsInliningStats.h ------------------------*- C++
>> -*-===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +// Generating inliner statistics for imported functions, mostly useful
>> for
>> +// ThinLTO.
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_TRANSFORMS_UTILS_IMPORTEDFUNCTIONSINLININGSTATISTICS_H
>> +#define LLVM_TRANSFORMS_UTILS_IMPORTEDFUNCTIONSINLININGSTATISTICS_H
>> +
>> +#include "llvm/ADT/SmallVector.h"
>> +#include "llvm/ADT/StringRef.h"
>> +#include <string>
>> +#include <unordered_map>
>> +#include <vector>
>> +
>> +namespace llvm {
>> +class Module;
>> +class Function;
>> +/// \brief Calculate and dump ThinLTO specific inliner stats.
>> +/// The main statistics are:
>> +/// (1) Number of inlined imported functions,
>> +/// (2) Number of imported functions inlined into importing module
>> (indirect),
>> +/// (3) Number of non imported functions inlined into importing module
>> +/// (indirect).
>> +/// The difference between first and the second is that first stat counts
>> +/// all performed inlines on imported functions, but the second one only
>> the
>> +/// functions that have been eventually inlined to a function in the
>> importing
>> +/// module (by a chain of inlines). Because llvm uses bottom-up inliner,
>> it is
>> +/// possible to e.g. import function `A`, `B` and then inline `B` to `A`,
>> +/// and after this `A` might be too big to be inlined into some other
>> function
>> +/// that calls it. It calculates this statistic by building graph, where
>> +/// the nodes are functions, and edges are performed inlines and then by
>> marking
>> +/// the edges starting from not imported function.
>> +///
>> +/// If `Verbose` is set to true, then it also dumps statistics
>> +/// per each inlined function, sorted by the greatest inlines count like
>> +/// - number of performed inlines
>> +/// - number of performed inlines to importing module
>> +class ImportedFunctionsInliningStatistics {
>> +private:
>> + /// InlineGraphNode represents node in graph of inlined functions.
>> + struct InlineGraphNode {
>> + // Default-constructible and movable.
>> + InlineGraphNode() = default;
>> + InlineGraphNode(InlineGraphNode &&) = default;
>> + InlineGraphNode &operator=(InlineGraphNode &&) = default;
>> + InlineGraphNode(const InlineGraphNode &) = delete;
>> + InlineGraphNode &operator=(const InlineGraphNode &) = delete;
>> +
>> + llvm::SmallVector<InlineGraphNode *, 8> InlinedCallees;
>> + /// Incremented every direct inline.
>> + int32_t NumberOfInlines = 0;
>> + /// Number of inlines into non imported function (possibly indirect
>> via
>> + /// intermediate inlines). Computed based on graph search.
>> + int32_t NumberOfRealInlines = 0;
>> + bool Imported = false;
>> + bool Visited = false;
>> + };
>> +
>> +public:
>> + ImportedFunctionsInliningStatistics() = default;
>> + ImportedFunctionsInliningStatistics(
>> + const ImportedFunctionsInliningStatistics &) = delete;
>> +
>> + /// Set information like AllFunctions, ImportedFunctions, ModuleName.
>> + void setModuleInfo(const Module &M);
>> + /// Record inline of @param Callee to @param Caller for statistis.
>> + void recordInline(const Function &Caller, const Function &Callee);
>> + /// Dump stats computed with InlinerStatistics class.
>> + /// If @param Verbose is true then separate statistics for every
>> inlined
>> + /// function will be printed.
>> + void dump(bool Verbose);
>> +
>> +private:
>> + /// Creates new Node in NodeMap and sets attributes, or returns
>> existed one.
>> + InlineGraphNode &createInlineGraphNode(const Function &);
>> + void calculateRealInlines();
>> + void dfs(InlineGraphNode &GraphNode);
>> +
>> + using NodesMapTy =
>> + std::unordered_map<std::string, std::unique_ptr<InlineGraphNode>>;
>>
>
> 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.
>
>
>> + using SortedNodesTy =
>> + std::vector<std::pair<std::string,
>> std::unique_ptr<InlineGraphNode>>>;
>>
>
> 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.
>
> + /// Clears NodesMap and returns vector of elements sorted by
>> + /// (-NumberOfInlines, -NumberOfRealInlines, FunctionName).
>> + SortedNodesTy getSortedNodes();
>> +
>> +private:
>> + /// FIXME: Change map keys to std::string/StringRef to avoid using
>> pointers
>> + /// to dead functions.
>>
>
> Remove this comment as you implemented that in the committed version.
>
>
>> + /// This map manage life of all InlineGraphNodes. Unique pointer to
>> + /// InlineGraphNode used since the node pointers are also saved in the
>> + /// InlinedCallees vector. If it would store InlineGraphNode instead
>> then the
>> + /// address of the node would not be invariant.
>> + NodesMapTy NodesMap;
>> + /// Non external functions that have some other function inlined
>> inside.
>> + /// Should not dereference pointers because Functions might be deleted.
>> + std::vector<std::string> NonImportedCallers;
>>
>
> 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.
>
> + int AllFunctions = 0;
>
> + int ImportedFunctions = 0;
>> + StringRef ModuleName;
>> +};
>> +
>> +} // llvm
>> +
>> +#endif // LLVM_TRANSFORMS_UTILS_IMPORTEDFUNCTIONSINLININGSTATISTICS_H
>>
>> Modified: llvm/trunk/lib/Transforms/IPO/Inliner.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/Inliner.cpp?rev=277089&r1=277088&r2=277089&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Transforms/IPO/Inliner.cpp (original)
>> +++ llvm/trunk/lib/Transforms/IPO/Inliner.cpp Thu Jul 28 19:27:16 2016
>> @@ -47,6 +47,24 @@ STATISTIC(NumMergedAllocas, "Number of a
>> // if those would be more profitable and blocked inline steps.
>> STATISTIC(NumCallerCallersAnalyzed, "Number of caller-callers analyzed");
>>
>> +namespace {
>> +enum class InlinerFunctionImportStatsOpts {
>> + No = 0,
>> + Basic = 1,
>> + Verbose = 2,
>> +};
>> +
>> +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"),
>> + clEnumValEnd),
>> + cl::Hidden, cl::desc("Enable inliner stats for imported functions"));
>> +} // namespace
>> +
>> Inliner::Inliner(char &ID) : CallGraphSCCPass(ID), InsertLifetime(true)
>> {}
>>
>> Inliner::Inliner(char &ID, bool InsertLifetime)
>> @@ -75,11 +93,11 @@ InlinedArrayAllocasTy;
>> /// available from other functions inlined into the caller. If we are
>> able to
>> /// inline this call site we attempt to reuse already available allocas
>> or add
>> /// any new allocas to the set if not possible.
>> -static bool
>> -InlineCallIfPossible(CallSite CS, InlineFunctionInfo &IFI,
>> - InlinedArrayAllocasTy &InlinedArrayAllocas,
>> - int InlineHistory, bool InsertLifetime,
>> - std::function<AAResults &(Function &)> &AARGetter) {
>> +static bool InlineCallIfPossible(
>> + CallSite CS, InlineFunctionInfo &IFI,
>> + InlinedArrayAllocasTy &InlinedArrayAllocas, int InlineHistory,
>> + bool InsertLifetime, std::function<AAResults &(Function &)>
>> &AARGetter,
>> + ImportedFunctionsInliningStatistics &ImportedFunctionsStats) {
>> Function *Callee = CS.getCalledFunction();
>> Function *Caller = CS.getCaller();
>>
>> @@ -90,6 +108,9 @@ InlineCallIfPossible(CallSite CS, Inline
>> if (!InlineFunction(CS, IFI, &AAR, InsertLifetime))
>> return false;
>>
>> + if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
>> + ImportedFunctionsStats.recordInline(*Caller, *Callee);
>> +
>> AttributeFuncs::mergeAttributesForInlining(*Caller, *Callee);
>>
>> // Look at all of the allocas that we inlined through this call site.
>> If we
>> @@ -371,10 +392,15 @@ static bool InlineHistoryIncludes(Functi
>> return false;
>> }
>>
>> +bool Inliner::doInitialization(CallGraph &CG) {
>> + if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
>> + ImportedFunctionsStats.setModuleInfo(CG.getModule());
>> + return false; // No changes to CallGraph.
>> +}
>> +
>> bool Inliner::runOnSCC(CallGraphSCC &SCC) {
>> if (skipSCC(SCC))
>> return false;
>> -
>> return inlineCalls(SCC);
>> }
>>
>> @@ -384,7 +410,8 @@ inlineCallsImpl(CallGraphSCC &SCC, CallG
>> ProfileSummaryInfo *PSI, TargetLibraryInfo &TLI,
>> bool InsertLifetime,
>> std::function<InlineCost(CallSite CS)> GetInlineCost,
>> - std::function<AAResults &(Function &)> AARGetter) {
>> + std::function<AAResults &(Function &)> AARGetter,
>> + ImportedFunctionsInliningStatistics
>> &ImportedFunctionsStats) {
>> SmallPtrSet<Function*, 8> SCCFunctions;
>> DEBUG(dbgs() << "Inliner visiting SCC:");
>> for (CallGraphNode *Node : SCC) {
>> @@ -502,7 +529,8 @@ inlineCallsImpl(CallGraphSCC &SCC, CallG
>>
>> // Attempt to inline the function.
>> if (!InlineCallIfPossible(CS, InlineInfo, InlinedArrayAllocas,
>> - InlineHistoryID, InsertLifetime,
>> AARGetter)) {
>> + InlineHistoryID, InsertLifetime,
>> AARGetter,
>> + ImportedFunctionsStats)) {
>> emitOptimizationRemarkMissed(CallerCtx, DEBUG_TYPE, *Caller,
>> DLoc,
>> Twine(Callee->getName() +
>> " will not be inlined into
>> " +
>> @@ -591,12 +619,15 @@ bool Inliner::inlineCalls(CallGraphSCC &
>> };
>> return inlineCallsImpl(SCC, CG, GetAssumptionCache, PSI, TLI,
>> InsertLifetime,
>> [this](CallSite CS) { return getInlineCost(CS);
>> },
>> - AARGetter);
>> + AARGetter, ImportedFunctionsStats);
>> }
>>
>> /// Remove now-dead linkonce functions at the end of
>> /// processing to avoid breaking the SCC traversal.
>> bool Inliner::doFinalization(CallGraph &CG) {
>> + if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No)
>> + ImportedFunctionsStats.dump(InlinerFunctionImportStats ==
>> + InlinerFunctionImportStatsOpts::Verbose);
>> return removeDeadFunctions(CG);
>> }
>>
>>
>> Modified: llvm/trunk/lib/Transforms/Utils/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/CMakeLists.txt?rev=277089&r1=277088&r2=277089&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Transforms/Utils/CMakeLists.txt (original)
>> +++ llvm/trunk/lib/Transforms/Utils/CMakeLists.txt Thu Jul 28 19:27:16
>> 2016
>> @@ -16,6 +16,7 @@ add_llvm_library(LLVMTransformUtils
>> FunctionImportUtils.cpp
>> GlobalStatus.cpp
>> InlineFunction.cpp
>> + ImportedFunctionsInliningStatistics.cpp
>> InstructionNamer.cpp
>> IntegerDivision.cpp
>> LCSSA.cpp
>>
>> Added:
>> llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp?rev=277089&view=auto
>>
>> ==============================================================================
>> ---
>> llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp
>> (added)
>> +++
>> llvm/trunk/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp Thu
>> Jul 28 19:27:16 2016
>> @@ -0,0 +1,201 @@
>> +//===-- ImportedFunctionsInliningStats.cpp ----------------------*- C++
>> -*-===//
>> +//
>> +// The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +// Generating inliner statistics for imported functions, mostly useful
>> for
>> +// ThinLTO.
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"
>> +#include "llvm/ADT/STLExtras.h"
>> +#include "llvm/IR/Function.h"
>> +#include "llvm/IR/Module.h"
>> +#include "llvm/Support/Debug.h"
>> +#include "llvm/Support/raw_ostream.h"
>> +#include <algorithm>
>> +#include <iomanip>
>> +#include <sstream>
>> +using namespace llvm;
>> +
>> +ImportedFunctionsInliningStatistics::InlineGraphNode &
>> +ImportedFunctionsInliningStatistics::createInlineGraphNode(const
>> Function &F) {
>> +
>> + auto &ValueLookup = NodesMap[F.getName()];
>> + if (!ValueLookup) {
>> + ValueLookup = llvm::make_unique<InlineGraphNode>();
>> + ValueLookup->Imported = F.getMetadata("thinlto_src_module") !=
>> nullptr;
>> + }
>> + return *ValueLookup;
>> +}
>> +
>> +void ImportedFunctionsInliningStatistics::recordInline(const Function
>> &Caller,
>> + const Function
>> &Callee) {
>> +
>> + InlineGraphNode &CallerNode = createInlineGraphNode(Caller);
>> + InlineGraphNode &CalleeNode = createInlineGraphNode(Callee);
>> + CalleeNode.NumberOfInlines++;
>> +
>> + if (!CallerNode.Imported && !CalleeNode.Imported) {
>> + // Direct inline from not imported callee to not imported caller, so
>> we
>> + // don't have to add this to graph. It might be very helpful if you
>> wanna
>> + // get the inliner statistics in compile step where there are no
>> imported
>> + // functions. In this case the graph would be empty.
>> + CalleeNode.NumberOfRealInlines++;
>> + return;
>> + }
>> +
>> + CallerNode.InlinedCallees.push_back(&CalleeNode);
>> + if (!CallerNode.Imported)
>> + // Save Caller as a starting node for traversal.
>> + NonImportedCallers.push_back(Caller.getName());
>> +}
>> +
>> +void ImportedFunctionsInliningStatistics::setModuleInfo(const Module &M)
>> {
>> + ModuleName = M.getName();
>> + for (const auto &F : M.functions()) {
>> + AllFunctions++;
>> + ImportedFunctions += int(F.getMetadata("thinlto_src_module") !=
>> nullptr);
>> + }
>> +}
>> +static std::string getStatString(const char *Msg, int32_t Fraction,
>> int32_t All,
>> + const char *PercentageOfMsg,
>> + bool LineEnd = true) {
>> + double Result = 0;
>> + if (All != 0)
>> + Result = 100 * static_cast<double>(Fraction) / All;
>> +
>> + std::stringstream Str;
>> + Str << std::setprecision(4) << Msg << ": " << Fraction << " [" <<
>> Result
>> + << "% of " << PercentageOfMsg << "]";
>> + if (LineEnd)
>> + Str << "\n";
>> + return Str.str();
>> +}
>> +
>> +void ImportedFunctionsInliningStatistics::dump(const bool Verbose) {
>> + calculateRealInlines();
>> + NonImportedCallers.clear();
>> +
>> + int32_t InlinedImportedFunctionsCount = 0;
>> + int32_t InlinedNotImportedFunctionsCount = 0;
>> +
>> + int32_t InlinedImportedFunctionsToImportingModuleCount = 0;
>> + int32_t InlinedNotImportedFunctionsToImportingModuleCount = 0;
>> +
>> + const auto SortedNodes = getSortedNodes();
>> + std::string Out;
>> + Out.reserve(5000);
>> + raw_string_ostream Ostream(Out);
>> +
>> + Ostream << "------- Dumping inliner stats for [" << ModuleName
>> + << "] -------\n";
>> +
>> + if (Verbose)
>> + Ostream << "-- List of inlined functions:\n";
>> +
>> + for (const auto &Node : SortedNodes) {
>> + assert(Node.second->NumberOfInlines >=
>> Node.second->NumberOfRealInlines);
>> + if (Node.second->NumberOfInlines == 0)
>> + continue;
>> +
>> + if (Node.second->Imported) {
>> + InlinedImportedFunctionsCount++;
>> + InlinedImportedFunctionsToImportingModuleCount +=
>> + int(Node.second->NumberOfRealInlines > 0);
>> + } else {
>> + InlinedNotImportedFunctionsCount++;
>> + InlinedNotImportedFunctionsToImportingModuleCount +=
>> + int(Node.second->NumberOfRealInlines > 0);
>> + }
>> +
>> + if (Verbose)
>> + Ostream << "Inlined "
>> + << (Node.second->Imported ? "imported " : "not imported ")
>> + << "function [" << Node.first << "]"
>> + << ": #inlines = " << Node.second->NumberOfInlines
>> + << ", #inlines_to_importing_module = "
>> + << Node.second->NumberOfRealInlines << "\n";
>> + }
>> +
>> + auto InlinedFunctionsCount =
>> + InlinedImportedFunctionsCount + InlinedNotImportedFunctionsCount;
>> + auto NotImportedFuncCount = AllFunctions - ImportedFunctions;
>> + auto ImportedNotInlinedIntoModule =
>> + ImportedFunctions - InlinedImportedFunctionsToImportingModuleCount;
>> +
>> + Ostream << "-- Summary:\n"
>> + << "All functions: " << AllFunctions
>> + << ", imported functions: " << ImportedFunctions << "\n"
>> + << getStatString("inlined functions", InlinedFunctionsCount,
>> + AllFunctions, "all functions")
>> + << getStatString("imported functions inlined anywhere",
>> + InlinedImportedFunctionsCount,
>> ImportedFunctions,
>> + "imported functions")
>> + << getStatString("imported functions inlined into importing
>> module",
>> +
>> InlinedImportedFunctionsToImportingModuleCount,
>> + ImportedFunctions, "imported functions",
>> + /*LineEnd=*/false)
>> + << getStatString(", remaining", ImportedNotInlinedIntoModule,
>> + ImportedFunctions, "imported functions")
>> + << getStatString("non-imported functions inlined anywhere",
>> + InlinedNotImportedFunctionsCount,
>> + NotImportedFuncCount, "non-imported
>> functions")
>> + << getStatString(
>> + "non-imported functions inlined into importing module",
>> + InlinedNotImportedFunctionsToImportingModuleCount,
>> + NotImportedFuncCount, "non-imported functions");
>> + Ostream.flush();
>> + dbgs() << Out;
>> +}
>> +
>> +void ImportedFunctionsInliningStatistics::calculateRealInlines() {
>> + // Removing duplicated Callers.
>> + std::sort(NonImportedCallers.begin(), NonImportedCallers.end());
>> + NonImportedCallers.erase(
>> + std::unique(NonImportedCallers.begin(), NonImportedCallers.end()),
>> + NonImportedCallers.end());
>> +
>> + for (const auto &Name : NonImportedCallers) {
>> + auto &Node = *NodesMap[Name];
>> + if (!Node.Visited)
>> + dfs(Node);
>> + }
>> +}
>> +
>> +void ImportedFunctionsInliningStatistics::dfs(InlineGraphNode
>> &GraphNode) {
>> + assert(!GraphNode.Visited);
>> + GraphNode.Visited = true;
>> + for (auto *const InlinedFunctionNode : GraphNode.InlinedCallees) {
>> + InlinedFunctionNode->NumberOfRealInlines++;
>> + if (!InlinedFunctionNode->Visited)
>> + dfs(*InlinedFunctionNode);
>> + }
>> +}
>> +
>> +ImportedFunctionsInliningStatistics::SortedNodesTy
>> +ImportedFunctionsInliningStatistics::getSortedNodes() {
>> + SortedNodesTy SortedNodes;
>> + SortedNodes.reserve(NodesMap.size());
>> +
>> + for (auto &&Node : NodesMap)
>> + SortedNodes.emplace_back(Node.first, std::move(Node.second));
>> +
>> + NodesMap.clear(); // We don't want to leave nullptrs.
>>
>
> 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.
>
> +
>> + std::sort(
>> + SortedNodes.begin(), SortedNodes.end(),
>> + [&](const SortedNodesTy::value_type &Lhs,
>> + const SortedNodesTy::value_type &Rhs) {
>> + if (Lhs.second->NumberOfInlines != Rhs.second->NumberOfInlines)
>> + return Lhs.second->NumberOfInlines >
>> Rhs.second->NumberOfInlines;
>> + if (Lhs.second->NumberOfRealInlines !=
>> Rhs.second->NumberOfRealInlines)
>> + return Lhs.second->NumberOfRealInlines >
>> + Rhs.second->NumberOfRealInlines;
>> + return Lhs.first < Rhs.first;
>> + });
>> + return SortedNodes;
>> +}
>>
>> Added: llvm/trunk/test/Transforms/Inline/inline_stats.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/inline_stats.ll?rev=277089&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/Transforms/Inline/inline_stats.ll (added)
>> +++ llvm/trunk/test/Transforms/Inline/inline_stats.ll Thu Jul 28 19:27:16
>> 2016
>> @@ -0,0 +1,87 @@
>> +; RUN: opt -S -inline -inliner-function-import-stats=basic < %s 2>&1 |
>> FileCheck %s -check-prefix=CHECK-BASIC -check-prefix=CHECK
>> +; RUN: opt -S -inline -inliner-function-import-stats=verbose < %s 2>&1 |
>> FileCheck %s -check-prefix="CHECK-VERBOSE" -check-prefix=CHECK
>> +
>> +; CHECK: ------- Dumping inliner stats for [<stdin>] -------
>> +; CHECK-BASIC-NOT: -- List of inlined functions:
>> +; CHECK-BASIC-NOT: -- Inlined not imported function
>> +; CHECK-VERBOSE: -- List of inlined functions:
>> +; CHECK-VERBOSE: Inlined not imported function [internal2]: #inlines =
>> 6, #inlines_to_importing_module = 2
>> +; CHECK-VERBOSE: Inlined imported function [external2]: #inlines = 4,
>> #inlines_to_importing_module = 1
>> +; CHECK-VERBOSE: Inlined imported function [external1]: #inlines = 3,
>> #inlines_to_importing_module = 2
>> +; CHECK-VERBOSE: Inlined imported function [external5]: #inlines = 1,
>> #inlines_to_importing_module = 1
>> +; CHECK-VERBOSE: Inlined imported function [external3]: #inlines = 1,
>> #inlines_to_importing_module = 0
>> +
>> +; CHECK: -- Summary:
>> +; CHECK: All functions: 10, imported functions: 7
>> +; CHECK: inlined functions: 5 [50% of all functions]
>> +; CHECK: imported functions inlined anywhere: 4 [57.14% of imported
>> functions]
>> +; CHECK: imported functions inlined into importing module: 3 [42.86% of
>> imported functions], remaining: 4 [57.14% of imported functions]
>> +; CHECK: non-imported functions inlined anywhere: 1 [33.33% of
>> non-imported functions]
>> +; CHECK: non-imported functions inlined into importing module: 1 [33.33%
>> of non-imported functions]
>> +
>> +define void @internal() {
>> + call fastcc void @external1()
>> + call fastcc void @internal2()
>> + call coldcc void @external_big()
>> + ret void
>> +}
>> +
>> +define void @internal2() alwaysinline {
>> + ret void
>> +}
>> +
>> +define void @internal3() {
>> + call fastcc void @external1()
>> + call fastcc void @external5()
>> + ret void
>> +}
>> +
>> +define void @external1() alwaysinline !thinlto_src_module !0 {
>> + call fastcc void @internal2()
>> + call fastcc void @external2();
>> + ret void
>> +}
>> +
>> +define void @external2() alwaysinline !thinlto_src_module !1 {
>> + ret void
>> +}
>> +
>> +define void @external3() alwaysinline !thinlto_src_module !1 {
>> + ret void
>> +}
>> +
>> +define void @external4() !thinlto_src_module !1 {
>> + call fastcc void @external1()
>> + call fastcc void @external2()
>> + ret void
>> +}
>> +
>> +define void @external5() !thinlto_src_module !1 {
>> + ret void
>> +}
>> +
>> +; Assume big piece of code here. This function won't be inlined, so all
>> the
>> +; inlined function it will have won't affect real inlines.
>> +define void @external_big() noinline !thinlto_src_module !1 {
>> +; CHECK-NOT: call fastcc void @internal2()
>> + call fastcc void @internal2()
>> + call fastcc void @internal2()
>> + call fastcc void @internal2()
>> + call fastcc void @internal2()
>> +
>> +; CHECK-NOT: call fastcc void @external2()
>> + call fastcc void @external2()
>> + call fastcc void @external2()
>> +; CHECK-NOT: call fastcc void @external3()
>> + call fastcc void @external3()
>> + ret void
>> +}
>> +
>> +; It should not be imported, but it should not break anything.
>> +define void @external_notcalled() !thinlto_src_module !0 {
>> + call void @external_notcalled()
>> + ret void
>> +}
>> +
>> +!0 = !{!"file.cc"}
>> +!1 = !{!"other.cc"}
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
>
>
> --
> Teresa Johnson | Software Engineer | tejohnson at google.com |
> 408-460-2413
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
--
Mike
Sent from phone
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160729/4678c357/attachment-0001.html>
More information about the llvm-commits
mailing list