Coverage Report

Created: 2018-10-23 09:19

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/CodeGen/PerfMonitor.cpp
Line
Count
Source (jump to first uncovered line)
1
//===------ PerfMonitor.cpp - Generate a run-time performance monitor. -======//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
//===----------------------------------------------------------------------===//
11
12
#include "polly/CodeGen/PerfMonitor.h"
13
#include "polly/CodeGen/RuntimeDebugBuilder.h"
14
#include "polly/ScopInfo.h"
15
#include "llvm/ADT/Triple.h"
16
#include "llvm/IR/Intrinsics.h"
17
#include <sstream>
18
19
using namespace llvm;
20
using namespace polly;
21
22
3
Function *PerfMonitor::getAtExit() {
23
3
  const char *Name = "atexit";
24
3
  Function *F = M->getFunction(Name);
25
3
26
3
  if (!F) {
27
3
    GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
28
3
    FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(),
29
3
                                         {Builder.getInt8PtrTy()}, false);
30
3
    F = Function::Create(Ty, Linkage, Name, M);
31
3
  }
32
3
33
3
  return F;
34
3
}
35
36
3
void PerfMonitor::addToGlobalConstructors(Function *Fn) {
37
3
  const char *Name = "llvm.global_ctors";
38
3
  GlobalVariable *GV = M->getGlobalVariable(Name);
39
3
  std::vector<Constant *> V;
40
3
41
3
  if (GV) {
42
0
    Constant *Array = GV->getInitializer();
43
0
    for (Value *X : Array->operand_values())
44
0
      V.push_back(cast<Constant>(X));
45
0
    GV->eraseFromParent();
46
0
  }
47
3
48
3
  StructType *ST = StructType::get(Builder.getInt32Ty(), Fn->getType(),
49
3
                                   Builder.getInt8PtrTy());
50
3
51
3
  V.push_back(
52
3
      ConstantStruct::get(ST, Builder.getInt32(10), Fn,
53
3
                          ConstantPointerNull::get(Builder.getInt8PtrTy())));
54
3
  ArrayType *Ty = ArrayType::get(ST, V.size());
55
3
56
3
  GV = new GlobalVariable(*M, Ty, true, GlobalValue::AppendingLinkage,
57
3
                          ConstantArray::get(Ty, V), Name, nullptr,
58
3
                          GlobalVariable::NotThreadLocal);
59
3
}
60
61
16
Function *PerfMonitor::getRDTSCP() {
62
16
  return Intrinsic::getDeclaration(M, Intrinsic::x86_rdtscp);
63
16
}
64
65
PerfMonitor::PerfMonitor(const Scop &S, Module *M)
66
5
    : M(M), Builder(M->getContext()), S(S) {
67
5
  if (Triple(M->getTargetTriple()).getArch() == llvm::Triple::x86_64)
68
5
    Supported = true;
69
0
  else
70
0
    Supported = false;
71
5
}
72
73
static void TryRegisterGlobal(Module *M, const char *Name,
74
30
                              Constant *InitialValue, Value **Location) {
75
30
  *Location = M->getGlobalVariable(Name);
76
30
77
30
  if (!*Location)
78
22
    *Location = new GlobalVariable(
79
22
        *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage,
80
22
        InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel);
81
30
}
82
83
// Generate a unique name that is usable as a LLVM name for a scop to name its
84
// performance counter.
85
5
static std::string GetScopUniqueVarname(const Scop &S) {
86
5
  std::stringstream Name;
87
5
  std::string EntryString, ExitString;
88
5
  std::tie(EntryString, ExitString) = S.getEntryExitStr();
89
5
90
5
  Name << "__polly_perf_in_" << std::string(S.getFunction().getName())
91
5
       << "_from__" << EntryString << "__to__" << ExitString;
92
5
  return Name.str();
93
5
}
94
95
5
void PerfMonitor::addScopCounter() {
96
5
  const std::string varname = GetScopUniqueVarname(S);
97
5
  TryRegisterGlobal(M, (varname + "_cycles").c_str(), Builder.getInt64(0),
98
5
                    &CyclesInCurrentScopPtr);
99
5
100
5
  TryRegisterGlobal(M, (varname + "_trip_count").c_str(), Builder.getInt64(0),
101
5
                    &TripCountForCurrentScopPtr);
102
5
}
103
104
5
void PerfMonitor::addGlobalVariables() {
105
5
  TryRegisterGlobal(M, "__polly_perf_cycles_total_start", Builder.getInt64(0),
106
5
                    &CyclesTotalStartPtr);
107
5
108
5
  TryRegisterGlobal(M, "__polly_perf_initialized", Builder.getInt1(0),
109
5
                    &AlreadyInitializedPtr);
110
5
111
5
  TryRegisterGlobal(M, "__polly_perf_cycles_in_scops", Builder.getInt64(0),
112
5
                    &CyclesInScopsPtr);
113
5
114
5
  TryRegisterGlobal(M, "__polly_perf_cycles_in_scop_start", Builder.getInt64(0),
115
5
                    &CyclesInScopStartPtr);
116
5
}
117
118
static const char *InitFunctionName = "__polly_perf_init";
119
static const char *FinalReportingFunctionName = "__polly_perf_final";
120
121
static BasicBlock *FinalStartBB = nullptr;
122
static ReturnInst *ReturnFromFinal = nullptr;
123
124
3
Function *PerfMonitor::insertFinalReporting() {
125
3
  // Create new function.
126
3
  GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
127
3
  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
128
3
  Function *ExitFn =
129
3
      Function::Create(Ty, Linkage, FinalReportingFunctionName, M);
130
3
  FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn);
