[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