Coverage Report

Created: 2017-08-21 19:50

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/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 (
!F3
)
{3
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 (
GV3
)
{0
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
3
  }
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
5
  else
70
0
    Supported = false;
71
5
}
72
73
static void TryRegisterGlobal(Module *M, const char *Name,
74
35
                              Constant *InitialValue, Value **Location) {
75
35
  *Location = M->getGlobalVariable(Name);
76
35
77
35
  if (!*Location)
78
35
    *Location = new GlobalVariable(
79
25
        *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage,
80
35
        InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel);
81
35
}
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
5
  TryRegisterGlobal(M, "__polly_perf_write_loation", Builder.getInt32(0),
118
5
                    &RDTSCPWriteLocation);
119
5
}
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
3
Function *PerfMonitor::insertFinalReporting() {
128
3
  // Create new function.
129
3
  GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
130
3
  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
131
3
  Function *ExitFn =
132
3
      Function::Create(Ty, Linkage, FinalReportingFunctionName, M);
133
3
  FinalStartBB = BasicBlock::Create(M->getContext(), "start", ExitFn);
134
3
  Builder.SetInsertPoint(FinalStartBB);
135
3
136
3
  if (
!Supported3
)
{0
137
0
    RuntimeDebugBuilder::createCPUPrinter(
138
0
        Builder, "Polly runtime information generation not supported\n");
139
0
    Builder.CreateRetVoid();
140
0
    return ExitFn;
141
3
  }
142
3
143
3
  // Measure current cycles and compute final timings.
144
3
  Function *RDTSCPFn = getRDTSCP();
145
3
  Value *CurrentCycles = Builder.CreateCall(
146
3
      RDTSCPFn,
147
3
      Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
148
3
  Value *CyclesStart = Builder.CreateLoad(CyclesTotalStartPtr, true);
149
3
  Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart);
150
3
  Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
151
3
152
3
  // Print the runtime information.
153
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n");
154
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n");
155
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n");
156
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops,
157
3
                                        "\n");
158
3
159
3
  // Print the preamble for per-scop information.
160
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "\n");
161
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "Per SCoP information\n");
162
3
  RuntimeDebugBuilder::createCPUPrinter(Builder, "--------------------\n");
163
3
164
3
  RuntimeDebugBuilder::createCPUPrinter(
165
3
      Builder, "scop function, "
166
3
               "entry block name, exit block name, total time, trip count\n");
167
3
  ReturnFromFinal = Builder.CreateRetVoid();
168
3
  return ExitFn;
169
3
}
170
171
5
void PerfMonitor::AppendScopReporting() {
172
5
  if (!Supported)
173
0
    return;
174
5
175
5
  assert(FinalStartBB && "Expected FinalStartBB to be initialized by "
176
5
                         "PerfMonitor::insertFinalReporting.");
177
5
  assert(ReturnFromFinal && "Expected ReturnFromFinal to be initialized by "
178
5
                            "PerfMonitor::insertFinalReporting.");
179
5
180
5
  Builder.SetInsertPoint(FinalStartBB);
181
5
  ReturnFromFinal->eraseFromParent();
182
5
183
5
  Value *CyclesInCurrentScop =
184
5
      Builder.CreateLoad(this->CyclesInCurrentScopPtr, true);
185
5
186
5
  Value *TripCountForCurrentScop =
187
5
      Builder.CreateLoad(this->TripCountForCurrentScopPtr, true);
188
5
189
5
  std::string EntryName, ExitName;
190
5
  std::tie(EntryName, ExitName) = S.getEntryExitStr();
191
5
192
5
  // print in CSV for easy parsing with other tools.
193
5
  RuntimeDebugBuilder::createCPUPrinter(
194
5
      Builder, S.getFunction().getName(), ", ", EntryName, ", ", ExitName, ", ",
195
5
      CyclesInCurrentScop, ", ", TripCountForCurrentScop, "\n");
196
5
197
5
  ReturnFromFinal = Builder.CreateRetVoid();
198
5
}
199
200
static Function *FinalReporting = nullptr;
201
202
5
void PerfMonitor::initialize() {
203
5
  addGlobalVariables();
204
5
  addScopCounter();
205
5
206
5
  // Ensure that we only add the final reporting function once.
207
5
  // On later invocations, append to the reporting function.
208
5
  if (
!FinalReporting5
)
{3
209
3
    FinalReporting = insertFinalReporting();
210
3
211
3
    Function *InitFn = insertInitFunction(FinalReporting);
212
3
    addToGlobalConstructors(InitFn);
213
5
  }
214
5
215
5
  AppendScopReporting();
216
5
}
217
218
3
Function *PerfMonitor::insertInitFunction(Function *FinalReporting) {
219
3
  // Insert function definition and BBs.
220
3
  GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
221
3
  FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
222
3
  Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M);