131
3
  Builder.SetInsertPoint(FinalStartBB);
132
3
133
3
  if (!Supported) {
134
0
    RuntimeDebugBuilder::createCPUPrinter(
135
0
        Builder, "Polly runtime information generation not supported\n");
136
0
    Builder.CreateRetVoid();
137
0
    return ExitFn;
138
0
  }
139
3
140
3
  // Measure current cycles and compute final timings.
141
3
  Function *RDTSCPFn = getRDTSCP();
142
3
143
3
  Value *CurrentCycles =
144
3
      Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
145
3
  Value *CyclesStart = Builder.CreateLoad(CyclesTotalStartPtr, true);
146
3
  Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart);
147
3
  Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
148
3
149
3
  // Print the runtime information.
150
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n");
151
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n");
152
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n");
153
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops,
154
3
                                        "\n");
155
3
156
3
  // Print the preamble for per-scop information.
157
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "\n");
158
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n");
159
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n");
160
3
161
3
  RuntimeDebugBuilder::createCPUPrinter(
162
3
      Builder, "scop function, "
163
3
               "entry block name, exit block name, total time, trip count\n");
164
3
  ReturnFromFinal = Builder.CreateRetVoid();
165
3
  return ExitFn;
166
3
}
167
168
5
void PerfMonitor::AppendScopReporting() {
169
5
  if (!Supported)
170
0
    return;
171
5
172
5
  assert(FinalStartBB && "Expected FinalStartBB to be initialized by "
173
5
                         "PerfMonitor::insertFinalReporting.");
174
5
  assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by "
175
5
                            "PerfMonitor::insertFinalReporting.");
176
5
177
5
  Builder.SetInsertPoint(FinalStartBB);
178
5
  ReturnFromFinal->eraseFromParent();
179
5
180
5
  Value *CyclesInCurrentScop =
181
5
      Builder.CreateLoad(this->CyclesInCurrentScopPtr, true);
182
5
183
5
  Value *TripCountForCurrentScop =
184
5
      Builder.CreateLoad(this->TripCountForCurrentScopPtr, true);
185
5
186
5
  std::string EntryName, ExitName;
187
5
  std::tie(EntryName, ExitName) = S.getEntryExitStr();
188
5
189
5
  // print in CSV for easy parsing with other tools.
