[llvm] r277089 - Added ThinLTO inlining statistics
Piotr Padlewski via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 29 11:34:33 PDT 2016
Yes, I didn't know that clang supports ancient compilers. I am just sending
my patch right now.
2016-07-29 11:30 GMT-07:00 Mike Aizatsky <aizatsky at google.com>:
> 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/d99af30b/attachment.html>
More information about the llvm-commits
mailing list