ProfileVerifierPass.cpp revision e7ddcfdebe357b4067f9c7d68d44616e11351a23
1//===- ProfileVerifierPass.cpp - LLVM Pass to estimate profile info -------===//
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// This file implements a pass that checks profiling information for
11// plausibility.
12//
13//===----------------------------------------------------------------------===//
14#define DEBUG_TYPE "profile-verifier"
15#include "llvm/Pass.h"
16#include "llvm/Analysis/ProfileInfo.h"
17#include "llvm/Support/CommandLine.h"
18#include "llvm/Support/CFG.h"
19#include "llvm/Support/raw_ostream.h"
20#include "llvm/Support/Debug.h"
21#include <set>
22using namespace llvm;
23
24static bool DisableAssertions = false;
25static cl::opt<bool,true>
26ProfileVerifierDisableAssertions("profile-verifier-noassert",
27    cl::location(DisableAssertions), cl::desc("Disable assertions"));
28bool PrintedDebugTree = false;
29
30namespace {
31  class VISIBILITY_HIDDEN ProfileVerifierPass : public FunctionPass {
32    ProfileInfo *PI;
33    std::set<const BasicBlock*> BBisVisited;
34#ifndef NDEBUG
35    std::set<const BasicBlock*> BBisPrinted;
36    void debugEntry(const BasicBlock* BB, double w, double inw, int inc,
37                    double outw, int outc, double d);
38    void printDebugInfo(const BasicBlock *BB);
39#endif
40  public:
41    static char ID; // Class identification, replacement for typeinfo
42
43    explicit ProfileVerifierPass () : FunctionPass(&ID) {
44      DisableAssertions = ProfileVerifierDisableAssertions;
45    }
46
47    void getAnalysisUsage(AnalysisUsage &AU) const {
48      AU.setPreservesAll();
49      AU.addRequired<ProfileInfo>();
50    }
51
52    const char *getPassName() const {
53      return "Profiling information verifier";
54    }
55
56    /// run - Verify the profile information.
57    bool runOnFunction(Function &F);
58    void recurseBasicBlock(const BasicBlock *BB);
59  };
60}  // End of anonymous namespace
61
62char ProfileVerifierPass::ID = 0;
63static RegisterPass<ProfileVerifierPass>
64X("profile-verifier", "Verify profiling information", false, true);
65
66namespace llvm {
67  FunctionPass *createProfileVerifierPass() {
68    return new ProfileVerifierPass();
69  }
70}
71
72#ifndef NDEBUG
73void ProfileVerifierPass::printDebugInfo(const BasicBlock *BB) {
74
75  if (BBisPrinted.find(BB) != BBisPrinted.end()) return;
76
77  double BBWeight = PI->getExecutionCount(BB);
78  if (BBWeight == ProfileInfo::MissingValue) { BBWeight = 0; }
79  double inWeight = 0;
80  int inCount = 0;
81  std::set<const BasicBlock*> ProcessedPreds;
82  for ( pred_const_iterator bbi = pred_begin(BB), bbe = pred_end(BB);
83        bbi != bbe; ++bbi ) {
84    if (ProcessedPreds.insert(*bbi).second) {
85      double EdgeWeight = PI->getEdgeWeight(PI->getEdge(*bbi,BB));
86      if (EdgeWeight == ProfileInfo::MissingValue) { EdgeWeight = 0; }
87      DEBUG(errs()<<"calculated in-edge ("<<(*bbi)->getNameStr()<<","<<BB->getNameStr()
88          <<"): "<<EdgeWeight<<"\n");
89      inWeight += EdgeWeight;
90      inCount++;
91    }
92  }
93  double outWeight = 0;
94  int outCount = 0;
95  std::set<const BasicBlock*> ProcessedSuccs;
96  for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
97        bbi != bbe; ++bbi ) {
98    if (ProcessedSuccs.insert(*bbi).second) {
99      double EdgeWeight = PI->getEdgeWeight(PI->getEdge(BB,*bbi));
100      if (EdgeWeight == ProfileInfo::MissingValue) { EdgeWeight = 0; }
101      DEBUG(errs()<<"calculated out-edge ("<<BB->getNameStr()<<","<<(*bbi)->getNameStr()
102          <<"): "<<EdgeWeight<<"\n");
103      outWeight += EdgeWeight;
104      outCount++;
105    }
106  }
107  DEBUG(errs()<<"Block "<<BB->getNameStr()<<" in "<<BB->getParent()->getNameStr()
108      <<",BBWeight="<<BBWeight<<",inWeight="<<inWeight<<",inCount="<<inCount
109      <<",outWeight="<<outWeight<<",outCount"<<outCount<<"\n");
110
111  // mark as visited and recurse into subnodes
112  BBisPrinted.insert(BB);
113  for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
114        bbi != bbe; ++bbi ) {
115    printDebugInfo(*bbi);
116  }
117}
118
119void ProfileVerifierPass::debugEntry (const BasicBlock* BB, double w,
120                                      double inw,  int inc, double outw, int
121                                      outc, double d) {
122  DEBUG(errs()<<"TROUBLE: Block "<<BB->getNameStr()<<" in "<<BB->getParent()->getNameStr()
123      <<",BBWeight="<<w<<",inWeight="<<inw<<",inCount="<<inc<<",outWeight="
124      <<outw<<",outCount"<<outc<<"\n");
125  DEBUG(errs()<<"DELTA:"<<d<<"\n");
126  if (!PrintedDebugTree) {
127    PrintedDebugTree = true;
128    printDebugInfo(&(BB->getParent()->getEntryBlock()));
129  }
130}
131#endif
132
133// compare with relative error
134static bool dcmp(double A, double B) {
135  double maxRelativeError = 0.0000001;
136  if (A == B)
137    return true;
138  double relativeError;
139  if (fabs(B) > fabs(A))
140    relativeError = fabs((A - B) / B);
141  else
142    relativeError = fabs((A - B) / A);
143  if (relativeError <= maxRelativeError) return true;
144  return false;
145}
146
147#define CHECK(C,M) \
148if (C) { \
149  if (DisableAssertions) { errs()<<(M)<<"\n"; } else { assert((!(C)) && (M)); } \
150}
151
152#define CHECKDEBUG(C,M,D) \
153if (C) { \
154  DEBUG(debugEntry(BB, BBWeight, inWeight,  inCount, \
155                                 outWeight, outCount, (D))); \
156  if (DisableAssertions) { errs()<<(M)<<"\n"; } else { assert((!(C)) && (M)); } \
157}
158
159void ProfileVerifierPass::recurseBasicBlock(const BasicBlock *BB) {
160
161  if (BBisVisited.find(BB) != BBisVisited.end()) return;
162
163  double inWeight = 0;
164  int inCount = 0;
165  std::set<const BasicBlock*> ProcessedPreds;
166  for ( pred_const_iterator bbi = pred_begin(BB), bbe = pred_end(BB);
167        bbi != bbe; ++bbi ) {
168    if (ProcessedPreds.insert(*bbi).second) {
169      double EdgeWeight = PI->getEdgeWeight(PI->getEdge(*bbi,BB));
170      CHECK(EdgeWeight == ProfileInfo::MissingValue,
171            "ASSERT:Edge has missing value");
172      inWeight += EdgeWeight; inCount++;
173    }
174  }
175
176  double outWeight = 0;
177  int outCount = 0;
178  std::set<const BasicBlock*> ProcessedSuccs;
179  for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
180        bbi != bbe; ++bbi ) {
181    if (ProcessedSuccs.insert(*bbi).second) {
182      double EdgeWeight = PI->getEdgeWeight(PI->getEdge(BB,*bbi));
183      CHECK(EdgeWeight == ProfileInfo::MissingValue,
184            "ASSERT:Edge has missing value");
185      outWeight += EdgeWeight; outCount++;
186    }
187  }
188
189  double BBWeight = PI->getExecutionCount(BB);
190  CHECKDEBUG(BBWeight == ProfileInfo::MissingValue,
191             "ASSERT:BasicBlock has missing value",-1);
192
193  if (inCount > 0) {
194    CHECKDEBUG(!dcmp(inWeight,BBWeight),
195        "ASSERT:inWeight and BBWeight do not match",inWeight-BBWeight);
196  }
197  if (outCount > 0) {
198    CHECKDEBUG(!dcmp(outWeight,BBWeight),
199        "ASSERT:outWeight and BBWeight do not match",outWeight-BBWeight);
200  }
201
202  // mark as visited and recurse into subnodes
203  BBisVisited.insert(BB);
204  for ( succ_const_iterator bbi = succ_begin(BB), bbe = succ_end(BB);
205        bbi != bbe; ++bbi ) {
206    recurseBasicBlock(*bbi);
207  }
208}
209
210bool ProfileVerifierPass::runOnFunction(Function &F) {
211  PI = &getAnalysis<ProfileInfo>();
212
213  if (PI->getExecutionCount(&F) == ProfileInfo::MissingValue) {
214    DEBUG(errs()<<"Function "<<F.getNameStr()<<" has no profile\n");
215    return false;
216  }
217
218  PrintedDebugTree = false;
219  BBisVisited.clear();
220
221  const BasicBlock *entry = &F.getEntryBlock();
222  recurseBasicBlock(entry);
223
224  if (!DisableAssertions)
225    assert((PI->getExecutionCount(&F)==PI->getExecutionCount(entry)) &&
226           "Function count and entry block count do not match");
227  return false;
228}
229