190
5
  RuntimeDebugBuilder::createCPUPrinter(
191
5
      Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ",
192
5
      CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n");
193
5
194
5
  ReturnFromFinal = Builder.CreateRetVoid();
195
5
}
196
197
static Function *FinalReporting = nullptr;
198
199
5
void PerfMonitor::initialize() {
200
5
  addGlobalVariables();
201
5
  addScopCounter();
202
5
203
5
  // Ensure that we only add the final reporting function once.
204
5
  // On later invocations, append to the reporting function.
205
5
  if (!FinalReporting) {
206
3
    FinalReporting = insertFinalReporting();
207
3
208
3
    Function *InitFn = insertInitFunction(FinalReporting);
209
3
    addToGlobalConstructors(InitFn);
210
3
  }
211
5
212
5
  AppendScopReporting();
213
5
}
214
215
3
Function *PerfMonitor::insertInitFunction(Function *FinalReporting) {
216
3
  // Insert function definition and BBs.
217
3
  GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
218
3
  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
219
3
  Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M);
220
3
  BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn);
221
3
  BasicBlock *EarlyReturn =
222
3
      BasicBlock::Create(M->getContext(), "earlyreturn", InitFn);
223
3
  BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn);
224
3
225
3
  Builder.SetInsertPoint(Start);
226
3
227
3
  // Check if this function was already run. If yes, return.
228
3
  //
229
3
  // In case profiling has been enabled in multiple translation units, the
230
3
  // initializer function will be added to the global constructors list of
231
3
  // each translation unit. When merging translation units, the global
232
3
  // constructor lists are just appended, such that the initializer will appear
233
3
  // multiple times. To avoid initializations being run multiple times (and
234
3
  // especially to avoid that atExitFn is called more than once), we bail
235
3
  // out if the initializer is run more than once.
236
3
  Value *HasRunBefore = Builder.CreateLoad(AlreadyInitializedPtr);
237
3
  Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB);
238
3
  Builder.SetInsertPoint(EarlyReturn);
239
3
  Builder.CreateRetVoid();
240
3
241
3
  // Keep track that this function has been run once.
242
3
  Builder.SetInsertPoint(InitBB);
243
3
  Value *True = Builder.getInt1(true);
244
3
  Builder.CreateStore(True, AlreadyInitializedPtr);
245
3
246
3
  // Register the final reporting function with atexit().
247
3
  Value *FinalReportingPtr =
248
3
      Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy());
249
3
  Function *AtExitFn = getAtExit();
250
3
  Builder.CreateCall(AtExitFn, {FinalReportingPtr});
251
3
252
3
  if (Supported) {
253
3
    // Read the currently cycle counter and store the result for later.
254
3
    Function *RDTSCPFn = getRDTSCP();
255
3
    Value *CurrentCycles =
256
3
        Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
257
3
    Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true);
258
3
  }
259
3
  Builder.CreateRetVoid();
260
3
261
3
  return InitFn;
262
3
}
263
264
5
void PerfMonitor::insertRegionStart(Instruction *InsertBefore) {
265
5
  if (!Supported)
266
0
    return;
267
5
268
5
  Builder.SetInsertPoint(InsertBefore);
269
5
  Function *RDTSCPFn = getRDTSCP();
270
5
  Value *CurrentCycles =
271
5
      Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
272
5
  Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true);
273
5
}
274
275
5
void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) {
276
5
  if (!Supported)
277
0
    return;
278
5
279
5
  Builder.SetInsertPoint(InsertBefore);
280
5
  Function *RDTSCPFn = getRDTSCP();
281
5
  LoadInst *CyclesStart = Builder.CreateLoad(CyclesInScopStartPtr, true);
282
5
  Value *CurrentCycles =
283
5
      Builder.CreateExtractValue(Builder.CreateCall(RDTSCPFn), {0});
284
5
  Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart);
285
5
  Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
286
5
  CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop);
287
5
  Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true);
288
5
289
5
  Value *CyclesInCurrentScop = Builder.CreateLoad(CyclesInCurrentScopPtr, true);
290
5
  CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop);
291
5
  Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true);
292
5
293
5
  Value *TripCountForCurrentScop =
294
5
      Builder.CreateLoad(TripCountForCurrentScopPtr, true);
295
5
  TripCountForCurrentScop =
296
5
      Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1));
297
5
  Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr,
298
5
                      true);
299
5
}