[llvm] r277089 - Added ThinLTO inlining statistics

Teresa Johnson via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 29 06:31:34 PDT 2016


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160729/c997d0d9/attachment.html>


More information about the llvm-commits mailing list