void StatsTracker::writeIStats() { Module *m = executor.kmodule->module; uint64_t istatsMask = 0; llvm::raw_fd_ostream &of = *istatsFile; // We assume that we didn't move the file pointer unsigned istatsSize = of.tell(); of.seek(0); of << "version: 1\n"; of << "creator: klee\n"; of << "pid: " << getpid() << "\n"; of << "cmd: " << m->getModuleIdentifier() << "\n\n"; of << "\n"; StatisticManager &sm = *theStatisticManager; unsigned nStats = sm.getNumStatistics(); // Max is 13, sadly istatsMask |= 1<<sm.getStatisticID("Queries"); istatsMask |= 1<<sm.getStatisticID("QueriesValid"); istatsMask |= 1<<sm.getStatisticID("QueriesInvalid"); istatsMask |= 1<<sm.getStatisticID("QueryTime"); istatsMask |= 1<<sm.getStatisticID("ResolveTime"); istatsMask |= 1<<sm.getStatisticID("Instructions"); istatsMask |= 1<<sm.getStatisticID("InstructionTimes"); istatsMask |= 1<<sm.getStatisticID("InstructionRealTimes"); istatsMask |= 1<<sm.getStatisticID("Forks"); istatsMask |= 1<<sm.getStatisticID("CoveredInstructions"); istatsMask |= 1<<sm.getStatisticID("UncoveredInstructions"); istatsMask |= 1<<sm.getStatisticID("States"); istatsMask |= 1<<sm.getStatisticID("MinDistToUncovered"); of << "positions: instr line\n"; for (unsigned i=0; i<nStats; i++) { if (istatsMask & (1<<i)) { Statistic &s = sm.getStatistic(i); of << "event: " << s.getShortName() << " : " << s.getName() << "\n"; } } of << "events: "; for (unsigned i=0; i<nStats; i++) { if (istatsMask & (1<<i)) of << sm.getStatistic(i).getShortName() << " "; } of << "\n"; // set state counts, decremented after we process so that we don't // have to zero all records each time. if (istatsMask & (1<<stats::states.getID())) updateStateStatistics(1); std::string sourceFile = ""; CallSiteSummaryTable callSiteStats; if (UseCallPaths) callPathManager.getSummaryStatistics(callSiteStats); of << "ob=" << objectFilename << "\n"; for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); fnIt != fn_ie; ++fnIt) { if (!fnIt->isDeclaration()) { // Always try to write the filename before the function name, as otherwise // KCachegrind can create two entries for the function, one with an // unnamed file and one without. const InstructionInfo &ii = executor.kmodule->infos->getFunctionInfo(fnIt); if (ii.file != sourceFile) { of << "fl=" << ii.file << "\n"; sourceFile = ii.file; } of << "fn=" << fnIt->getName().str() << "\n"; for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); bbIt != bb_ie; ++bbIt) { for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); it != ie; ++it) { Instruction *instr = &*it; const InstructionInfo &ii = executor.kmodule->infos->getInfo(instr); unsigned index = ii.id; if (ii.file!=sourceFile) { of << "fl=" << ii.file << "\n"; sourceFile = ii.file; } of << ii.assemblyLine << " "; of << ii.line << " "; for (unsigned i=0; i<nStats; i++) if (istatsMask&(1<<i)) of << sm.getIndexedValue(sm.getStatistic(i), index) << " "; of << "\n"; if (UseCallPaths && (isa<CallInst>(instr) || isa<InvokeInst>(instr))) { CallSiteSummaryTable::iterator it = callSiteStats.find(instr); if (it!=callSiteStats.end()) { for (std::map<llvm::Function*, CallSiteInfo>::iterator fit = it->second.begin(), fie = it->second.end(); fit != fie; ++fit) { Function *f = fit->first; CallSiteInfo &csi = fit->second; const InstructionInfo &fii = executor.kmodule->infos->getFunctionInfo(f); if (fii.file!="" && fii.file!=sourceFile) of << "cfl=" << fii.file << "\n"; of << "cfn=" << f->getName().str() << "\n"; of << "calls=" << csi.count << " "; of << fii.assemblyLine << " "; of << fii.line << "\n"; of << ii.assemblyLine << " "; of << ii.line << " "; for (unsigned i=0; i<nStats; i++) { if (istatsMask&(1<<i)) { Statistic &s = sm.getStatistic(i); uint64_t value; // Hack, ignore things that don't make sense on // call paths. if (&s == &stats::uncoveredInstructions) { value = 0; } else { value = csi.statistics.getValue(s); } of << value << " "; } } of << "\n"; } } } } } } } if (istatsMask & (1<<stats::states.getID())) updateStateStatistics((uint64_t)-1); // Clear then end of the file if necessary (no truncate op?). unsigned pos = of.tell(); for (unsigned i=pos; i<istatsSize; ++i) of << '\n'; of.flush(); }
// TODO(sbucur): Break this into multiple methods void StatsTracker::getCallgraphProfile(data::GlobalProfile &globalProfile) { Module *m = executor.kmodule->module; uint64_t istatsMask = 0; StatisticManager &sm = *theStatisticManager; unsigned nStats = sm.getNumStatistics(); istatsMask |= 1<<sm.getStatisticID("Queries"); istatsMask |= 1<<sm.getStatisticID("QueriesValid"); istatsMask |= 1<<sm.getStatisticID("QueriesInvalid"); istatsMask |= 1<<sm.getStatisticID("QueryTime"); istatsMask |= 1<<sm.getStatisticID("ResolveTime"); istatsMask |= 1<<sm.getStatisticID("Instructions"); istatsMask |= 1<<sm.getStatisticID("InstructionTimes"); istatsMask |= 1<<sm.getStatisticID("InstructionRealTimes"); istatsMask |= 1<<sm.getStatisticID("Forks"); istatsMask |= 1<<sm.getStatisticID("GloballyCoveredInstructions"); istatsMask |= 1<<sm.getStatisticID("GloballyUncoveredInstructions"); istatsMask |= 1<<sm.getStatisticID("States"); istatsMask |= 1<<sm.getStatisticID("MinDistToUncovered"); for (unsigned i=0; i<nStats; i++) { if (istatsMask & (1<<i)) { Statistic &s = sm.getStatistic(i); globalProfile.add_cost_label(s.getName()); } } globalProfile.set_time_stamp(::time(NULL)); // set state counts, decremented after we process so that we don't // have to zero all records each time. if (istatsMask & (1<<stats::states.getID())) updateStateStatistics(1); CallSiteSummaryTable callSiteStats; if (UseCallPaths) callPathManager.getSummaryStatistics(callSiteStats); for (Module::iterator fnIt = m->begin(), fn_ie = m->end(); fnIt != fn_ie; ++fnIt) { if (fnIt->isDeclaration()) continue; data::FunctionProfile *functionProfile = globalProfile.add_function_profile(); functionProfile->set_function_id(executor.kmodule->functionMap[&(*fnIt)]->nameID); for (Function::iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); bbIt != bb_ie; ++bbIt) { for (BasicBlock::iterator it = bbIt->begin(), ie = bbIt->end(); it != ie; ++it) { Instruction *instr = &*it; const InstructionInfo &ii = executor.kmodule->infos->getInfo(instr); unsigned index = ii.id; data::LineProfile *lineProfile = functionProfile->add_line_profile(); executor.kmodule->fillInstructionDebugInfo( instr, *lineProfile->mutable_debug_info()); for (unsigned i=0; i<nStats; i++) { if (istatsMask&(1<<i)) { lineProfile->add_cost_value( sm.getIndexedValue(sm.getStatistic(i), index)); } } if (UseCallPaths && (isa<CallInst>(instr) || isa<InvokeInst>(instr))) { CallSiteSummaryTable::iterator it = callSiteStats.find(instr); if (it!=callSiteStats.end()) { for (std::map<llvm::Function*, CallSiteInfo>::iterator fit = it->second.begin(), fie = it->second.end(); fit != fie; ++fit) { Function *f = fit->first; CallSiteInfo &csi = fit->second; data::CallSiteProfile *callsiteProfile = lineProfile->add_call_site_profile(); executor.kmodule->fillFunctionDebugInfo( f, *callsiteProfile->mutable_debug_info()); callsiteProfile->set_call_count(csi.count); for (unsigned i=0; i<nStats; i++) { if (istatsMask&(1<<i)) { Statistic &s = sm.getStatistic(i); uint64_t value; // Hack, ignore things that don't make sense on // call paths. if (&s == &stats::globallyUncoveredInstructions) { value = 0; } else { value = csi.statistics.getValue(s); } callsiteProfile->add_cost_value(value); } } } } } } } } if (istatsMask & (1<<stats::states.getID())) updateStateStatistics((uint64_t)-1); }