223
3
  BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn);
224
3
  BasicBlock *EarlyReturn =
225
3
      BasicBlock::Create(M->getContext(), "earlyreturn", InitFn);
226
3
  BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn);
227
3
228
3
  Builder.SetInsertPoint(Start);
229
3
230
3
  // Check if this function was already run. If yes, return.
231
3
  //
232
3
  // In case profiling has been enabled in multiple translation units, the
233
3
  // initializer function will be added to the global constructors list of
234
3
  // each translation unit. When merging translation units, the global
235
3
  // constructor lists are just appended, such that the initializer will appear
236
3
  // multiple times. To avoid initializations being run multiple times (and
237
3
  // especially to avoid that atExitFn is called more than once), we bail
238
3
  // out if the initializer is run more than once.
239
3
  Value *HasRunBefore = Builder.CreateLoad(AlreadyInitializedPtr);
240
3
  Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB);
241
3
  Builder.SetInsertPoint(EarlyReturn);
242
3
  Builder.CreateRetVoid();
243
3
244
3
  // Keep track that this function has been run once.
245
3
  Builder.SetInsertPoint(InitBB);
246
3
  Value *True = Builder.getInt1(true);
247
3
  Builder.CreateStore(True, AlreadyInitializedPtr);
248
3
249
3
  // Register the final reporting function with atexit().
250
3
  Value *FinalReportingPtr =
251
3
      Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy());
252
3
  Function *AtExitFn = getAtExit();
253
3
  Builder.CreateCall(AtExitFn, {FinalReportingPtr});
254
3
255
3
  if (
Supported3
)
{3
256
3
    // Read the currently cycle counter and store the result for later.
257
3
    Function *RDTSCPFn = getRDTSCP();
258
3
    Value *CurrentCycles = Builder.CreateCall(
259
3
        RDTSCPFn,
260
3
        Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
261
3
    Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true);
262
3
  }
263
3
  Builder.CreateRetVoid();
264
3
265
3
  return InitFn;
266
3
}
267
268
5
void PerfMonitor::insertRegionStart(Instruction *InsertBefore) {
269
5
  if (!Supported)
270
0
    return;
271
5
272
5
  Builder.SetInsertPoint(InsertBefore);
273
5
  Function *RDTSCPFn = getRDTSCP();
274
5
  Value *CurrentCycles = Builder.CreateCall(
275
5
      RDTSCPFn,
276
5
      Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
277
5
  Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true);
278
5
}
279
280
5
void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) {
281
5
  if (!Supported)
282
0
    return;
283
5
284
5
  Builder.SetInsertPoint(InsertBefore);
285
5
  Function *RDTSCPFn = getRDTSCP();
286
5
  LoadInst *CyclesStart = Builder.CreateLoad(CyclesInScopStartPtr, true);
287
5
  Value *CurrentCycles = Builder.CreateCall(
288
5
      RDTSCPFn,
289
5
      Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
290
5
  Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart);
291
5
  Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
292
5
  CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop);
293
5
  Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true);
294
5
295
5
  Value *CyclesInCurrentScop = Builder.CreateLoad(CyclesInCurrentScopPtr, true);
296
5
  CyclesInCurrentScop = Builder.CreateAdd(CyclesInCurrentScop, CyclesInScop);
297
5
  Builder.CreateStore(CyclesInCurrentScop, CyclesInCurrentScopPtr, true);
298
5
299
5
  Value *TripCountForCurrentScop =
300
5
      Builder.CreateLoad(TripCountForCurrentScopPtr, true);
301
5
  TripCountForCurrentScop =
302
5
      Builder.CreateAdd(TripCountForCurrentScop, Builder.getInt64(1));
303
5
  Builder.CreateStore(TripCountForCurrentScop, TripCountForCurrentScopPtr,
304
5
                      true);
305
5
}