From e7ddcfdebe357b4067f9c7d68d44616e11351a23 Mon Sep 17 00:00:00 2001 From: Andreas Neustifter Date: Tue, 1 Sep 2009 08:48:42 +0000 Subject: [PATCH] Preparation for Optimal Edge Profiling: This adds a pass to verify the current profile against the flow conditions. This is very helpful when later on trying to perserve the profiling information during all passes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80666 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/Passes.h | 6 + include/llvm/LinkAllPasses.h | 1 + lib/Analysis/ProfileVerifierPass.cpp | 228 +++++++++++++++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 lib/Analysis/ProfileVerifierPass.cpp diff --git a/include/llvm/Analysis/Passes.h b/include/llvm/Analysis/Passes.h index e68765310fb..66ab3ea5caf 100644 --- a/include/llvm/Analysis/Passes.h +++ b/include/llvm/Analysis/Passes.h @@ -107,6 +107,12 @@ namespace llvm { FunctionPass *createProfileEstimatorPass(); extern const PassInfo *ProfileEstimatorPassID; + //===--------------------------------------------------------------------===// + // + // createProfileVerifierPass - This pass verifies profiling information. + // + FunctionPass *createProfileVerifierPass(); + //===--------------------------------------------------------------------===// // // createDSAAPass - This pass implements simple context sensitive alias diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 347dba44477..8d935576e7b 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -94,6 +94,7 @@ namespace { (void) llvm::createNoAAPass(); (void) llvm::createNoProfileInfoPass(); (void) llvm::createProfileEstimatorPass(); + (void) llvm::createProfileVerifierPass(); (void) llvm::createProfileLoaderPass(); (void) llvm::createPromoteMemoryToRegisterPass(); (void) llvm::createDemoteRegisterToMemoryPass(); diff --git a/lib/Analysis/ProfileVerifierPass.cpp b/lib/Analysis/ProfileVerifierPass.cpp new file mode 100644 index 00000000000..d92ca65baef --- /dev/null +++ b/lib/Analysis/ProfileVerifierPass.cpp @@ -0,0 +1,228 @@ +//===- ProfileVerifierPass.cpp - LLVM Pass to estimate profile info -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a pass that checks profiling information for +// plausibility. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "profile-verifier" +#include "llvm/Pass.h" +#include "llvm/Analysis/ProfileInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Debug.h" +#include +using namespace llvm; + +static bool DisableAssertions = false; +static cl::opt +ProfileVerifierDisableAssertions("profile-verifier-noassert", + cl::location(DisableAssertions), cl::desc("Disable assertions")); +bool PrintedDebugTree = false; + +namespace { + class VISIBILITY_HIDDEN ProfileVerifierPass : public FunctionPass { + ProfileInfo *PI; + std::set BBisVisited; +#ifndef NDEBUG + std::set BBisPrinted; + void debugEntry(const BasicBlock* BB, double w, double inw, int inc, + double outw, int outc, double d); + void printDebugInfo(const BasicBlock *BB); +#endif + public: + static char ID; // Class identification, replacement for typeinfo + + explicit ProfileVerifierPass () : FunctionPass(&ID) { + DisableAssertions = ProfileVerifierDisableAssertions; + } + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + } + + const char *getPassName() const { + return "Profiling information verifier"; + } + + /// run - Verify the profile information. + bool runOnFunction(Function &F); + void recurseBasicBlock(const BasicBlock *BB); + }; +} // End of anonymous namespace + +char ProfileVerifierPass::ID = 0; +static RegisterPass +X("profile-verifier", "Verify profiling information", false, true); + +namespace llvm { + FunctionPass *createProfileVerifierPass() { + return new ProfileVerifierPass(); + } +} + +#ifndef NDEBUG +void ProfileVerifierPass::printDebugInfo(const BasicBlock *BB) { + + if (BBisPrinted.find(BB) != BBisPrinted.end()) return; + + double BBWeight = PI->getExecutionCount(BB); + if (BBWeight == ProfileInfo::MissingValue) { BBWeight = 0; } + double inWeight = 0; + int inCount = 0; + std::set ProcessedPreds; + for ( pred_const_iterator bbi = pred_begin(BB), bbe = pred_end(BB); + bbi != bbe; ++bbi ) { + if (ProcessedPreds.insert(*bbi).second) { + double EdgeWeight = PI->getEdgeWeight(PI->getEdge(*bbi,BB)); + if (EdgeWeight == ProfileInfo::MissingValue) { EdgeWeight = 0; } + DEBUG(errs()<<"calculated in-edge ("<<(*bbi)->getNameStr()<<","<getNameStr() + <<"): "< ProcessedSuccs; + for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB); + bbi != bbe; ++bbi ) { + if (ProcessedSuccs.insert(*bbi).second) { + double EdgeWeight = PI->getEdgeWeight(PI->getEdge(BB,*bbi)); + if (EdgeWeight == ProfileInfo::MissingValue) { EdgeWeight = 0; } + DEBUG(errs()<<"calculated out-edge ("<getNameStr()<<","<<(*bbi)->getNameStr() + <<"): "<getNameStr()<<" in "<getParent()->getNameStr() + <<",BBWeight="<getNameStr()<<" in "<getParent()->getNameStr() + <<",BBWeight="<getParent()->getEntryBlock())); + } +} +#endif + +// compare with relative error +static bool dcmp(double A, double B) { + double maxRelativeError = 0.0000001; + if (A == B) + return true; + double relativeError; + if (fabs(B) > fabs(A)) + relativeError = fabs((A - B) / B); + else + relativeError = fabs((A - B) / A); + if (relativeError <= maxRelativeError) return true; + return false; +} + +#define CHECK(C,M) \ +if (C) { \ + if (DisableAssertions) { errs()<<(M)<<"\n"; } else { assert((!(C)) && (M)); } \ +} + +#define CHECKDEBUG(C,M,D) \ +if (C) { \ + DEBUG(debugEntry(BB, BBWeight, inWeight, inCount, \ + outWeight, outCount, (D))); \ + if (DisableAssertions) { errs()<<(M)<<"\n"; } else { assert((!(C)) && (M)); } \ +} + +void ProfileVerifierPass::recurseBasicBlock(const BasicBlock *BB) { + + if (BBisVisited.find(BB) != BBisVisited.end()) return; + + double inWeight = 0; + int inCount = 0; + std::set ProcessedPreds; + for ( pred_const_iterator bbi = pred_begin(BB), bbe = pred_end(BB); + bbi != bbe; ++bbi ) { + if (ProcessedPreds.insert(*bbi).second) { + double EdgeWeight = PI->getEdgeWeight(PI->getEdge(*bbi,BB)); + CHECK(EdgeWeight == ProfileInfo::MissingValue, + "ASSERT:Edge has missing value"); + inWeight += EdgeWeight; inCount++; + } + } + + double outWeight = 0; + int outCount = 0; + std::set ProcessedSuccs; + for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB); + bbi != bbe; ++bbi ) { + if (ProcessedSuccs.insert(*bbi).second) { + double EdgeWeight = PI->getEdgeWeight(PI->getEdge(BB,*bbi)); + CHECK(EdgeWeight == ProfileInfo::MissingValue, + "ASSERT:Edge has missing value"); + outWeight += EdgeWeight; outCount++; + } + } + + double BBWeight = PI->getExecutionCount(BB); + CHECKDEBUG(BBWeight == ProfileInfo::MissingValue, + "ASSERT:BasicBlock has missing value",-1); + + if (inCount > 0) { + CHECKDEBUG(!dcmp(inWeight,BBWeight), + "ASSERT:inWeight and BBWeight do not match",inWeight-BBWeight); + } + if (outCount > 0) { + CHECKDEBUG(!dcmp(outWeight,BBWeight), + "ASSERT:outWeight and BBWeight do not match",outWeight-BBWeight); + } + + // mark as visited and recurse into subnodes + BBisVisited.insert(BB); + for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB); + bbi != bbe; ++bbi ) { + recurseBasicBlock(*bbi); + } +} + +bool ProfileVerifierPass::runOnFunction(Function &F) { + PI = &getAnalysis(); + + if (PI->getExecutionCount(&F) == ProfileInfo::MissingValue) { + DEBUG(errs()<<"Function "<getExecutionCount(&F)==PI->getExecutionCount(entry)) && + "Function count and entry block count do not match"); + return false; +}