165371af2STobias Grosser //===------ PerfMonitor.cpp - Generate a run-time performance monitor. -======//
265371af2STobias Grosser //
365371af2STobias Grosser //                     The LLVM Compiler Infrastructure
465371af2STobias Grosser //
565371af2STobias Grosser // This file is distributed under the University of Illinois Open Source
665371af2STobias Grosser // License. See LICENSE.TXT for details.
765371af2STobias Grosser //
865371af2STobias Grosser //===----------------------------------------------------------------------===//
965371af2STobias Grosser //
1065371af2STobias Grosser //===----------------------------------------------------------------------===//
1165371af2STobias Grosser 
1265371af2STobias Grosser #include "polly/CodeGen/PerfMonitor.h"
1365371af2STobias Grosser #include "polly/CodeGen/RuntimeDebugBuilder.h"
1465371af2STobias Grosser #include "llvm/ADT/Triple.h"
15637be04bSTobias Grosser #include "llvm/IR/Intrinsics.h"
1665371af2STobias Grosser 
1765371af2STobias Grosser using namespace llvm;
1865371af2STobias Grosser using namespace polly;
1965371af2STobias Grosser 
2065371af2STobias Grosser Function *PerfMonitor::getAtExit() {
2165371af2STobias Grosser   const char *Name = "atexit";
2265371af2STobias Grosser   Function *F = M->getFunction(Name);
2365371af2STobias Grosser 
2465371af2STobias Grosser   if (!F) {
2565371af2STobias Grosser     GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage;
2665371af2STobias Grosser     FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(),
2765371af2STobias Grosser                                          {Builder.getInt8PtrTy()}, false);
2865371af2STobias Grosser     F = Function::Create(Ty, Linkage, Name, M);
2965371af2STobias Grosser   }
3065371af2STobias Grosser 
3165371af2STobias Grosser   return F;
3265371af2STobias Grosser }
3365371af2STobias Grosser 
3465371af2STobias Grosser void PerfMonitor::addToGlobalConstructors(Function *Fn) {
3565371af2STobias Grosser   const char *Name = "llvm.global_ctors";
3665371af2STobias Grosser   GlobalVariable *GV = M->getGlobalVariable(Name);
3765371af2STobias Grosser   std::vector<Constant *> V;
3865371af2STobias Grosser 
3965371af2STobias Grosser   if (GV) {
4065371af2STobias Grosser     Constant *Array = GV->getInitializer();
4165371af2STobias Grosser     for (Value *X : Array->operand_values())
4265371af2STobias Grosser       V.push_back(cast<Constant>(X));
4365371af2STobias Grosser     GV->eraseFromParent();
4465371af2STobias Grosser   }
4565371af2STobias Grosser 
4665371af2STobias Grosser   StructType *ST = StructType::get(Builder.getInt32Ty(), Fn->getType(),
47*d742e5efSChandler Carruth                                    Builder.getInt8PtrTy());
4865371af2STobias Grosser 
4965371af2STobias Grosser   V.push_back(ConstantStruct::get(
5065371af2STobias Grosser       ST, Builder.getInt32(10), Fn,
51*d742e5efSChandler Carruth       ConstantPointerNull::get(Builder.getInt8PtrTy())));
5265371af2STobias Grosser   ArrayType *Ty = ArrayType::get(ST, V.size());
5365371af2STobias Grosser 
5465371af2STobias Grosser   GV = new GlobalVariable(*M, Ty, true, GlobalValue::AppendingLinkage,
5565371af2STobias Grosser                           ConstantArray::get(Ty, V), Name, nullptr,
5665371af2STobias Grosser                           GlobalVariable::NotThreadLocal);
5765371af2STobias Grosser }
5865371af2STobias Grosser 
5965371af2STobias Grosser Function *PerfMonitor::getRDTSCP() {
60637be04bSTobias Grosser   return Intrinsic::getDeclaration(M, Intrinsic::x86_rdtscp);
6165371af2STobias Grosser }
6265371af2STobias Grosser 
6365371af2STobias Grosser PerfMonitor::PerfMonitor(Module *M) : M(M), Builder(M->getContext()) {
6465371af2STobias Grosser   if (Triple(M->getTargetTriple()).getArch() == llvm::Triple::x86_64)
6565371af2STobias Grosser     Supported = true;
6665371af2STobias Grosser   else
6765371af2STobias Grosser     Supported = false;
6865371af2STobias Grosser }
6965371af2STobias Grosser 
7065371af2STobias Grosser void PerfMonitor::addGlobalVariables() {
7165371af2STobias Grosser   auto TryRegisterGlobal = [=](const char *Name, Constant *InitialValue,
7265371af2STobias Grosser                                Value **Location) {
7365371af2STobias Grosser     *Location = M->getGlobalVariable(Name);
7465371af2STobias Grosser 
7565371af2STobias Grosser     if (!*Location)
7665371af2STobias Grosser       *Location = new GlobalVariable(
7765371af2STobias Grosser           *M, InitialValue->getType(), true, GlobalValue::WeakAnyLinkage,
7865371af2STobias Grosser           InitialValue, Name, nullptr, GlobalVariable::InitialExecTLSModel);
7965371af2STobias Grosser   };
8065371af2STobias Grosser 
8165371af2STobias Grosser   TryRegisterGlobal("__polly_perf_cycles_total_start", Builder.getInt64(0),
8265371af2STobias Grosser                     &CyclesTotalStartPtr);
8365371af2STobias Grosser 
8465371af2STobias Grosser   TryRegisterGlobal("__polly_perf_initialized", Builder.getInt1(0),
8565371af2STobias Grosser                     &AlreadyInitializedPtr);
8665371af2STobias Grosser 
8765371af2STobias Grosser   TryRegisterGlobal("__polly_perf_cycles_in_scops", Builder.getInt64(0),
8865371af2STobias Grosser                     &CyclesInScopsPtr);
8965371af2STobias Grosser 
9065371af2STobias Grosser   TryRegisterGlobal("__polly_perf_cycles_in_scop_start", Builder.getInt64(0),
9165371af2STobias Grosser                     &CyclesInScopStartPtr);
9265371af2STobias Grosser 
9365371af2STobias Grosser   TryRegisterGlobal("__polly_perf_write_loation", Builder.getInt32(0),
9465371af2STobias Grosser                     &RDTSCPWriteLocation);
9565371af2STobias Grosser }
9665371af2STobias Grosser 
9765371af2STobias Grosser static const char *InitFunctionName = "__polly_perf_init";
9865371af2STobias Grosser static const char *FinalReportingFunctionName = "__polly_perf_final";
9965371af2STobias Grosser 
10065371af2STobias Grosser Function *PerfMonitor::insertFinalReporting() {
10165371af2STobias Grosser   // Create new function.
10265371af2STobias Grosser   GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
10365371af2STobias Grosser   FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
10465371af2STobias Grosser   Function *ExitFn =
10565371af2STobias Grosser       Function::Create(Ty, Linkage, FinalReportingFunctionName, M);
10665371af2STobias Grosser   BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", ExitFn);
10765371af2STobias Grosser   Builder.SetInsertPoint(Start);
10865371af2STobias Grosser 
10965371af2STobias Grosser   if (!Supported) {
11065371af2STobias Grosser     RuntimeDebugBuilder::createCPUPrinter(
11165371af2STobias Grosser         Builder, "Polly runtime information generation not supported\n");
11265371af2STobias Grosser     Builder.CreateRetVoid();
11365371af2STobias Grosser     return ExitFn;
11465371af2STobias Grosser   }
11565371af2STobias Grosser 
11665371af2STobias Grosser   // Measure current cycles and compute final timings.
11765371af2STobias Grosser   Function *RDTSCPFn = getRDTSCP();
11865371af2STobias Grosser   Value *CurrentCycles = Builder.CreateCall(
11965371af2STobias Grosser       RDTSCPFn,
12065371af2STobias Grosser       Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
12165371af2STobias Grosser   Value *CyclesStart = Builder.CreateLoad(CyclesTotalStartPtr, true);
12265371af2STobias Grosser   Value *CyclesTotal = Builder.CreateSub(CurrentCycles, CyclesStart);
12365371af2STobias Grosser   Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
12465371af2STobias Grosser 
12565371af2STobias Grosser   // Print the runtime information.
12665371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "Polly runtime information\n");
12765371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "-------------------------\n");
12865371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "Total: ", CyclesTotal, "\n");
12965371af2STobias Grosser   RuntimeDebugBuilder::createCPUPrinter(Builder, "Scops: ", CyclesInScops,
13065371af2STobias Grosser                                         "\n");
13165371af2STobias Grosser 
13265371af2STobias Grosser   // Finalize function.
13365371af2STobias Grosser   Builder.CreateRetVoid();
13465371af2STobias Grosser   return ExitFn;
13565371af2STobias Grosser }
13665371af2STobias Grosser 
13765371af2STobias Grosser void PerfMonitor::initialize() {
13865371af2STobias Grosser   addGlobalVariables();
13965371af2STobias Grosser 
14065371af2STobias Grosser   Function *F = M->getFunction(InitFunctionName);
14165371af2STobias Grosser   if (F)
14265371af2STobias Grosser     return;
14365371af2STobias Grosser 
14465371af2STobias Grosser   // initialize
14565371af2STobias Grosser   Function *FinalReporting = insertFinalReporting();
14665371af2STobias Grosser   Function *InitFn = insertInitFunction(FinalReporting);
14765371af2STobias Grosser   addToGlobalConstructors(InitFn);
14865371af2STobias Grosser }
14965371af2STobias Grosser 
15065371af2STobias Grosser Function *PerfMonitor::insertInitFunction(Function *FinalReporting) {
15165371af2STobias Grosser   // Insert function definition and BBs.
15265371af2STobias Grosser   GlobalValue::LinkageTypes Linkage = Function::WeakODRLinkage;
15365371af2STobias Grosser   FunctionType *Ty = FunctionType::get(Builder.getVoidTy(), {}, false);
15465371af2STobias Grosser   Function *InitFn = Function::Create(Ty, Linkage, InitFunctionName, M);
15565371af2STobias Grosser   BasicBlock *Start = BasicBlock::Create(M->getContext(), "start", InitFn);
15665371af2STobias Grosser   BasicBlock *EarlyReturn =
15765371af2STobias Grosser       BasicBlock::Create(M->getContext(), "earlyreturn", InitFn);
15865371af2STobias Grosser   BasicBlock *InitBB = BasicBlock::Create(M->getContext(), "initbb", InitFn);
15965371af2STobias Grosser 
16065371af2STobias Grosser   Builder.SetInsertPoint(Start);
16165371af2STobias Grosser 
16265371af2STobias Grosser   // Check if this function was already run. If yes, return.
16365371af2STobias Grosser   //
16465371af2STobias Grosser   // In case profiling has been enabled in multiple translation units, the
16565371af2STobias Grosser   // initializer function will be added to the global constructors list of
16665371af2STobias Grosser   // each translation unit. When merging translation units, the global
16765371af2STobias Grosser   // constructor lists are just appended, such that the initializer will appear
16865371af2STobias Grosser   // multiple times. To avoid initializations being run multiple times (and
16965371af2STobias Grosser   // especially to avoid that atExitFn is called more than once), we bail
17065371af2STobias Grosser   // out if the intializer is run more than once.
17165371af2STobias Grosser   Value *HasRunBefore = Builder.CreateLoad(AlreadyInitializedPtr);
17265371af2STobias Grosser   Builder.CreateCondBr(HasRunBefore, EarlyReturn, InitBB);
17365371af2STobias Grosser   Builder.SetInsertPoint(EarlyReturn);
17465371af2STobias Grosser   Builder.CreateRetVoid();
17565371af2STobias Grosser 
17665371af2STobias Grosser   // Keep track that this function has been run once.
17765371af2STobias Grosser   Builder.SetInsertPoint(InitBB);
17865371af2STobias Grosser   Value *True = Builder.getInt1(true);
17965371af2STobias Grosser   Builder.CreateStore(True, AlreadyInitializedPtr);
18065371af2STobias Grosser 
18165371af2STobias Grosser   // Register the final reporting function with atexit().
18265371af2STobias Grosser   Value *FinalReportingPtr =
18365371af2STobias Grosser       Builder.CreatePointerCast(FinalReporting, Builder.getInt8PtrTy());
18465371af2STobias Grosser   Function *AtExitFn = getAtExit();
18565371af2STobias Grosser   Builder.CreateCall(AtExitFn, {FinalReportingPtr});
18665371af2STobias Grosser 
18765371af2STobias Grosser   if (Supported) {
18865371af2STobias Grosser     // Read the currently cycle counter and store the result for later.
18965371af2STobias Grosser     Function *RDTSCPFn = getRDTSCP();
19065371af2STobias Grosser     Value *CurrentCycles = Builder.CreateCall(
19165371af2STobias Grosser         RDTSCPFn,
19265371af2STobias Grosser         Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
19365371af2STobias Grosser     Builder.CreateStore(CurrentCycles, CyclesTotalStartPtr, true);
19465371af2STobias Grosser   }
19565371af2STobias Grosser   Builder.CreateRetVoid();
19665371af2STobias Grosser 
19765371af2STobias Grosser   return InitFn;
19865371af2STobias Grosser }
19965371af2STobias Grosser 
20065371af2STobias Grosser void PerfMonitor::insertRegionStart(Instruction *InsertBefore) {
20165371af2STobias Grosser   if (!Supported)
20265371af2STobias Grosser     return;
20365371af2STobias Grosser 
20465371af2STobias Grosser   Builder.SetInsertPoint(InsertBefore);
20565371af2STobias Grosser   Function *RDTSCPFn = getRDTSCP();
20665371af2STobias Grosser   Value *CurrentCycles = Builder.CreateCall(
20765371af2STobias Grosser       RDTSCPFn,
20865371af2STobias Grosser       Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
20965371af2STobias Grosser   Builder.CreateStore(CurrentCycles, CyclesInScopStartPtr, true);
21065371af2STobias Grosser }
21165371af2STobias Grosser 
21265371af2STobias Grosser void PerfMonitor::insertRegionEnd(Instruction *InsertBefore) {
21365371af2STobias Grosser   if (!Supported)
21465371af2STobias Grosser     return;
21565371af2STobias Grosser 
21665371af2STobias Grosser   Builder.SetInsertPoint(InsertBefore);
21765371af2STobias Grosser   Function *RDTSCPFn = getRDTSCP();
21865371af2STobias Grosser   LoadInst *CyclesStart = Builder.CreateLoad(CyclesInScopStartPtr, true);
21965371af2STobias Grosser   Value *CurrentCycles = Builder.CreateCall(
22065371af2STobias Grosser       RDTSCPFn,
22165371af2STobias Grosser       Builder.CreatePointerCast(RDTSCPWriteLocation, Builder.getInt8PtrTy()));
22265371af2STobias Grosser   Value *CyclesInScop = Builder.CreateSub(CurrentCycles, CyclesStart);
22365371af2STobias Grosser   Value *CyclesInScops = Builder.CreateLoad(CyclesInScopsPtr, true);
22465371af2STobias Grosser   CyclesInScops = Builder.CreateAdd(CyclesInScops, CyclesInScop);
22565371af2STobias Grosser   Builder.CreateStore(CyclesInScops, CyclesInScopsPtr, true);
22665371af2STobias Grosser }
227