diff --git a/tools/prune-trace/BasicPruner.cc b/tools/prune-trace/BasicPruner.cc index 38c4c639..9b5b5f86 100644 --- a/tools/prune-trace/BasicPruner.cc +++ b/tools/prune-trace/BasicPruner.cc @@ -7,50 +7,60 @@ static fail::Logger LOG ("BasicPruner"); bool BasicPruner::prune_all() { std::stringstream ss; - ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr1, instr2, data_address, fspmethod_id) " - "SELECT 0, variant_id, instr1, instr2, data_address, " << m_method_id << " " + /* When we are in basic-left mode we use the left boundary of the + equivalence interval. Since the current database scheme has no + instr1_absolute, we set this to NULL in the basic-left mode. */ + // FIXME "basic-left mode" doesn't make any sense; injections at instr1 and + // at instr2 are completely equivalent. + std::string injection_instr = this->use_instr1 ? "instr1" : "instr2"; + std::string injection_instr_absolute = this->use_instr1 ? "NULL" : "instr2_absolute"; + + ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, injection_instr, injection_instr_absolute, data_address, fspmethod_id) " + "SELECT 0, variant_id, instr2, " << injection_instr << ", " << injection_instr_absolute << ", " + " data_address, " << m_method_id << " " "FROM trace " - "WHERE variant_id = " << m_variant_id << " AND accesstype = 'R'"; + "WHERE variant_id IN (" << m_variant_id_query << ") AND accesstype = 'R'"; if (!db->query(ss.str().c_str())) return false; ss.str(""); int rows = db->affected_rows(); - // single entry for known outcome (write access) - ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr1, instr2, data_address, fspmethod_id) " - "SELECT 1, variant_id, instr1, instr2, data_address, " << m_method_id << " " - "FROM trace " - "WHERE variant_id = " << m_variant_id << " AND accesstype = 'W' " - "LIMIT 1"; - if (!db->query(ss.str().c_str())) return false; - ss.str(""); - 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))) { + // single entry for known outcome (write access) + ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, injection_instr, injection_instr_absolute, data_address, fspmethod_id) " + "SELECT 1, variant_id, instr2, " << injection_instr << ", " << injection_instr_absolute << ", " + " data_address, " << m_method_id << " " + "FROM trace " + "WHERE variant_id = " << row[0] << " AND accesstype = 'W' " + "LIMIT 1"; + if (!db->query(ss.str().c_str())) return false; + ss.str(""); + rows += db->affected_rows(); + } LOG << "created " << rows << " fsppilot entries" << std::endl; - /* When we are in basic-left mode we use the left boundary of the - equivalence interval. Sine the current database scheme has no - instr2_absolute, we set this to NULL in the basic-left mode. */ - std::string injection_instr = this->use_instr1 ? "t.instr1" : "t.instr2"; - std::string injection_instr_absolute = this->use_instr1 ? "NULL" : "t.instr2_absolute"; - - ss << "INSERT INTO fspgroup (variant_id, injection_instr, injection_instr_absolute, " - << " data_address, fspmethod_id, pilot_id) " - << "SELECT p.variant_id, " << injection_instr << ", " << injection_instr_absolute << ", p.data_address, p.fspmethod_id, p.id " + ss << "INSERT INTO fspgroup (variant_id, instr2, data_address, fspmethod_id, pilot_id) " + << "SELECT STRAIGHT_JOIN p.variant_id, p.instr2, p.data_address, p.fspmethod_id, p.id " << "FROM fsppilot p " - << " JOIN trace t ON t.variant_id = p.variant_id AND t.instr2 = p.instr2" + << "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 = " << m_variant_id; + << "WHERE known_outcome = 0 AND p.fspmethod_id = " << m_method_id << " " + << "AND p.variant_id IN (" << m_variant_id_query << ")"; if (!db->query(ss.str().c_str())) return false; ss.str(""); rows = db->affected_rows(); - ss << "INSERT INTO fspgroup (variant_id, injection_instr, injection_instr_absolute, data_address, fspmethod_id, pilot_id) " - "SELECT t.variant_id, "<< injection_instr << ", " << injection_instr_absolute <<", t.data_address, p.fspmethod_id, p.id " - "FROM trace t " - "JOIN fsppilot p " + 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 = " << m_variant_id << " AND t.accesstype = 'W'"; + "WHERE t.variant_id IN (" << m_variant_id_query << ") AND t.accesstype = 'W'"; if (!db->query(ss.str().c_str())) return false; ss.str(""); rows += db->affected_rows(); diff --git a/tools/prune-trace/Pruner.cc b/tools/prune-trace/Pruner.cc index 5708ae36..286927f2 100644 --- a/tools/prune-trace/Pruner.cc +++ b/tools/prune-trace/Pruner.cc @@ -8,17 +8,42 @@ static Logger LOG ("Pruner"); #include "Pruner.hpp" -bool Pruner::init(const std::string &variant, const std::string &benchmark, Database *db) { +bool Pruner::init(fail::Database *db, + const std::vector& variants, + const std::vector& variants_exclude, + const std::vector& benchmarks, + const std::vector& benchmarks_exclude) +{ this->db = db; - if (!(m_variant_id = db->get_variant_id(variant, benchmark))) { - return false; + std::stringstream ss; + + // FIXME string escaping + ss << "SELECT id FROM variant WHERE "; + for (std::vector::const_iterator it = variants.begin(); + it != variants.end(); ++it) { + ss << "variant LIKE '" << *it << "' AND "; } + for (std::vector::const_iterator it = variants_exclude.begin(); + it != variants_exclude.end(); ++it) { + ss << "variant NOT LIKE '" << *it << "' AND "; + } + for (std::vector::const_iterator it = benchmarks.begin(); + it != benchmarks.end(); ++it) { + ss << "benchmark LIKE '" << *it << "' AND "; + } + for (std::vector::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(); + if (!(m_method_id = db->get_fspmethod_id(method_name()))) { return false; } - LOG << "Pruning variant " - << variant << "/" << benchmark << " (ID: " << m_variant_id << ")" - << " with method " << method_name() << " (ID: " << m_method_id << ")" + + LOG << "Pruning with method " << method_name() << " (ID: " << m_method_id << ")" << std::endl; return true; } @@ -28,37 +53,37 @@ bool Pruner::create_database() { " id int(11) NOT NULL AUTO_INCREMENT," " known_outcome tinyint(4) NOT NULL," " variant_id int(11) NOT NULL," - " instr1 int(10) unsigned NOT NULL," " instr2 int(10) unsigned NOT NULL," + " injection_instr int(10) unsigned NOT NULL," + " injection_instr_absolute int(10) unsigned," " data_address int(10) unsigned NOT NULL," " fspmethod_id int(11) NOT NULL," " PRIMARY KEY (id)," - " KEY fspmethod_id (fspmethod_id,variant_id,instr1,instr2,data_address)" - ") engine=MyISAM "; + " KEY fspmethod_id (fspmethod_id,variant_id,instr2,data_address)" + ") engine=MyISAM "; bool success = (bool) db->query(create_statement.c_str()); if (!success) return false; create_statement = "CREATE TABLE IF NOT EXISTS fspgroup (" " variant_id int(11) NOT NULL," - " injection_instr int(10) unsigned NOT NULL," - " injection_instr_absolute int(10) unsigned," + " instr2 int(11) unsigned NOT NULL," " data_address int(10) unsigned NOT NULL," " fspmethod_id int(11) NOT NULL," " pilot_id int(11) NOT NULL," - " PRIMARY KEY (variant_id, injection_instr, data_address, fspmethod_id, pilot_id)," - " KEY joinresults (pilot_id,fspmethod_id))"; + " PRIMARY KEY (variant_id, instr2, data_address, fspmethod_id, pilot_id)," + " KEY joinresults (pilot_id,fspmethod_id)) engine=MyISAM"; return db->query(create_statement.c_str()); } bool Pruner::clear_database() { std::stringstream ss; - ss << "DELETE FROM fsppilot WHERE variant_id = " << m_variant_id << " AND fspmethod_id = " << m_method_id; + ss << "DELETE FROM fsppilot WHERE variant_id IN (" << m_variant_id_query << ")"; 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 = " << m_variant_id << " AND fspmethod_id = " << m_method_id; + ss << "DELETE FROM fspgroup WHERE variant_id IN (" << m_variant_id_query << ")"; ret = ret && (bool) db->query(ss.str().c_str()); LOG << "deleted " << db->affected_rows() << " rows from fspgroup table" << std::endl; diff --git a/tools/prune-trace/Pruner.hpp b/tools/prune-trace/Pruner.hpp index bcafa295..cbbb2113 100644 --- a/tools/prune-trace/Pruner.hpp +++ b/tools/prune-trace/Pruner.hpp @@ -1,24 +1,29 @@ #ifndef __PRUNER_H__ #define __PRUNER_H__ +#include +#include #include "util/Database.hpp" class Pruner { protected: - int m_variant_id; - int m_method_id; - fail::Database *db; + int m_method_id; + std::string m_variant_id_query; + fail::Database *db; public: - bool init(const std::string &variant, const std::string &benchmark, - fail::Database *sql); + bool init(fail::Database *db, + const std::vector& variants, + const std::vector& variants_exclude, + const std::vector& benchmarks, + const std::vector& benchmarks_exclude); - virtual std::string method_name() = 0; + virtual std::string method_name() = 0; virtual bool create_database(); virtual bool clear_database(); - virtual bool prune_all() = 0; + virtual bool prune_all() = 0; }; #endif diff --git a/tools/prune-trace/main.cc b/tools/prune-trace/main.cc index 990a94fd..0dc606c4 100644 --- a/tools/prune-trace/main.cc +++ b/tools/prune-trace/main.cc @@ -13,7 +13,7 @@ using std::endl; #include "BasicPruner.hpp" int main(int argc, char *argv[]) { - std::string username, hostname, database, benchmark, variant; + std::string username, hostname, database; // Manually fill the command line option parser CommandLine &cmd = CommandLine::Inst(); @@ -25,12 +25,24 @@ int main(int argc, char *argv[]) { Database::cmdline_setup(); - CommandLine::option_handle VARIANT = cmd.addOption("v", "variant", Arg::Required, - "-v/--variant \tVariant label (default: \"none\")"); - CommandLine::option_handle BENCHMARK = cmd.addOption("b", "benchmark", Arg::Required, - "-b/--benchmark \tBenchmark label (default: \"none\")\n"); - CommandLine::option_handle PRUNER = cmd.addOption("p", "prune-method", Arg::Required, - "-p/--prune-method \tWhich import method to use (default: basic)"); + CommandLine::option_handle VARIANT = + cmd.addOption("v", "variant", Arg::Required, + "-v/--variant \tVariant label (default: \"none\"; use % and _ as wildcard characters; may be used more than once)"); + CommandLine::option_handle VARIANT_EXCLUDE = + cmd.addOption("", "variant-exclude", Arg::Required, + "--variant-exclude \tVariant to exclude (default: UNSET; use % and _ as wildcard characters; may be used more than once)"); + CommandLine::option_handle BENCHMARK = + cmd.addOption("b", "benchmark", Arg::Required, + "-b/--benchmark \tBenchmark label (default: \"none\"; use % and _ as wildcard characters; may be used more than once)"); + CommandLine::option_handle BENCHMARK_EXCLUDE = + cmd.addOption("", "benchmark-exclude", Arg::Required, + "--benchmark-exclude \tBenchmark to exclude (default: UNSET; use % and _ as wildcard characters; may be used more than once)"); + CommandLine::option_handle PRUNER = + cmd.addOption("p", "prune-method", Arg::Required, + "-p/--prune-method \tWhich import method to use (default: basic)"); + CommandLine::option_handle NO_DELETE = + cmd.addOption("", "no-delete", Arg::None, + "--no-delete \tAssume there are no DB entries for this variant/benchmark, don't issue a DELETE"); if(!cmd.parse()) { std::cerr << "Error parsing arguments." << std::endl; @@ -64,17 +76,36 @@ int main(int argc, char *argv[]) { Database *db = Database::cmdline_connect(); - if (cmd[VARIANT].count() > 0) - variant = std::string(cmd[VARIANT].first()->arg); - else - variant = "none"; + std::vector variants, benchmarks, variants_exclude, benchmarks_exclude; + if (cmd[VARIANT].count() > 0) { + for (option::Option *o = cmd[VARIANT]; o; o = o->next()) { + variants.push_back(std::string(o->arg)); + } + } else { + variants.push_back(std::string("none")); + } - if (cmd[BENCHMARK].count() > 0) - benchmark = std::string(cmd[BENCHMARK].first()->arg); - else - benchmark = "none"; + if (cmd[VARIANT_EXCLUDE].count() > 0) { + for (option::Option *o = cmd[VARIANT_EXCLUDE]; o; o = o->next()) { + variants_exclude.push_back(std::string(o->arg)); + } + } - if (!pruner->init(variant, benchmark, db)) { + if (cmd[BENCHMARK].count() > 0) { + for (option::Option *o = cmd[BENCHMARK]; o; o = o->next()) { + benchmarks.push_back(std::string(o->arg)); + } + } else { + benchmarks.push_back(std::string("none")); + } + + if (cmd[BENCHMARK_EXCLUDE].count() > 0) { + for (option::Option *o = cmd[BENCHMARK_EXCLUDE]; o; o = o->next()) { + benchmarks_exclude.push_back(std::string(o->arg)); + } + } + + if (!pruner->init(db, variants, variants_exclude, benchmarks, benchmarks_exclude)) { LOG << "pruner->init() failed" << endl; exit(-1); } @@ -87,7 +118,7 @@ int main(int argc, char *argv[]) { exit(-1); } - if (!pruner->clear_database()) { + if (cmd[NO_DELETE].count() == 0 && !pruner->clear_database()) { LOG << "clear_database() failed" << endl; exit(-1); }