StatsTracker.cpp

Go to the documentation of this file.
00001 //===-- StatsTracker.cpp --------------------------------------------------===//
00002 //
00003 //                     The KLEE Symbolic Virtual Machine
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "Common.h"
00011 
00012 #include "StatsTracker.h"
00013 
00014 #include "klee/ExecutionState.h"
00015 #include "klee/Statistics.h"
00016 #include "klee/Internal/Module/InstructionInfoTable.h"
00017 #include "klee/Internal/Module/KModule.h"
00018 #include "klee/Internal/Module/KInstruction.h"
00019 #include "klee/Internal/Support/ModuleUtil.h"
00020 #include "klee/Internal/System/Time.h"
00021 
00022 #include "CallPathManager.h"
00023 #include "CoreStats.h"
00024 #include "Executor.h"
00025 #include "MemoryManager.h"
00026 #include "UserSearcher.h"
00027 #include "../Solver/SolverStats.h"
00028 
00029 #include "llvm/BasicBlock.h"
00030 #include "llvm/Function.h"
00031 #include "llvm/Instructions.h"
00032 #include "llvm/IntrinsicInst.h"
00033 #include "llvm/InlineAsm.h"
00034 #include "llvm/Module.h"
00035 #include "llvm/Type.h"
00036 #include "llvm/Support/CommandLine.h"
00037 #include "llvm/Support/CFG.h"
00038 #include "llvm/System/Process.h"
00039 #include "llvm/System/Path.h"
00040 
00041 #include <iostream>
00042 #include <fstream>
00043 
00044 using namespace klee;
00045 using namespace llvm;
00046 
00048 
00049 namespace {  
00050   cl::opt<bool>
00051   TrackInstructionTime("track-instruction-time",
00052                        cl::desc("Enable tracking of time for individual instructions"),
00053                        cl::init(false));
00054 
00055   cl::opt<bool>
00056   OutputStats("output-stats",
00057               cl::desc("Write running stats trace file"),
00058               cl::init(true));
00059 
00060   cl::opt<bool>
00061   OutputIStats("output-istats",
00062                cl::desc("Write instruction level statistics (in callgrind format)"),
00063                cl::init(true));
00064 
00065   cl::opt<double>
00066   StatsWriteInterval("stats-write-interval",
00067                      cl::desc("Approximate number of seconds between stats writes (default: 1.0)"),
00068                      cl::init(1.));
00069 
00070   cl::opt<double>
00071   IStatsWriteInterval("istats-write-interval",
00072                       cl::desc("Approximate number of seconds between istats writes (default: 10.0)"),
00073                       cl::init(10.));
00074 
00075   /*
00076   cl::opt<double>
00077   BranchCovCountsWriteInterval("branch-cov-counts-write-interval",
00078                      cl::desc("Approximate number of seconds between run.branches writes (default: 5.0)"),
00079                      cl::init(5.));
00080   */
00081 
00082   // XXX I really would like to have dynamic rate control for something like this.
00083   cl::opt<double>
00084   UncoveredUpdateInterval("uncovered-update-interval",
00085                           cl::init(30.));
00086   
00087   cl::opt<bool>
00088   UseCallPaths("use-call-paths",
00089                cl::desc("Enable calltree tracking for instruction level statistics"),
00090                cl::init(true));
00091   
00092 }
00093 
00095 
00096 bool StatsTracker::useStatistics() {
00097   return OutputStats || OutputIStats;
00098 }
00099 
00100 namespace klee {
00101   class WriteIStatsTimer : public Executor::Timer {
00102     StatsTracker *statsTracker;
00103     
00104   public:
00105     WriteIStatsTimer(StatsTracker *_statsTracker) : statsTracker(_statsTracker) {}
00106     ~WriteIStatsTimer() {}
00107     
00108     void run() { statsTracker->writeIStats(); }
00109   };
00110   
00111   class WriteStatsTimer : public Executor::Timer {
00112     StatsTracker *statsTracker;
00113     
00114   public:
00115     WriteStatsTimer(StatsTracker *_statsTracker) : statsTracker(_statsTracker) {}
00116     ~WriteStatsTimer() {}
00117     
00118     void run() { statsTracker->writeStatsLine(); }
00119   };
00120 
00121   class UpdateReachableTimer : public Executor::Timer {
00122     StatsTracker *statsTracker;
00123     
00124   public:
00125     UpdateReachableTimer(StatsTracker *_statsTracker) : statsTracker(_statsTracker) {}
00126     
00127     void run() { statsTracker->computeReachableUncovered(); }
00128   };
00129  
00130 }
00131 
00132 //
00133 
00138 static bool instructionIsCoverable(Instruction *i) {
00139   if (i->getOpcode() == Instruction::Unreachable) {
00140     BasicBlock *bb = i->getParent();
00141     BasicBlock::iterator it(i);
00142     if (it==bb->begin()) {
00143       return true;
00144     } else {
00145       Instruction *prev = --it;
00146       if (isa<CallInst>(prev) || isa<InvokeInst>(prev)) {
00147         Function *target = getDirectCallTarget(prev);
00148         if (target && target->doesNotReturn())
00149           return false;
00150       }
00151     }
00152   }
00153 
00154   return true;
00155 }
00156 
00157 StatsTracker::StatsTracker(Executor &_executor, std::string _objectFilename,
00158                            bool _updateMinDistToUncovered)
00159   : executor(_executor),
00160     objectFilename(_objectFilename),
00161     statsFile(0),
00162     istatsFile(0),
00163     startWallTime(util::getWallTime()),
00164     numBranches(0),
00165     fullBranches(0),
00166     partialBranches(0),
00167     updateMinDistToUncovered(_updateMinDistToUncovered) {
00168   KModule *km = executor.kmodule;
00169 
00170   sys::Path module(objectFilename);
00171   if (!sys::Path(objectFilename).isAbsolute()) {
00172     sys::Path current = sys::Path::GetCurrentDirectory();
00173     current.appendComponent(objectFilename);
00174     if (current.exists())
00175       objectFilename = current.c_str();
00176   }
00177 
00178   if (OutputIStats)
00179     theStatisticManager->useIndexedStats(km->infos->getMaxID());
00180 
00181   for (std::vector<KFunction*>::iterator it = km->functions.begin(), 
00182          ie = km->functions.end(); it != ie; ++it) {
00183     KFunction *kf = *it;
00184     kf->trackCoverage = 1;
00185 
00186     for (unsigned i=0; i<kf->numInstructions; ++i) {
00187       KInstruction *ki = kf->instructions[i];
00188 
00189       if (OutputIStats) {
00190         unsigned id = ki->info->id;
00191         theStatisticManager->setIndex(id);
00192         if (kf->trackCoverage && instructionIsCoverable(ki->inst))
00193           ++stats::uncoveredInstructions;
00194       }
00195       
00196       if (kf->trackCoverage) {
00197         if (BranchInst *bi = dyn_cast<BranchInst>(ki->inst))
00198           if (!bi->isUnconditional())
00199             numBranches++;
00200       }
00201     }
00202   }
00203 
00204   if (OutputStats) {
00205     statsFile = executor.interpreterHandler->openOutputFile("run.stats");
00206     assert(statsFile && "unable to open statistics trace file");
00207     writeStatsHeader();
00208     writeStatsLine();
00209 
00210     executor.addTimer(new WriteStatsTimer(this), StatsWriteInterval);
00211 
00212     if (updateMinDistToUncovered)
00213       executor.addTimer(new UpdateReachableTimer(this), UncoveredUpdateInterval);
00214   }
00215 
00216   if (OutputIStats) {
00217     istatsFile = executor.interpreterHandler->openOutputFile("run.istats");
00218     assert(istatsFile && "unable to open istats file");
00219 
00220     executor.addTimer(new WriteIStatsTimer(this), IStatsWriteInterval);
00221   }
00222 }
00223 
00224 StatsTracker::~StatsTracker() {  
00225   if (statsFile)
00226     delete statsFile;
00227   if (istatsFile)
00228     delete istatsFile;
00229 }
00230 
00231 void StatsTracker::done() {
00232   if (statsFile)
00233     writeStatsLine();
00234   if (OutputIStats)
00235     writeIStats();
00236 }
00237 
00238 void StatsTracker::stepInstruction(ExecutionState &es) {
00239   if (OutputIStats) {
00240     if (TrackInstructionTime) {
00241       static sys::TimeValue lastNowTime(0,0),lastUserTime(0,0);
00242     
00243       if (lastUserTime.seconds()==0 && lastUserTime.nanoseconds()==0) {
00244         sys::TimeValue sys(0,0);
00245         sys::Process::GetTimeUsage(lastNowTime,lastUserTime,sys);
00246       } else {
00247         sys::TimeValue now(0,0),user(0,0),sys(0,0);
00248         sys::Process::GetTimeUsage(now,user,sys);
00249         sys::TimeValue delta = user - lastUserTime;
00250         sys::TimeValue deltaNow = now - lastNowTime;
00251         stats::instructionTime += delta.usec();
00252         stats::instructionRealTime += deltaNow.usec();
00253         lastUserTime = user;
00254         lastNowTime = now;
00255       }
00256     }
00257 
00258     Instruction *inst = es.pc->inst;
00259     const InstructionInfo &ii = *es.pc->info;
00260     StackFrame &sf = es.stack.back();
00261     theStatisticManager->setIndex(ii.id);
00262     if (UseCallPaths)
00263       theStatisticManager->setContext(&sf.callPathNode->statistics);
00264 
00265     if (es.instsSinceCovNew)
00266       ++es.instsSinceCovNew;
00267 
00268     if (sf.kf->trackCoverage && instructionIsCoverable(inst)) {
00269       if (!theStatisticManager->getIndexedValue(stats::coveredInstructions, ii.id)) {
00270         // Checking for actual stoppoints avoids inconsistencies due
00271         // to line number propogation.
00272         if (isa<DbgStopPointInst>(inst))
00273           es.coveredLines[&ii.file].insert(ii.line);
00274         es.coveredNew = true;
00275         es.instsSinceCovNew = 1;
00276         ++stats::coveredInstructions;
00277         stats::uncoveredInstructions += (uint64_t)-1;
00278       }
00279     }
00280   }
00281 }
00282 
00284 
00285 /* Should be called _after_ the es->pushFrame() */
00286 void StatsTracker::framePushed(ExecutionState &es, StackFrame *parentFrame) {
00287   if (OutputIStats) {
00288     StackFrame &sf = es.stack.back();
00289 
00290     if (UseCallPaths) {
00291       CallPathNode *parent = parentFrame ? parentFrame->callPathNode : 0;
00292       CallPathNode *cp = callPathManager.getCallPath(parent, 
00293                                                      sf.caller ? sf.caller->inst : 0, 
00294                                                      sf.kf->function);
00295       sf.callPathNode = cp;
00296       cp->count++;
00297     }
00298 
00299     if (updateMinDistToUncovered) {
00300       uint64_t minDistAtRA = 0;
00301       if (parentFrame)
00302         minDistAtRA = parentFrame->minDistToUncoveredOnReturn;
00303       
00304       sf.minDistToUncoveredOnReturn = sf.caller ?
00305         computeMinDistToUncovered(sf.caller, minDistAtRA) : 0;
00306     }
00307   }
00308 }
00309 
00310 /* Should be called _after_ the es->popFrame() */
00311 void StatsTracker::framePopped(ExecutionState &es) {
00312   // XXX remove me?
00313 }
00314 
00315 
00316 void StatsTracker::markBranchVisited(ExecutionState *visitedTrue, 
00317                                      ExecutionState *visitedFalse) {
00318   if (OutputIStats) {
00319     unsigned id = theStatisticManager->getIndex();
00320     uint64_t hasTrue = theStatisticManager->getIndexedValue(stats::trueBranches, id);
00321     uint64_t hasFalse = theStatisticManager->getIndexedValue(stats::falseBranches, id);
00322     if (visitedTrue && !hasTrue) {
00323       visitedTrue->coveredNew = true;
00324       visitedTrue->instsSinceCovNew = 1;
00325       ++stats::trueBranches;
00326       if (hasFalse) { ++fullBranches; --partialBranches; }
00327       else ++partialBranches;
00328       hasTrue = 1;
00329     }
00330     if (visitedFalse && !hasFalse) {
00331       visitedFalse->coveredNew = true;
00332       visitedFalse->instsSinceCovNew = 1;
00333       ++stats::falseBranches;
00334       if (hasTrue) { ++fullBranches; --partialBranches; }
00335       else ++partialBranches;
00336     }
00337   }
00338 }
00339 
00340 void StatsTracker::writeStatsHeader() {
00341   *statsFile << "('Instructions',"
00342              << "'FullBranches',"
00343              << "'PartialBranches',"
00344              << "'NumBranches',"
00345              << "'UserTime',"
00346              << "'NumStates',"
00347              << "'MallocUsage',"
00348              << "'NumQueries',"
00349              << "'NumQueryConstructs',"
00350              << "'NumObjects',"
00351              << "'WallTime',"
00352              << "'CoveredInstructions',"
00353              << "'UncoveredInstructions',"
00354              << "'QueryTime',"
00355              << "'SolverTime',"
00356              << "'CexCacheTime',"
00357              << "'ForkTime',"
00358              << "'ResolveTime',"
00359              << ")\n";
00360   statsFile->flush();
00361 }
00362 
00363 double StatsTracker::elapsed() {
00364   return util::getWallTime() - startWallTime;
00365 }
00366 
00367 void StatsTracker::writeStatsLine() {
00368   *statsFile << "(" << stats::instructions
00369              << "," << fullBranches
00370              << "," << partialBranches
00371              << "," << numBranches
00372              << "," << util::getUserTime()
00373              << "," << executor.states.size()
00374              << "," << sys::Process::GetTotalMemoryUsage()
00375              << "," << stats::queries
00376              << "," << stats::queryConstructs
00377              << "," << 0 // was numObjects
00378              << "," << elapsed()
00379              << "," << stats::coveredInstructions
00380              << "," << stats::uncoveredInstructions
00381              << "," << stats::queryTime / 1000000.
00382              << "," << stats::solverTime / 1000000.
00383              << "," << stats::cexCacheTime / 1000000.
00384              << "," << stats::forkTime / 1000000.
00385              << "," << stats::resolveTime / 1000000.
00386              << ")\n";
00387   statsFile->flush();
00388 }
00389 
00390 void StatsTracker::updateStateStatistics(uint64_t addend) {
00391   for (std::set<ExecutionState*>::iterator it = executor.states.begin(),
00392          ie = executor.states.end(); it != ie; ++it) {
00393     ExecutionState &state = **it;
00394     const InstructionInfo &ii = *state.pc->info;
00395     theStatisticManager->incrementIndexedValue(stats::states, ii.id, addend);
00396     if (UseCallPaths)
00397       state.stack.back().callPathNode->statistics.incrementValue(stats::states, addend);
00398   }
00399 }
00400 
00401 void StatsTracker::writeIStats() {
00402   Module *m = executor.kmodule->module;
00403   uint64_t istatsMask = 0;
00404   std::ostream &of = *istatsFile;
00405   
00406   of.seekp(0, std::ios::end);
00407   unsigned istatsSize = of.tellp();
00408   of.seekp(0);
00409 
00410   of << "version: 1\n";
00411   of << "creator: klee\n";
00412   of << "pid: " << sys::Process::GetCurrentUserId() << "\n";
00413   of << "cmd: " << m->getModuleIdentifier() << "\n\n";
00414   of << "\n";
00415   
00416   StatisticManager &sm = *theStatisticManager;
00417   unsigned nStats = sm.getNumStatistics();
00418 
00419   // Max is 13, sadly
00420   istatsMask |= 1<<sm.getStatisticID("Queries");
00421   istatsMask |= 1<<sm.getStatisticID("QueriesValid");
00422   istatsMask |= 1<<sm.getStatisticID("QueriesInvalid");
00423   istatsMask |= 1<<sm.getStatisticID("QueryTime");
00424   istatsMask |= 1<<sm.getStatisticID("ResolveTime");
00425   istatsMask |= 1<<sm.getStatisticID("Instructions");
00426   istatsMask |= 1<<sm.getStatisticID("InstructionTimes");
00427   istatsMask |= 1<<sm.getStatisticID("InstructionRealTimes");
00428   istatsMask |= 1<<sm.getStatisticID("Forks");
00429   istatsMask |= 1<<sm.getStatisticID("CoveredInstructions");
00430   istatsMask |= 1<<sm.getStatisticID("UncoveredInstructions");
00431   istatsMask |= 1<<sm.getStatisticID("States");
00432   istatsMask |= 1<<sm.getStatisticID("MinDistToUncovered");
00433 
00434   of << "positions: instr line\n";
00435 
00436   for (unsigned i=0; i<nStats; i++) {
00437     if (istatsMask & (1<<i)) {
00438       Statistic &s = sm.getStatistic(i);
00439       of << "event: " << s.getShortName() << " : " 
00440          << s.getName() << "\n";
00441     }
00442   }
00443 
00444   of << "events: ";
00445   for (unsigned i=0; i<nStats; i++) {
00446     if (istatsMask & (1<<i))
00447       of << sm.getStatistic(i).getShortName() << " ";
00448   }
00449   of << "\n";
00450   
00451   // set state counts, decremented after we process so that we don't
00452   // have to zero all records each time.
00453   if (istatsMask & (1<<stats::states.getID()))
00454     updateStateStatistics(1);
00455 
00456   std::string sourceFile = "";
00457 
00458   CallSiteSummaryTable callSiteStats;
00459   if (UseCallPaths)
00460     callPathManager.getSummaryStatistics(callSiteStats);
00461 
00462   of << "ob=" << objectFilename << "\n";
00463 
00464   for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); 
00465        fnIt != fn_ie; ++fnIt) {
00466     if (!fnIt->isDeclaration()) {
00467       of << "fn=" << fnIt->getName() << "\n";
00468       for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); 
00469            bbIt != bb_ie; ++bbIt) {
00470         for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); 
00471              it != ie; ++it) {
00472           Instruction *instr = &*it;
00473           const InstructionInfo &ii = executor.kmodule->infos->getInfo(instr);
00474           unsigned index = ii.id;
00475           if (ii.file!=sourceFile) {
00476             of << "fl=" << ii.file << "\n";
00477             sourceFile = ii.file;
00478           }
00479           of << ii.assemblyLine << " ";
00480           of << ii.line << " ";
00481           for (unsigned i=0; i<nStats; i++)
00482             if (istatsMask&(1<<i))
00483               of << sm.getIndexedValue(sm.getStatistic(i), index) << " ";
00484           of << "\n";
00485 
00486           if (UseCallPaths && 
00487               (isa<CallInst>(instr) || isa<InvokeInst>(instr))) {
00488             CallSiteSummaryTable::iterator it = callSiteStats.find(instr);
00489             if (it!=callSiteStats.end()) {
00490               for (std::map<llvm::Function*, CallSiteInfo>::iterator
00491                      fit = it->second.begin(), fie = it->second.end(); 
00492                    fit != fie; ++fit) {
00493                 Function *f = fit->first;
00494                 CallSiteInfo &csi = fit->second;
00495                 const InstructionInfo &fii = 
00496                   executor.kmodule->infos->getFunctionInfo(f);
00497   
00498                 if (fii.file!="" && fii.file!=sourceFile)
00499                   of << "cfl=" << fii.file << "\n";
00500                 of << "cfn=" << f->getName() << "\n";
00501                 of << "calls=" << csi.count << " ";
00502                 of << fii.assemblyLine << " ";
00503                 of << fii.line << "\n";
00504 
00505                 of << ii.assemblyLine << " ";
00506                 of << ii.line << " ";
00507                 for (unsigned i=0; i<nStats; i++) {
00508                   if (istatsMask&(1<<i)) {
00509                     Statistic &s = sm.getStatistic(i);
00510                     uint64_t value;
00511 
00512                     // Hack, ignore things that don't make sense on
00513                     // call paths.
00514                     if (&s == &stats::uncoveredInstructions) {
00515                       value = 0;
00516                     } else {
00517                       value = csi.statistics.getValue(s);
00518                     }
00519 
00520                     of << value << " ";
00521                   }
00522                 }
00523                 of << "\n";
00524               }
00525             }
00526           }
00527         }
00528       }
00529     }
00530   }
00531 
00532   if (istatsMask & (1<<stats::states.getID()))
00533     updateStateStatistics((uint64_t)-1);
00534   
00535   // Clear then end of the file if necessary (no truncate op?).
00536   unsigned pos = of.tellp();
00537   for (unsigned i=pos; i<istatsSize; ++i)
00538     of << '\n';
00539   
00540   of.flush();
00541 }
00542 
00544 
00545 typedef std::map<Instruction*, std::vector<Function*> > calltargets_ty;
00546 
00547 static calltargets_ty callTargets;
00548 static std::map<Function*, std::vector<Instruction*> > functionCallers;
00549 static std::map<Function*, unsigned> functionShortestPath;
00550 
00551 static std::vector<Instruction*> getSuccs(Instruction *i) {
00552   BasicBlock *bb = i->getParent();
00553   std::vector<Instruction*> res;
00554 
00555   if (i==bb->getTerminator()) {
00556     for (succ_iterator it = succ_begin(bb), ie = succ_end(bb); it != ie; ++it)
00557       res.push_back(it->begin());
00558   } else {
00559     res.push_back(++BasicBlock::iterator(i));
00560   }
00561 
00562   return res;
00563 }
00564 
00565 uint64_t klee::computeMinDistToUncovered(const KInstruction *ki,
00566                                          uint64_t minDistAtRA) {
00567   StatisticManager &sm = *theStatisticManager;
00568   if (minDistAtRA==0) { // unreachable on return, best is local
00569     return sm.getIndexedValue(stats::minDistToUncovered,
00570                               ki->info->id);
00571   } else {
00572     uint64_t minDistLocal = sm.getIndexedValue(stats::minDistToUncovered,
00573                                                ki->info->id);
00574     uint64_t distToReturn = sm.getIndexedValue(stats::minDistToReturn,
00575                                                ki->info->id);
00576 
00577     if (distToReturn==0) { // return unreachable, best is local
00578       return minDistLocal;
00579     } else if (!minDistLocal) { // no local reachable
00580       return distToReturn + minDistAtRA;
00581     } else {
00582       return std::min(minDistLocal, distToReturn + minDistAtRA);
00583     }
00584   }
00585 }
00586 
00587 void StatsTracker::computeReachableUncovered() {
00588   KModule *km = executor.kmodule;
00589   Module *m = km->module;
00590   static bool init = true;
00591   const InstructionInfoTable &infos = *km->infos;
00592   StatisticManager &sm = *theStatisticManager;
00593   
00594   if (init) {
00595     init = false;
00596 
00597     // Compute call targets. It would be nice to use alias information
00598     // instead of assuming all indirect calls hit all escaping
00599     // functions, eh?
00600     for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); 
00601          fnIt != fn_ie; ++fnIt) {
00602       for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); 
00603            bbIt != bb_ie; ++bbIt) {
00604         for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); 
00605              it != it; ++it) {
00606           if (isa<CallInst>(it) || isa<InvokeInst>(it)) {
00607             if (isa<InlineAsm>(it->getOperand(0))) {
00608               // We can never call through here so assume no targets
00609               // (which should be correct anyhow).
00610               callTargets.insert(std::make_pair(it,
00611                                                 std::vector<Function*>()));
00612             } else if (Function *target = getDirectCallTarget(it)) {
00613               callTargets[it].push_back(target);
00614             } else {
00615               callTargets[it] = 
00616                 std::vector<Function*>(km->escapingFunctions.begin(),
00617                                        km->escapingFunctions.end());
00618             }
00619           }
00620         }
00621       }
00622     }
00623 
00624     // Compute function callers as reflexion of callTargets.
00625     for (calltargets_ty::iterator it = callTargets.begin(), 
00626            ie = callTargets.end(); it != ie; ++it)
00627       for (std::vector<Function*>::iterator fit = it->second.begin(), 
00628              fie = it->second.end(); fit != fie; ++fit) 
00629         functionCallers[*fit].push_back(it->first);
00630 
00631     // Initialize minDistToReturn to shortest paths through
00632     // functions. 0 is unreachable.
00633     std::vector<Instruction *> instructions;
00634     for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); 
00635          fnIt != fn_ie; ++fnIt) {
00636       if (fnIt->isDeclaration()) {
00637         if (fnIt->doesNotReturn()) {
00638           functionShortestPath[fnIt] = 0;
00639         } else {
00640           functionShortestPath[fnIt] = 1; // whatever
00641         }
00642       } else {
00643         functionShortestPath[fnIt] = 0;
00644       }
00645 
00646       // Not sure if I should bother to preorder here. XXX I should.
00647       for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); 
00648            bbIt != bb_ie; ++bbIt) {
00649         for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); 
00650              it != it; ++it) {
00651           instructions.push_back(it);
00652           unsigned id = infos.getInfo(it).id;
00653           sm.setIndexedValue(stats::minDistToReturn, 
00654                              id, 
00655                              isa<ReturnInst>(it) || isa<UnwindInst>(it));
00656         }
00657       }
00658     }
00659   
00660     std::reverse(instructions.begin(), instructions.end());
00661     
00662     // I'm so lazy it's not even worklisted.
00663     bool changed;
00664     do {
00665       changed = false;
00666       for (std::vector<Instruction*>::iterator it = instructions.begin(),
00667              ie = instructions.end(); it != ie; ++it) {
00668         Instruction *inst = *it;
00669         unsigned bestThrough = 0;
00670 
00671         if (isa<CallInst>(inst) || isa<InvokeInst>(inst)) {
00672           std::vector<Function*> &targets = callTargets[inst];
00673           for (std::vector<Function*>::iterator fnIt = targets.begin(),
00674                  ie = targets.end(); fnIt != ie; ++fnIt) {
00675             uint64_t dist = functionShortestPath[*fnIt];
00676             if (dist) {
00677               dist = 1+dist; // count instruction itself
00678               if (bestThrough==0 || dist<bestThrough)
00679                 bestThrough = dist;
00680             }
00681           }
00682         } else {
00683           bestThrough = 1;
00684         }
00685        
00686         if (bestThrough) {
00687           unsigned id = infos.getInfo(*it).id;
00688           uint64_t best, cur = best = sm.getIndexedValue(stats::minDistToReturn, id);
00689           std::vector<Instruction*> succs = getSuccs(*it);
00690           for (std::vector<Instruction*>::iterator it2 = succs.begin(),
00691                  ie = succs.end(); it2 != ie; ++it2) {
00692             uint64_t dist = sm.getIndexedValue(stats::minDistToReturn,
00693                                                infos.getInfo(*it2).id);
00694             if (dist) {
00695               uint64_t val = bestThrough + dist;
00696               if (best==0 || val<best)
00697                 best = val;
00698             }
00699           }
00700           if (best != cur) {
00701             sm.setIndexedValue(stats::minDistToReturn, id, best);
00702             changed = true;
00703 
00704             // Update shortest path if this is the entry point.
00705             Function *f = inst->getParent()->getParent();
00706             if (inst==f->begin()->begin())
00707               functionShortestPath[f] = best;
00708           }
00709         }
00710       }
00711     } while (changed);
00712   }
00713 
00714   // compute minDistToUncovered, 0 is unreachable
00715   std::vector<Instruction *> instructions;
00716   for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); 
00717        fnIt != fn_ie; ++fnIt) {
00718     // Not sure if I should bother to preorder here.
00719     for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); 
00720          bbIt != bb_ie; ++bbIt) {
00721       for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); 
00722            it != it; ++it) {
00723         unsigned id = infos.getInfo(it).id;
00724         instructions.push_back(&*it);
00725         sm.setIndexedValue(stats::minDistToUncovered, 
00726                            id, 
00727                            sm.getIndexedValue(stats::uncoveredInstructions, id));
00728       }
00729     }
00730   }
00731   
00732   std::reverse(instructions.begin(), instructions.end());
00733   
00734   // I'm so lazy it's not even worklisted.
00735   bool changed;
00736   do {
00737     changed = false;
00738     for (std::vector<Instruction*>::iterator it = instructions.begin(),
00739            ie = instructions.end(); it != ie; ++it) {
00740       Instruction *inst = *it;
00741       uint64_t best, cur = best = sm.getIndexedValue(stats::minDistToUncovered, 
00742                                                      infos.getInfo(inst).id);
00743       unsigned bestThrough = 0;
00744       
00745       if (isa<CallInst>(inst) || isa<InvokeInst>(inst)) {
00746         std::vector<Function*> &targets = callTargets[inst];
00747         for (std::vector<Function*>::iterator fnIt = targets.begin(),
00748                ie = targets.end(); fnIt != ie; ++fnIt) {
00749           uint64_t dist = functionShortestPath[*fnIt];
00750           if (dist) {
00751             dist = 1+dist; // count instruction itself
00752             if (bestThrough==0 || dist<bestThrough)
00753               bestThrough = dist;
00754           }
00755 
00756           if (!(*fnIt)->isDeclaration()) {
00757             uint64_t calleeDist = sm.getIndexedValue(stats::minDistToUncovered,
00758                                                      infos.getFunctionInfo(*fnIt).id);
00759             if (calleeDist) {
00760               calleeDist = 1+calleeDist; // count instruction itself
00761               if (best==0 || calleeDist<best)
00762                 best = calleeDist;
00763             }
00764           }
00765         }
00766       } else {
00767         bestThrough = 1;
00768       }
00769       
00770       if (bestThrough) {
00771         std::vector<Instruction*> succs = getSuccs(inst);
00772         for (std::vector<Instruction*>::iterator it2 = succs.begin(),
00773                ie = succs.end(); it2 != ie; ++it2) {
00774           uint64_t dist = sm.getIndexedValue(stats::minDistToUncovered,
00775                                              infos.getInfo(*it2).id);
00776           if (dist) {
00777             uint64_t val = bestThrough + dist;
00778             if (best==0 || val<best)
00779               best = val;
00780           }
00781         }
00782       }
00783 
00784       if (best != cur) {
00785         sm.setIndexedValue(stats::minDistToUncovered, 
00786                            infos.getInfo(inst).id, 
00787                            best);
00788         changed = true;
00789       }
00790     }
00791   } while (changed);
00792 
00793   for (std::set<ExecutionState*>::iterator it = executor.states.begin(),
00794          ie = executor.states.end(); it != ie; ++it) {
00795     ExecutionState *es = *it;
00796     uint64_t currentFrameMinDist = 0;
00797     for (ExecutionState::stack_ty::iterator sfIt = es->stack.begin(),
00798            sf_ie = es->stack.end(); sfIt != sf_ie; ++sfIt) {
00799       ExecutionState::stack_ty::iterator next = sfIt + 1;
00800       KInstIterator kii;
00801 
00802       if (next==es->stack.end()) {
00803         kii = es->pc;
00804       } else {
00805         kii = next->caller;
00806         ++kii;
00807       }
00808       
00809       sfIt->minDistToUncoveredOnReturn = currentFrameMinDist;
00810       
00811       currentFrameMinDist = computeMinDistToUncovered(kii, currentFrameMinDist);
00812     }
00813   }
00814 }

Generated on Fri Jun 5 03:31:32 2009 for klee by  doxygen 1.5.8