Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp
Line
Count
Source
1
//===-- ImportedFunctionsInliningStats.cpp ----------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
// Generating inliner statistics for imported functions, mostly useful for
9
// ThinLTO.
10
//===----------------------------------------------------------------------===//
11
12
#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h"
13
#include "llvm/ADT/STLExtras.h"
14
#include "llvm/IR/Function.h"
15
#include "llvm/IR/Module.h"
16
#include "llvm/Support/Debug.h"
17
#include "llvm/Support/raw_ostream.h"
18
#include <algorithm>
19
#include <iomanip>
20
#include <sstream>
21
using namespace llvm;
22
23
ImportedFunctionsInliningStatistics::InlineGraphNode &
24
120
ImportedFunctionsInliningStatistics::createInlineGraphNode(const Function &F) {
25
120
26
120
  auto &ValueLookup = NodesMap[F.getName()];
27
120
  if (!ValueLookup) {
28
36
    ValueLookup = llvm::make_unique<InlineGraphNode>();
29
36
    ValueLookup->Imported = F.getMetadata("thinlto_src_module") != nullptr;
30
36
  }
31
120
  return *ValueLookup;
32
120
}
33
34
void ImportedFunctionsInliningStatistics::recordInline(const Function &Caller,
35
60
                                                       const Function &Callee) {
36
60
37
60
  InlineGraphNode &CallerNode = createInlineGraphNode(Caller);
38
60
  InlineGraphNode &CalleeNode = createInlineGraphNode(Callee);
39
60
  CalleeNode.NumberOfInlines++;
40
60
41
60
  if (!CallerNode.Imported && 
!CalleeNode.Imported16
) {
42
4
    // Direct inline from not imported callee to not imported caller, so we
43
4
    // don't have to add this to graph. It might be very helpful if you wanna
44
4
    // get the inliner statistics in compile step where there are no imported
45
4
    // functions. In this case the graph would be empty.
46
4
    CalleeNode.NumberOfRealInlines++;
47
4
    return;
48
4
  }
49
56
50
56
  CallerNode.InlinedCallees.push_back(&CalleeNode);
51
56
  if (!CallerNode.Imported) {
52
12
    // We could avoid second lookup, but it would make the code ultra ugly.
53
12
    auto It = NodesMap.find(Caller.getName());
54
12
    assert(It != NodesMap.end() && "The node should be already there.");
55
12
    // Save Caller as a starting node for traversal. The string has to be one
56
12
    // from map because Caller can disappear (and function name with it).
57
12
    NonImportedCallers.push_back(It->first());
58
12
  }
59
56
}
60
61
4
void ImportedFunctionsInliningStatistics::setModuleInfo(const Module &M) {
62
4
  ModuleName = M.getName();
63
44
  for (const auto &F : M.functions()) {
64
44
    if (F.isDeclaration())
65
4
      continue;
66
40
    AllFunctions++;
67
40
    ImportedFunctions += int(F.getMetadata("thinlto_src_module") != nullptr);
68
40
  }
69
4
}
70
static std::string getStatString(const char *Msg, int32_t Fraction, int32_t All,
71
                                 const char *PercentageOfMsg,
72
24
                                 bool LineEnd = true) {
73
24
  double Result = 0;
74
24
  if (All != 0)
75
24
    Result = 100 * static_cast<double>(Fraction) / All;
76
24
77
24
  std::stringstream Str;
78
24
  Str << std::setprecision(4) << Msg << ": " << Fraction << " [" << Result
79
24
      << "% of " << PercentageOfMsg << "]";
80
24
  if (LineEnd)
81
20
    Str << "\n";
82
24
  return Str.str();
83
24
}
84
85
4
void ImportedFunctionsInliningStatistics::dump(const bool Verbose) {
86
4
  calculateRealInlines();
87
4
  NonImportedCallers.clear();
88
4
89
4
  int32_t InlinedImportedFunctionsCount = 0;
90
4
  int32_t InlinedNotImportedFunctionsCount = 0;
91
4
92
4
  int32_t InlinedImportedFunctionsToImportingModuleCount = 0;
93
4
  int32_t InlinedNotImportedFunctionsToImportingModuleCount = 0;
94
4
95
4
  const auto SortedNodes = getSortedNodes();
96
4
  std::string Out;
97
4
  Out.reserve(5000);
98
4
  raw_string_ostream Ostream(Out);
99
4
100
4
  Ostream << "------- Dumping inliner stats for [" << ModuleName
101
4
          << "] -------\n";
102
4
103
4
  if (Verbose)
104
2
    Ostream << "-- List of inlined functions:\n";
105
4
106
36
  for (const auto &Node : SortedNodes) {
107
36
    assert(Node->second->NumberOfInlines >= Node->second->NumberOfRealInlines);
108
36
    if (Node->second->NumberOfInlines == 0)
109
16
      continue;
110
20
111
20
    if (Node->second->Imported) {
112
16
      InlinedImportedFunctionsCount++;
113
16
      InlinedImportedFunctionsToImportingModuleCount +=
114
16
          int(Node->second->NumberOfRealInlines > 0);
115
16
    } else {
116
4
      InlinedNotImportedFunctionsCount++;
117
4
      InlinedNotImportedFunctionsToImportingModuleCount +=
118
4
          int(Node->second->NumberOfRealInlines > 0);
119
4
    }
120
20
121
20
    if (Verbose)
122
10
      Ostream << "Inlined "
123
10
              << (Node->second->Imported ? 
"imported "8
:
"not imported "2
)
124
10
              << "function [" << Node->first() << "]"
125
10
              << ": #inlines = " << Node->second->NumberOfInlines
126
10
              << ", #inlines_to_importing_module = "
127
10
              << Node->second->NumberOfRealInlines << "\n";
128
20
  }
129
4
130
4
  auto InlinedFunctionsCount =
131
4
      InlinedImportedFunctionsCount + InlinedNotImportedFunctionsCount;
132
4
  auto NotImportedFuncCount = AllFunctions - ImportedFunctions;
133
4
  auto ImportedNotInlinedIntoModule =
134
4
      ImportedFunctions - InlinedImportedFunctionsToImportingModuleCount;
135
4
136
4
  Ostream << "-- Summary:\n"
137
4
          << "All functions: " << AllFunctions
138
4
          << ", imported functions: " << ImportedFunctions << "\n"
139
4
          << getStatString("inlined functions", InlinedFunctionsCount,
140
4
                           AllFunctions, "all functions")
141
4
          << getStatString("imported functions inlined anywhere",
142
4
                           InlinedImportedFunctionsCount, ImportedFunctions,
143
4
                           "imported functions")
144
4
          << getStatString("imported functions inlined into importing module",
145
4
                           InlinedImportedFunctionsToImportingModuleCount,
146
4
                           ImportedFunctions, "imported functions",
147
4
                           /*LineEnd=*/false)
148
4
          << getStatString(", remaining", ImportedNotInlinedIntoModule,
149
4
                           ImportedFunctions, "imported functions")
150
4
          << getStatString("non-imported functions inlined anywhere",
151
4
                           InlinedNotImportedFunctionsCount,
152
4
                           NotImportedFuncCount, "non-imported functions")
153
4
          << getStatString(
154
4
                 "non-imported functions inlined into importing module",
155
4
                 InlinedNotImportedFunctionsToImportingModuleCount,
156
4
                 NotImportedFuncCount, "non-imported functions");
157
4
  Ostream.flush();
158
4
  dbgs() << Out;
159
4
}
160
161
4
void ImportedFunctionsInliningStatistics::calculateRealInlines() {
162
4
  // Removing duplicated Callers.
163
4
  llvm::sort(NonImportedCallers);
164
4
  NonImportedCallers.erase(
165
4
      std::unique(NonImportedCallers.begin(), NonImportedCallers.end()),
166
4
      NonImportedCallers.end());
167
4
168
8
  for (const auto &Name : NonImportedCallers) {
169
8
    auto &Node = *NodesMap[Name];
170
8
    if (!Node.Visited)
171
8
      dfs(Node);
172
8
  }
173
4
}
174
175
24
void ImportedFunctionsInliningStatistics::dfs(InlineGraphNode &GraphNode) {
176
24
  assert(!GraphNode.Visited);
177
24
  GraphNode.Visited = true;
178
24
  for (auto *const InlinedFunctionNode : GraphNode.InlinedCallees) {
179
20
    InlinedFunctionNode->NumberOfRealInlines++;
180
20
    if (!InlinedFunctionNode->Visited)
181
16
      dfs(*InlinedFunctionNode);
182
20
  }
183
24
}
184
185
ImportedFunctionsInliningStatistics::SortedNodesTy
186
4
ImportedFunctionsInliningStatistics::getSortedNodes() {
187
4
  SortedNodesTy SortedNodes;
188
4
  SortedNodes.reserve(NodesMap.size());
189
4
  for (const NodesMapTy::value_type& Node : NodesMap)
190
36
    SortedNodes.push_back(&Node);
191
4
192
4
  llvm::sort(SortedNodes, [&](const SortedNodesTy::value_type &Lhs,
193
100
                              const SortedNodesTy::value_type &Rhs) {
194
100
    if (Lhs->second->NumberOfInlines != Rhs->second->NumberOfInlines)
195
76
      return Lhs->second->NumberOfInlines > Rhs->second->NumberOfInlines;
196
24
    if (Lhs->second->NumberOfRealInlines != Rhs->second->NumberOfRealInlines)
197
4
      return Lhs->second->NumberOfRealInlines >
198
4
             Rhs->second->NumberOfRealInlines;
199
20
    return Lhs->first() < Rhs->first();
200
20
  });
201
4
  return SortedNodes;
202
4
}