Merge commit '0da8ba0dec111d78292455bb5f17c6045820db25'

This commit is contained in:
Horst Schirmeier
2014-08-28 12:04:34 +02:00
13 changed files with 585 additions and 51 deletions

View File

@ -19,22 +19,21 @@ bool BasicPruner::prune_all() {
"SELECT 0, variant_id, instr2, " << injection_instr << ", " << injection_instr_absolute << ", "
" data_address, width, " << m_method_id << " "
"FROM trace "
"WHERE variant_id IN (" << m_variant_id_query << ") AND accesstype = 'R'";
"WHERE variant_id IN (" << m_variants_sql << ") AND accesstype = 'R'";
if (!db->query(ss.str().c_str())) return false;
ss.str("");
int rows = db->affected_rows();
// for each variant:
MYSQL_RES *res = db->query(m_variant_id_query.c_str(), true);
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
for (std::vector<fail::Database::Variant>::const_iterator it = m_variants.begin();
it != m_variants.end(); ++it) {
// single entry for known outcome (write access)
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, injection_instr, injection_instr_absolute, data_address, data_width, fspmethod_id) "
"SELECT 1, variant_id, instr2, " << injection_instr << ", " << injection_instr_absolute << ", "
" data_address, width, " << m_method_id << " "
"FROM trace "
"WHERE variant_id = " << row[0] << " AND accesstype = 'W' "
"WHERE variant_id = " << it->id << " AND accesstype = 'W' "
"ORDER BY instr2 ASC "
"LIMIT 1";
if (!db->query(ss.str().c_str())) return false;
@ -50,7 +49,7 @@ bool BasicPruner::prune_all() {
<< "JOIN trace t ON t.variant_id = p.variant_id AND t.instr2 = p.instr2"
<< " AND t.data_address = p.data_address "
<< "WHERE known_outcome = 0 AND p.fspmethod_id = " << m_method_id << " "
<< "AND p.variant_id IN (" << m_variant_id_query << ")";
<< "AND p.variant_id IN (" << m_variants_sql << ")";
if (!db->query(ss.str().c_str())) return false;
ss.str("");
@ -61,7 +60,7 @@ bool BasicPruner::prune_all() {
"FROM fsppilot p "
"JOIN trace t "
"ON t.variant_id = p.variant_id AND p.fspmethod_id = " << m_method_id << " AND p.known_outcome = 1 "
"WHERE t.variant_id IN (" << m_variant_id_query << ") AND t.accesstype = 'W'";
"WHERE t.variant_id IN (" << m_variants_sql << ") AND t.accesstype = 'W'";
if (!db->query(ss.str().c_str())) return false;
ss.str("");
rows += db->affected_rows();

View File

@ -1,6 +1,7 @@
set(SRCS
Pruner.cc
BasicPruner.cc
FESamplingPruner.cc
)
find_package(MySQL REQUIRED)

View File

@ -0,0 +1,176 @@
#include <sstream>
#include <stdlib.h>
#include <fstream>
#include <algorithm>
#include "FESamplingPruner.hpp"
#include "util/Logger.hpp"
#include "util/CommandLine.hpp"
#include "util/SumTree.hpp"
static fail::Logger LOG("FESamplingPruner");
using std::endl;
struct Pilot {
uint64_t duration;
uint32_t instr2;
uint32_t instr2_absolute;
uint32_t data_address;
typedef uint64_t size_type;
size_type size() const { return duration; }
};
bool FESamplingPruner::commandline_init()
{
fail::CommandLine &cmd = fail::CommandLine::Inst();
SAMPLESIZE = cmd.addOption("", "samplesize", Arg::Required,
"--samplesize N \tNumber of samples to take (per variant)");
return true;
}
bool FESamplingPruner::prune_all()
{
fail::CommandLine &cmd = fail::CommandLine::Inst();
if (!cmd[SAMPLESIZE]) {
LOG << "parameter --samplesize required, aborting" << endl;
return false;
}
m_samplesize = strtoul(cmd[SAMPLESIZE].first()->arg, 0, 10);
// for each variant:
for (std::vector<fail::Database::Variant>::const_iterator it = m_variants.begin();
it != m_variants.end(); ++it) {
if (!sampling_prune(*it)) {
return false;
}
}
return true;
}
// TODO: replace with a less syscall-intensive RNG
static std::ifstream dev_urandom("/dev/urandom", std::ifstream::binary);
static uint64_t my_rand(uint64_t limit)
{
// find smallest bitpos that satisfies (1 << bitpos) > limit
int bitpos = 0;
while (limit >> bitpos) {
bitpos++;
}
uint64_t retval;
do {
dev_urandom.read((char *) &retval, sizeof(retval));
retval &= (1ULL << bitpos) - 1;
} while (retval > limit);
return retval;
}
bool FESamplingPruner::sampling_prune(const fail::Database::Variant& variant)
{
fail::SumTree<Pilot> pop; // sample population
std::stringstream ss;
MYSQL_RES *res;
MYSQL_ROW row;
LOG << "loading trace entries for " << variant.variant << "/" << variant.benchmark << " ..." << endl;
unsigned pilotcount = 0;
// load trace entries
ss << "SELECT instr2, instr2_absolute, data_address, time2-time1+1 AS duration"
<< " FROM trace"
<< " WHERE variant_id = " << variant.id
<< " AND accesstype = 'R'"
<< " ORDER BY duration DESC"; // speeds up sampling, but query may be slow
res = db->query_stream(ss.str().c_str());
ss.str("");
if (!res) return false;
while ((row = mysql_fetch_row(res))) {
Pilot p;
p.instr2 = strtoul(row[0], 0, 10);
p.instr2_absolute = strtoul(row[1], 0, 10);
p.data_address = strtoul(row[2], 0, 10);
p.duration = strtoull(row[3], 0, 10);
pop.add(p);
++pilotcount;
}
mysql_free_result(res);
unsigned samplerows = std::min(pilotcount, m_samplesize);
LOG << "loaded " << pilotcount << " entries, sampling "
<< samplerows << " entries with fault expansion ..." << endl;
// FIXME: change strategy when trace entries have IDs, insert into fspgroup first
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, injection_instr, "
<< "injection_instr_absolute, data_address, data_width, fspmethod_id) VALUES ";
std::string insert_sql(ss.str());
ss.str("");
for (unsigned i = 0; i < samplerows; ++i) {
uint64_t pos = my_rand(pop.get_size() - 1);
Pilot p = pop.get(pos);
ss << "(0," << variant.id << "," << p.instr2 << "," << p.instr2
<< "," << p.instr2_absolute << "," << p.data_address
<< ",1," << m_method_id << ")";
db->insert_multiple(insert_sql.c_str(), ss.str().c_str());
ss.str("");
}
db->insert_multiple();
unsigned num_fsppilot_entries = samplerows;
// single entry for known outcome (write access)
ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, injection_instr, injection_instr_absolute, data_address, data_width, fspmethod_id) "
"SELECT 1, variant_id, instr2, instr2, instr2_absolute, "
" data_address, width, " << m_method_id << " "
"FROM trace "
"WHERE variant_id = " << variant.id << " AND accesstype = 'W' "
"ORDER BY instr2 ASC "
"LIMIT 1";
if (!db->query(ss.str().c_str())) return false;
ss.str("");
num_fsppilot_entries += db->affected_rows();
assert(num_fsppilot_entries == (samplerows + 1));
LOG << "created " << num_fsppilot_entries << " fsppilot entries" << std::endl;
// fspgroup entries for sampled trace entries
ss << "INSERT INTO fspgroup (variant_id, instr2, data_address, fspmethod_id, pilot_id) "
<< "SELECT p.variant_id, p.instr2, p.data_address, p.fspmethod_id, p.id "
<< "FROM fsppilot p "
<< "WHERE known_outcome = 0 AND p.fspmethod_id = " << m_method_id << " "
<< "AND p.variant_id = " << variant.id;
if (!db->query(ss.str().c_str())) return false;
ss.str("");
unsigned num_fspgroup_entries = db->affected_rows();
#if 0 // do it like the basic pruner:
// fspgroup entries for known (W) trace entries
ss << "INSERT INTO fspgroup (variant_id, instr2, data_address, fspmethod_id, pilot_id) "
"SELECT STRAIGHT_JOIN t.variant_id, t.instr2, t.data_address, p.fspmethod_id, p.id "
"FROM fsppilot p "
"JOIN trace t "
"ON t.variant_id = p.variant_id AND p.fspmethod_id = " << m_method_id << " AND p.known_outcome = 1 "
"WHERE t.variant_id = " << variant.id << " AND t.accesstype = 'W'";
#else
// *one* fspgroup entry for known (W) trace entries (no need to create one
// for each W); this needs to be accounted for at data analysis time,
// though.
ss << "INSERT INTO fspgroup (variant_id, instr2, data_address, fspmethod_id, pilot_id) "
"SELECT variant_id, instr2, data_address, fspmethod_id, id "
"FROM fsppilot "
"WHERE variant_id = " << variant.id << " AND known_outcome = 1 AND fspmethod_id = " << m_method_id;
#endif
if (!db->query(ss.str().c_str())) return false;
ss.str("");
num_fspgroup_entries += db->affected_rows();
LOG << "created " << num_fspgroup_entries << " fspgroup entries" << std::endl;
return true;
}

View File

@ -0,0 +1,31 @@
#ifndef __FESAMPLING_PRUNER_H__
#define __FESAMPLING_PRUNER_H__
#include "Pruner.hpp"
#include "util/CommandLine.hpp"
///
/// FESamplingPruner: implements sampling with Fault Expansion
///
/// The FESamplingPruner implements the fault-expansion variance reduction
/// technique (FE-VRT) as described in: Smith, D. Todd and Johnson, Barry W.
/// and Andrianos, Nikos and Profeta, III, Joseph A., "A variance-reduction
/// technique via fault-expansion for fault-coverage estimation" (1997),
/// 366--374.
///
class FESamplingPruner : public Pruner {
fail::CommandLine::option_handle SAMPLESIZE;
unsigned m_samplesize;
public:
FESamplingPruner() : m_samplesize(0) { }
virtual std::string method_name() { return "FESampling"; }
virtual bool commandline_init();
virtual bool prune_all();
private:
bool sampling_prune(const fail::Database::Variant& variant);
};
#endif

View File

@ -15,29 +15,24 @@ bool Pruner::init(fail::Database *db,
const std::vector<std::string>& benchmarks_exclude)
{
this->db = db;
std::stringstream ss;
// FIXME string escaping
ss << "SELECT id FROM variant WHERE ";
for (std::vector<std::string>::const_iterator it = variants.begin();
it != variants.end(); ++it) {
ss << "variant LIKE '" << *it << "' AND ";
m_variants = db->get_variants(
variants, variants_exclude,
benchmarks, benchmarks_exclude);
if (m_variants.size() == 0) {
LOG << "no variants found, nothing to do" << std::endl;
return false;
}
for (std::vector<std::string>::const_iterator it = variants_exclude.begin();
it != variants_exclude.end(); ++it) {
ss << "variant NOT LIKE '" << *it << "' AND ";
std::stringstream ss;
for (std::vector<fail::Database::Variant>::const_iterator it = m_variants.begin();
it != m_variants.end(); ++it) {
if (it != m_variants.begin()) {
ss << ",";
}
ss << it->id;
}
for (std::vector<std::string>::const_iterator it = benchmarks.begin();
it != benchmarks.end(); ++it) {
ss << "benchmark LIKE '" << *it << "' AND ";
}
for (std::vector<std::string>::const_iterator it = benchmarks_exclude.begin();
it != benchmarks_exclude.end(); ++it) {
ss << "benchmark NOT LIKE '" << *it << "' AND ";
}
// dummy terminator to avoid special cases in query construction above
ss << "1";
m_variant_id_query = ss.str();
m_variants_sql = ss.str();
if (!(m_method_id = db->get_fspmethod_id(method_name()))) {
return false;
@ -79,12 +74,14 @@ bool Pruner::create_database() {
bool Pruner::clear_database() {
std::stringstream ss;
ss << "DELETE FROM fsppilot WHERE variant_id IN (" << m_variant_id_query << ")";
ss << "DELETE FROM fsppilot WHERE variant_id IN (" << m_variants_sql
<< ") AND fspmethod_id = " << m_method_id;
bool ret = (bool) db->query(ss.str().c_str());
LOG << "deleted " << db->affected_rows() << " rows from fsppilot table" << std::endl;
ss.str("");
ss << "DELETE FROM fspgroup WHERE variant_id IN (" << m_variant_id_query << ")";
ss << "DELETE FROM fspgroup WHERE variant_id IN (" << m_variants_sql
<< ") AND fspmethod_id = " << m_method_id;
ret = ret && (bool) db->query(ss.str().c_str());
LOG << "deleted " << db->affected_rows() << " rows from fspgroup table" << std::endl;

View File

@ -8,8 +8,9 @@
class Pruner {
protected:
int m_method_id;
std::string m_variant_id_query;
fail::Database *db;
std::vector<fail::Database::Variant> m_variants;
std::string m_variants_sql;
public:
bool init(fail::Database *db,
@ -18,6 +19,12 @@ public:
const std::vector<std::string>& benchmarks,
const std::vector<std::string>& benchmarks_exclude);
/**
* Callback function that can be used to add command line options
* to the cmd interface
*/
virtual bool commandline_init() { return true; }
virtual std::string method_name() = 0;
virtual bool create_database();

View File

@ -11,6 +11,7 @@ using std::endl;
#include "Pruner.hpp"
#include "BasicPruner.hpp"
#include "FESamplingPruner.hpp"
int main(int argc, char *argv[]) {
std::string username, hostname, database;
@ -59,6 +60,9 @@ int main(int argc, char *argv[]) {
} else if (imp == "BasicPrunerLeft" || imp == "basic-left") {
LOG << "Using BasicPruner (use left border, instr1)" << endl;
pruner = new BasicPruner(true);
} else if (imp == "FESamplingPruner" || imp == "sampling") {
LOG << "Using FESamplingPruner" << endl;
pruner = new FESamplingPruner;
} else {
LOG << "Unknown pruning method: " << imp << endl;
@ -70,6 +74,14 @@ int main(int argc, char *argv[]) {
pruner = new BasicPruner();
}
if (pruner && !(pruner->commandline_init())) {
std::cerr << "Pruner's commandline initialization failed" << std::endl;
exit(-1);
}
// Since the pruner might have added command line options, we need to
// reparse all arguments.
cmd.parse();
if (cmd[HELP]) {
cmd.printUsage();
exit(0);