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