Coverage Report

Created: 2017-11-21 16:49

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