Searcher.cpp

Go to the documentation of this file.
00001 //===-- Searcher.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 "Searcher.h"
00013 
00014 #include "CoreStats.h"
00015 #include "Executor.h"
00016 #include "PTree.h"
00017 #include "StatsTracker.h"
00018 
00019 #include "klee/ExecutionState.h"
00020 #include "klee/Statistics.h"
00021 #include "klee/Internal/Module/InstructionInfoTable.h"
00022 #include "klee/Internal/Module/KInstruction.h"
00023 #include "klee/Internal/Module/KModule.h"
00024 #include "klee/Internal/ADT/DiscretePDF.h"
00025 #include "klee/Internal/ADT/RNG.h"
00026 #include "klee/Internal/Support/ModuleUtil.h"
00027 #include "klee/Internal/System/Time.h"
00028 
00029 #include "llvm/Constants.h"
00030 #include "llvm/Instructions.h"
00031 #include "llvm/Module.h"
00032 #include "llvm/Support/CallSite.h"
00033 #include "llvm/Support/CFG.h"
00034 #include "llvm/Support/CommandLine.h"
00035 
00036 #include <cassert>
00037 #include <fstream>
00038 #include <climits>
00039 
00040 using namespace klee;
00041 using namespace llvm;
00042 
00043 namespace {
00044   cl::opt<bool>
00045   DebugLogMerge("debug-log-merge");
00046 }
00047 
00048 namespace klee {
00049   extern RNG theRNG;
00050 }
00051 
00052 Searcher::~Searcher() {
00053 }
00054 
00056 
00057 ExecutionState &DFSSearcher::selectState() {
00058   return *states.back();
00059 }
00060 
00061 void DFSSearcher::update(ExecutionState *current,
00062                          const std::set<ExecutionState*> &addedStates,
00063                          const std::set<ExecutionState*> &removedStates) {
00064   states.insert(states.end(),
00065                 addedStates.begin(),
00066                 addedStates.end());
00067   for (std::set<ExecutionState*>::const_iterator it = removedStates.begin(),
00068          ie = removedStates.end(); it != ie; ++it) {
00069     ExecutionState *es = *it;
00070     if (es == states.back()) {
00071       states.pop_back();
00072     } else {
00073       bool ok = false;
00074 
00075       for (std::vector<ExecutionState*>::iterator it = states.begin(),
00076              ie = states.end(); it != ie; ++it) {
00077         if (es==*it) {
00078           states.erase(it);
00079           ok = true;
00080           break;
00081         }
00082       }
00083 
00084       assert(ok && "invalid state removed");
00085     }
00086   }
00087 }
00088 
00090 
00091 ExecutionState &RandomSearcher::selectState() {
00092   return *states[theRNG.getInt32()%states.size()];
00093 }
00094 
00095 void RandomSearcher::update(ExecutionState *current,
00096                             const std::set<ExecutionState*> &addedStates,
00097                             const std::set<ExecutionState*> &removedStates) {
00098   states.insert(states.end(),
00099                 addedStates.begin(),
00100                 addedStates.end());
00101   for (std::set<ExecutionState*>::const_iterator it = removedStates.begin(),
00102          ie = removedStates.end(); it != ie; ++it) {
00103     ExecutionState *es = *it;
00104     bool ok = false;
00105 
00106     for (std::vector<ExecutionState*>::iterator it = states.begin(),
00107            ie = states.end(); it != ie; ++it) {
00108       if (es==*it) {
00109         states.erase(it);
00110         ok = true;
00111         break;
00112       }
00113     }
00114     
00115     assert(ok && "invalid state removed");
00116   }
00117 }
00118 
00120 
00121 WeightedRandomSearcher::WeightedRandomSearcher(Executor &_executor,
00122                                                WeightType _type) 
00123   : executor(_executor),
00124     states(new DiscretePDF<ExecutionState*>()),
00125     type(_type) {
00126   switch(type) {
00127   case Depth: 
00128     updateWeights = false;
00129     break;
00130   case InstCount:
00131   case CPInstCount:
00132   case QueryCost:
00133   case MinDistToUncovered:
00134   case CoveringNew:
00135     updateWeights = true;
00136     break;
00137   default:
00138     assert(0 && "invalid weight type");
00139   }
00140 }
00141 
00142 WeightedRandomSearcher::~WeightedRandomSearcher() {
00143   delete states;
00144 }
00145 
00146 ExecutionState &WeightedRandomSearcher::selectState() {
00147   return *states->choose(theRNG.getDoubleL());
00148 }
00149 
00150 double WeightedRandomSearcher::getWeight(ExecutionState *es) {
00151   switch(type) {
00152   default:
00153   case Depth: 
00154     return es->weight;
00155   case InstCount: {
00156     uint64_t count = theStatisticManager->getIndexedValue(stats::instructions,
00157                                                           es->pc->info->id);
00158     double inv = 1. / std::max((uint64_t) 1, count);
00159     return inv * inv;
00160   }
00161   case CPInstCount: {
00162     StackFrame &sf = es->stack.back();
00163     uint64_t count = sf.callPathNode->statistics.getValue(stats::instructions);
00164     double inv = 1. / std::max((uint64_t) 1, count);
00165     return inv;
00166   }
00167   case QueryCost:
00168     return (es->queryCost < .1) ? 1. : 1./es->queryCost;
00169   case CoveringNew:
00170   case MinDistToUncovered: {
00171     uint64_t md2u = computeMinDistToUncovered(es->pc,
00172                                               es->stack.back().minDistToUncoveredOnReturn);
00173 
00174     double invMD2U = 1. / (md2u ? md2u : 10000);
00175     if (type==CoveringNew) {
00176       double invCovNew = 0.;
00177       if (es->instsSinceCovNew)
00178         invCovNew = 1. / std::max(1, (int) es->instsSinceCovNew - 1000);
00179       return (invCovNew * invCovNew + invMD2U * invMD2U);
00180     } else {
00181       return invMD2U * invMD2U;
00182     }
00183   }
00184   }
00185 }
00186 
00187 void WeightedRandomSearcher::update(ExecutionState *current,
00188                                     const std::set<ExecutionState*> &addedStates,
00189                                     const std::set<ExecutionState*> &removedStates) {
00190   if (current && updateWeights && !removedStates.count(current))
00191     states->update(current, getWeight(current));
00192   
00193   for (std::set<ExecutionState*>::const_iterator it = addedStates.begin(),
00194          ie = addedStates.end(); it != ie; ++it) {
00195     ExecutionState *es = *it;
00196     states->insert(es, getWeight(es));
00197   }
00198 
00199   for (std::set<ExecutionState*>::const_iterator it = removedStates.begin(),
00200          ie = removedStates.end(); it != ie; ++it) {
00201     states->remove(*it);
00202   }
00203 }
00204 
00205 bool WeightedRandomSearcher::empty() { 
00206   return states->empty(); 
00207 }
00208 
00210 
00211 RandomPathSearcher::RandomPathSearcher(Executor &_executor)
00212   : executor(_executor) {
00213 }
00214 
00215 RandomPathSearcher::~RandomPathSearcher() {
00216 }
00217 
00218 ExecutionState &RandomPathSearcher::selectState() {
00219   unsigned flips=0, bits=0;
00220   PTree::Node *n = executor.processTree->root;
00221   
00222   while (!n->data) {
00223     if (!n->left) {
00224       n = n->right;
00225     } else if (!n->right) {
00226       n = n->left;
00227     } else {
00228       if (bits==0) {
00229         flips = theRNG.getInt32();
00230         bits = 32;
00231       }
00232       --bits;
00233       n = (flips&(1<<bits)) ? n->left : n->right;
00234     }
00235   }
00236 
00237   return *n->data;
00238 }
00239 
00240 void RandomPathSearcher::update(ExecutionState *current,
00241                                 const std::set<ExecutionState*> &addedStates,
00242                                 const std::set<ExecutionState*> &removedStates) {
00243 }
00244 
00245 bool RandomPathSearcher::empty() { 
00246   return executor.states.empty(); 
00247 }
00248 
00250 
00251 BumpMergingSearcher::BumpMergingSearcher(Executor &_executor, Searcher *_baseSearcher) 
00252   : executor(_executor),
00253     baseSearcher(_baseSearcher),
00254     mergeFunction(executor.kmodule->kleeMergeFn) {
00255 }
00256 
00257 BumpMergingSearcher::~BumpMergingSearcher() {
00258   delete baseSearcher;
00259 }
00260 
00262 
00263 Instruction *BumpMergingSearcher::getMergePoint(ExecutionState &es) {  
00264   if (mergeFunction) {
00265     Instruction *i = es.pc->inst;
00266 
00267     if (i->getOpcode()==Instruction::Call) {
00268       CallSite cs(cast<CallInst>(i));
00269       if (mergeFunction==cs.getCalledFunction())
00270         return i;
00271     }
00272   }
00273 
00274   return 0;
00275 }
00276 
00277 ExecutionState &BumpMergingSearcher::selectState() {
00278 entry:
00279   // out of base states, pick one to pop
00280   if (baseSearcher->empty()) {
00281     std::map<llvm::Instruction*, ExecutionState*>::iterator it = 
00282       statesAtMerge.begin();
00283     ExecutionState *es = it->second;
00284     statesAtMerge.erase(it);
00285     ++es->pc;
00286 
00287     baseSearcher->addState(es);
00288   }
00289 
00290   ExecutionState &es = baseSearcher->selectState();
00291 
00292   if (Instruction *mp = getMergePoint(es)) {
00293     std::map<llvm::Instruction*, ExecutionState*>::iterator it = 
00294       statesAtMerge.find(mp);
00295 
00296     baseSearcher->removeState(&es);
00297 
00298     if (it==statesAtMerge.end()) {
00299       statesAtMerge.insert(std::make_pair(mp, &es));
00300     } else {
00301       ExecutionState *mergeWith = it->second;
00302       if (mergeWith->merge(es)) {
00303         // hack, because we are terminating the state we need to let
00304         // the baseSearcher know about it again
00305         baseSearcher->addState(&es);
00306         executor.terminateState(es);
00307       } else {
00308         it->second = &es; // the bump
00309         ++mergeWith->pc;
00310 
00311         baseSearcher->addState(mergeWith);
00312       }
00313     }
00314 
00315     goto entry;
00316   } else {
00317     return es;
00318   }
00319 }
00320 
00321 void BumpMergingSearcher::update(ExecutionState *current,
00322                                  const std::set<ExecutionState*> &addedStates,
00323                                  const std::set<ExecutionState*> &removedStates) {
00324   baseSearcher->update(current, addedStates, removedStates);
00325 }
00326 
00328 
00329 MergingSearcher::MergingSearcher(Executor &_executor, Searcher *_baseSearcher) 
00330   : executor(_executor),
00331     baseSearcher(_baseSearcher),
00332     mergeFunction(executor.kmodule->kleeMergeFn) {
00333 }
00334 
00335 MergingSearcher::~MergingSearcher() {
00336   delete baseSearcher;
00337 }
00338 
00340 
00341 Instruction *MergingSearcher::getMergePoint(ExecutionState &es) {
00342   if (mergeFunction) {
00343     Instruction *i = es.pc->inst;
00344 
00345     if (i->getOpcode()==Instruction::Call) {
00346       CallSite cs(cast<CallInst>(i));
00347       if (mergeFunction==cs.getCalledFunction())
00348         return i;
00349     }
00350   }
00351 
00352   return 0;
00353 }
00354 
00355 ExecutionState &MergingSearcher::selectState() {
00356   while (!baseSearcher->empty()) {
00357     ExecutionState &es = baseSearcher->selectState();
00358     if (getMergePoint(es)) {
00359       baseSearcher->removeState(&es, &es);
00360       statesAtMerge.insert(&es);
00361     } else {
00362       return es;
00363     }
00364   }
00365   
00366   // build map of merge point -> state list
00367   std::map<Instruction*, std::vector<ExecutionState*> > merges;
00368   for (std::set<ExecutionState*>::const_iterator it = statesAtMerge.begin(),
00369          ie = statesAtMerge.end(); it != ie; ++it) {
00370     ExecutionState &state = **it;
00371     Instruction *mp = getMergePoint(state);
00372     
00373     merges[mp].push_back(&state);
00374   }
00375   
00376   if (DebugLogMerge)
00377     llvm::cerr << "-- all at merge --\n";
00378   for (std::map<Instruction*, std::vector<ExecutionState*> >::iterator
00379          it = merges.begin(), ie = merges.end(); it != ie; ++it) {
00380     if (DebugLogMerge) {
00381       llvm::cerr << "\tmerge: " << it->first << " [";
00382       for (std::vector<ExecutionState*>::iterator it2 = it->second.begin(),
00383              ie2 = it->second.end(); it2 != ie2; ++it2) {
00384         ExecutionState *state = *it2;
00385         llvm::cerr << state << ", ";
00386       }
00387       llvm::cerr << "]\n";
00388     }
00389 
00390     // merge states
00391     std::set<ExecutionState*> toMerge(it->second.begin(), it->second.end());
00392     while (!toMerge.empty()) {
00393       ExecutionState *base = *toMerge.begin();
00394       toMerge.erase(toMerge.begin());
00395       
00396       std::set<ExecutionState*> toErase;
00397       for (std::set<ExecutionState*>::iterator it = toMerge.begin(),
00398              ie = toMerge.end(); it != ie; ++it) {
00399         ExecutionState *mergeWith = *it;
00400         
00401         if (base->merge(*mergeWith)) {
00402           toErase.insert(mergeWith);
00403         }
00404       }
00405       if (DebugLogMerge && !toErase.empty()) {
00406         llvm::cerr << "\t\tmerged: " << base << " with [";
00407         for (std::set<ExecutionState*>::iterator it = toErase.begin(),
00408                ie = toErase.end(); it != ie; ++it) {
00409           if (it!=toErase.begin()) llvm::cerr << ", ";
00410           llvm::cerr << *it;
00411         }
00412         llvm::cerr << "]\n";
00413       }
00414       for (std::set<ExecutionState*>::iterator it = toErase.begin(),
00415              ie = toErase.end(); it != ie; ++it) {
00416         std::set<ExecutionState*>::iterator it2 = toMerge.find(*it);
00417         assert(it2!=toMerge.end());
00418         executor.terminateState(**it);
00419         toMerge.erase(it2);
00420       }
00421 
00422       // step past merge and toss base back in pool
00423       statesAtMerge.erase(statesAtMerge.find(base));
00424       ++base->pc;
00425       baseSearcher->addState(base);
00426     }  
00427   }
00428   
00429   if (DebugLogMerge)
00430     llvm::cerr << "-- merge complete, continuing --\n";
00431   
00432   return selectState();
00433 }
00434 
00435 void MergingSearcher::update(ExecutionState *current,
00436                              const std::set<ExecutionState*> &addedStates,
00437                              const std::set<ExecutionState*> &removedStates) {
00438   if (!removedStates.empty()) {
00439     std::set<ExecutionState *> alt = removedStates;
00440     for (std::set<ExecutionState*>::const_iterator it = removedStates.begin(),
00441            ie = removedStates.end(); it != ie; ++it) {
00442       ExecutionState *es = *it;
00443       std::set<ExecutionState*>::const_iterator it = statesAtMerge.find(es);
00444       if (it!=statesAtMerge.end()) {
00445         statesAtMerge.erase(it);
00446         alt.erase(alt.find(es));
00447       }
00448     }    
00449     baseSearcher->update(current, addedStates, alt);
00450   } else {
00451     baseSearcher->update(current, addedStates, removedStates);
00452   }
00453 }
00454 
00456 
00457 BatchingSearcher::BatchingSearcher(Searcher *_baseSearcher,
00458                                    double _timeBudget,
00459                                    unsigned _instructionBudget) 
00460   : baseSearcher(_baseSearcher),
00461     timeBudget(_timeBudget),
00462     instructionBudget(_instructionBudget),
00463     lastState(0) {
00464   
00465 }
00466 
00467 BatchingSearcher::~BatchingSearcher() {
00468   delete baseSearcher;
00469 }
00470 
00471 ExecutionState &BatchingSearcher::selectState() {
00472   if (!lastState || 
00473       (util::getWallTime()-lastStartTime)>timeBudget ||
00474       (stats::instructions-lastStartInstructions)>instructionBudget) {
00475     if (lastState) {
00476       double delta = util::getWallTime()-lastStartTime;
00477       if (delta>timeBudget*1.1) {
00478         llvm::cerr << "KLEE: increased time budget from " << timeBudget << " to " << delta << "\n";
00479         timeBudget = delta;
00480       }
00481     }
00482     lastState = &baseSearcher->selectState();
00483     lastStartTime = util::getWallTime();
00484     lastStartInstructions = stats::instructions;
00485     return *lastState;
00486   } else {
00487     return *lastState;
00488   }
00489 }
00490 
00491 void BatchingSearcher::update(ExecutionState *current,
00492                               const std::set<ExecutionState*> &addedStates,
00493                               const std::set<ExecutionState*> &removedStates) {
00494   if (removedStates.count(lastState))
00495     lastState = 0;
00496   baseSearcher->update(current, addedStates, removedStates);
00497 }
00498 
00499 /***/
00500 
00501 IterativeDeepeningTimeSearcher::IterativeDeepeningTimeSearcher(Searcher *_baseSearcher)
00502   : baseSearcher(_baseSearcher),
00503     time(1.) {
00504 }
00505 
00506 IterativeDeepeningTimeSearcher::~IterativeDeepeningTimeSearcher() {
00507   delete baseSearcher;
00508 }
00509 
00510 ExecutionState &IterativeDeepeningTimeSearcher::selectState() {
00511   ExecutionState &res = baseSearcher->selectState();
00512   startTime = util::getWallTime();
00513   return res;
00514 }
00515 
00516 void IterativeDeepeningTimeSearcher::update(ExecutionState *current,
00517                                             const std::set<ExecutionState*> &addedStates,
00518                                             const std::set<ExecutionState*> &removedStates) {
00519   double elapsed = util::getWallTime() - startTime;
00520 
00521   if (!removedStates.empty()) {
00522     std::set<ExecutionState *> alt = removedStates;
00523     for (std::set<ExecutionState*>::const_iterator it = removedStates.begin(),
00524            ie = removedStates.end(); it != ie; ++it) {
00525       ExecutionState *es = *it;
00526       std::set<ExecutionState*>::const_iterator it = pausedStates.find(es);
00527       if (it!=pausedStates.end()) {
00528         pausedStates.erase(it);
00529         alt.erase(alt.find(es));
00530       }
00531     }    
00532     baseSearcher->update(current, addedStates, alt);
00533   } else {
00534     baseSearcher->update(current, addedStates, removedStates);
00535   }
00536 
00537   if (current && !removedStates.count(current) && elapsed>time) {
00538     pausedStates.insert(current);
00539     baseSearcher->removeState(current);
00540   }
00541 
00542   if (baseSearcher->empty()) {
00543     time *= 2;
00544     llvm::cerr << "KLEE: increasing time budget to: " << time << "\n";
00545     baseSearcher->update(0, pausedStates, std::set<ExecutionState*>());
00546     pausedStates.clear();
00547   }
00548 }
00549 
00550 /***/
00551 
00552 InterleavedSearcher::InterleavedSearcher(const std::vector<Searcher*> &_searchers)
00553   : searchers(_searchers),
00554     index(1) {
00555 }
00556 
00557 InterleavedSearcher::~InterleavedSearcher() {
00558   for (std::vector<Searcher*>::const_iterator it = searchers.begin(),
00559          ie = searchers.end(); it != ie; ++it)
00560     delete *it;
00561 }
00562 
00563 ExecutionState &InterleavedSearcher::selectState() {
00564   Searcher *s = searchers[--index];
00565   if (index==0) index = searchers.size();
00566   return s->selectState();
00567 }
00568 
00569 void InterleavedSearcher::update(ExecutionState *current,
00570                                  const std::set<ExecutionState*> &addedStates,
00571                                  const std::set<ExecutionState*> &removedStates) {
00572   for (std::vector<Searcher*>::const_iterator it = searchers.begin(),
00573          ie = searchers.end(); it != ie; ++it)
00574     (*it)->update(current, addedStates, removedStates);
00575 }

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