Coverage Report

Created: 2019-02-23 12:57

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