diff --git a/src/core/cpn/DatabaseCampaign.cc b/src/core/cpn/DatabaseCampaign.cc index 1303722e..9570c243 100644 --- a/src/core/cpn/DatabaseCampaign.cc +++ b/src/core/cpn/DatabaseCampaign.cc @@ -82,7 +82,7 @@ bool DatabaseCampaign::run() { /* Gather all unfinished jobs */ int experiment_count; - std::string sql_select = "SELECT pilot_id, g.fspmethod_id, g.variant_id, g.injection_instr, g.injection_instr_absolute, g.data_address"; + std::string sql_select = "SELECT pilot_id, g.fspmethod_id, g.variant_id, p.injection_instr, p.injection_instr_absolute, g.data_address"; std::stringstream ss; ss << " FROM fspgroup g" << " INNER JOIN fsppilot p ON p.id = g.pilot_id " @@ -90,7 +90,7 @@ bool DatabaseCampaign::run() { << " AND g.fspmethod_id = " << fspmethod_id << " AND g.variant_id = " << variant_id << " AND (SELECT COUNT(*) FROM " + db_connect.result_table() + " as r WHERE r.pilot_id = g.pilot_id) = 0" - << " ORDER BY g.injection_instr"; + << " ORDER BY p.injection_instr"; std::string sql_body = ss.str(); /* Get the number of unfinished experiments */ diff --git a/src/core/util/DatabaseProtobufAdapter.cc b/src/core/util/DatabaseProtobufAdapter.cc index 21c8dcb5..8d35e10e 100644 --- a/src/core/util/DatabaseProtobufAdapter.cc +++ b/src/core/util/DatabaseProtobufAdapter.cc @@ -369,6 +369,7 @@ void DatabaseProtobufAdapter::create_table(const Descriptor *toplevel_desc) { create_table_stmt << "CREATE TABLE IF NOT EXISTS " << result_table_name << "("; create_table_stmt << top_level_msg.sql_create_stmt() << ", PRIMARY KEY(" << primary_join.join(", ") << "))"; + create_table_stmt << " ENGINE=MyISAM"; insert_stmt << "INSERT INTO " << result_table_name << "(" << insert_join.join(","); insert_stmt << ") VALUES (" << question_marks.join(",") << ")"; diff --git a/src/experiments/dciao-kernelstructs/CMakeLists.txt b/src/experiments/dciao-kernelstructs/CMakeLists.txt index d45e26e8..a1834697 100644 --- a/src/experiments/dciao-kernelstructs/CMakeLists.txt +++ b/src/experiments/dciao-kernelstructs/CMakeLists.txt @@ -30,6 +30,6 @@ target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY}) ## This is the example's campaign server distributing experiment parameters add_executable(${EXPERIMENT_NAME}-server main.cc) -target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient) +target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} -lmysqlclient -Wl,--end-group) install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin) diff --git a/tools/import-trace/BasicImporter.cc b/tools/import-trace/BasicImporter.cc index 04e0d0b0..22aac15c 100644 --- a/tools/import-trace/BasicImporter.cc +++ b/tools/import-trace/BasicImporter.cc @@ -7,6 +7,7 @@ bool BasicImporter::create_database() { std::string create_statement = "CREATE TABLE IF NOT EXISTS trace (" " variant_id int(11) NOT NULL," " instr1 int(10) unsigned NOT NULL," + " instr1_absolute int(10) unsigned DEFAULT NULL," " instr2 int(10) unsigned NOT NULL," " instr2_absolute int(10) unsigned DEFAULT NULL," " time1 bigint(10) unsigned NOT NULL," @@ -19,15 +20,13 @@ bool BasicImporter::create_database() { return db->query(create_statement.c_str()); } -bool BasicImporter::add_trace_event(instruction_count_t begin, instruction_count_t end, - fail::simtime_t time_begin, fail::simtime_t time_end, - const Trace_Event &event, bool is_fake) { - +bool BasicImporter::add_trace_event(margin_info_t &begin, margin_info_t &end, + const Trace_Event &event, bool is_fake) { static MYSQL_STMT *stmt = 0; if (!stmt) { - std::string sql("INSERT INTO trace (variant_id, instr1, instr2, instr2_absolute, time1, time2, data_address, width," + std::string sql("INSERT INTO trace (variant_id, instr1, instr1_absolute, instr2, instr2_absolute, time1, time2, data_address, width," " accesstype)" - "VALUES (?,?,?,?,?,?,?,?,?)"); + "VALUES (?,?,?,?,?,?,?,?,?,?)"); stmt = mysql_stmt_init(db->getHandle()); if (mysql_stmt_prepare(stmt, sql.c_str(), sql.length())) { LOG << "query '" << sql << "' failed: " << mysql_error(db->getHandle()) << std::endl; @@ -35,13 +34,18 @@ bool BasicImporter::add_trace_event(instruction_count_t begin, instruction_count } } - MYSQL_BIND bind[9]; + MYSQL_BIND bind[10]; my_bool is_null = is_fake; + my_bool null = true; + unsigned long accesstype_len = 1; - unsigned ip = event.ip(); + unsigned data_address = event.memaddr(); unsigned width = event.width(); + char accesstype = event.accesstype() == event.READ ? 'R' : 'W'; + // LOG << m_variant_id << "-" << ":" << begin.dyninstr << ":" << end.dyninstr << "-" << data_address << " " << accesstype << std::endl; + memset(bind, 0, sizeof(bind)); for (unsigned i = 0; i < sizeof(bind)/sizeof(*bind); ++i) { @@ -49,19 +53,22 @@ bool BasicImporter::add_trace_event(instruction_count_t begin, instruction_count bind[i].is_unsigned = 1; switch (i) { case 0: bind[i].buffer = &m_variant_id; break; - case 1: bind[i].buffer = &begin; break; - case 2: bind[i].buffer = &end; break; - case 3: bind[i].buffer = &ip; + case 1: bind[i].buffer = &begin.dyninstr; break; + case 2: bind[i].buffer = &begin.ip; + bind[i].is_null = begin.ip == 0 ? &null : &is_null; + break; + case 3: bind[i].buffer = &end.dyninstr; break; + case 4: bind[i].buffer = &end.ip; bind[i].is_null = &is_null; break; - case 4: bind[i].buffer = &time_begin; + case 5: bind[i].buffer = &begin.time; bind[i].buffer_type = MYSQL_TYPE_LONGLONG; break; - case 5: bind[i].buffer = &time_end; + case 6: bind[i].buffer = &end.time; bind[i].buffer_type = MYSQL_TYPE_LONGLONG; break; - case 6: bind[i].buffer = &data_address; break; - case 7: bind[i].buffer = &width; break; - case 8: bind[i].buffer = &accesstype; + case 7: bind[i].buffer = &data_address; break; + case 8: bind[i].buffer = &width; break; + case 9: bind[i].buffer = &accesstype; bind[i].buffer_type = MYSQL_TYPE_STRING; bind[i].buffer_length = accesstype_len; bind[i].length = &accesstype_len; diff --git a/tools/import-trace/BasicImporter.hpp b/tools/import-trace/BasicImporter.hpp index 936f8e25..a37a4014 100644 --- a/tools/import-trace/BasicImporter.hpp +++ b/tools/import-trace/BasicImporter.hpp @@ -7,12 +7,8 @@ class BasicImporter : public Importer { public: virtual bool create_database(); - bool add_trace_event(instruction_count_t begin, - instruction_count_t end, - fail::simtime_t time_begin, - fail::simtime_t time_end, - const Trace_Event &event, - bool is_fake = false); + virtual bool add_trace_event(margin_info_t &begin, margin_info_t &end, + const Trace_Event &event, bool is_fake = false); }; #endif diff --git a/tools/import-trace/DCiAOKernelImporter.cc b/tools/import-trace/DCiAOKernelImporter.cc index 4451c76a..ed00acf3 100644 --- a/tools/import-trace/DCiAOKernelImporter.cc +++ b/tools/import-trace/DCiAOKernelImporter.cc @@ -11,9 +11,9 @@ using namespace fail; bool DCiAOKernelImporter::inDynamicKernelMemory(fail::address_t addr) { const std::string &name = m_elf->getSymbol(addr).getDemangledName(); bool dynamic = name.find("os::data::dynamic", 0) != std::string::npos; - // bool stack = name.find("_stack") != std::string::npos; - // return dynamic && !stack; - return dynamic; + bool stack = name.find("_stack") != std::string::npos; + return dynamic && !stack; + // return dynamic; } bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { @@ -31,8 +31,12 @@ bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { // instruction counter within trace unsigned instr = 0; + unsigned instr_last_kernel_inject = 0; unsigned instr_last_kernel_leave = 0; + unsigned instr_last_kernel_enter = 0; + + address_t inject_kernel_addr = getInjectKernelAddress(); address_t enter_kernel_addr = getEnterKernelAddress(); address_t leave_kernel_addr = getLeaveKernelAddress(); @@ -50,14 +54,18 @@ bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { // new instruction instr++; + if (ev.ip() == inject_kernel_addr) { + instr_last_kernel_inject = instr; + already_written_addresses.clear(); + } if (ev.ip() == enter_kernel_addr) { in_kernel_space = true; + instr_last_kernel_enter = instr; } if (ev.ip() == leave_kernel_addr) { instr_last_kernel_leave = instr; in_kernel_space = false; - already_written_addresses.clear(); } continue; } @@ -77,13 +85,18 @@ bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { address_t from = ev.memaddr(), to = ev.memaddr() + ev.width(); // Iterate over all accessed bytes for (address_t data_address = from; data_address < to; ++data_address) { - int instr1 = instr_last_kernel_leave; - int instr2 = instr; // the current instruction + margin_info_t left_margin, right_margin; + left_margin.dyninstr = instr_last_kernel_inject + 1; + left_margin.ip = inject_kernel_addr; + left_margin.time = 0; + right_margin.dyninstr = instr; // the current instruction + right_margin.ip = ev.ip(); + right_margin.time = 0; /* Was the byte already written in this kernel space */ if (already_written_addresses.find(data_address) - == already_written_addresses.end()) + != already_written_addresses.end()) continue; ev.set_memaddr(data_address); @@ -91,8 +104,9 @@ bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { // we now have an interval-terminating R/W event to the memaddr // we're currently looking at; the EC is defined by - // data_address [last_kernel_leave, read_instr] (instr_absolute) - if (!add_trace_event(instr1, instr2, 0, 0, ev)) { // FIXME use timing data + // data_address [last_kernel_leave, read_instr] + // (instr_absolute) + if (!add_trace_event(left_margin, right_margin, ev)) { LOG << "add_trace_event failed" << std::endl; return false; } @@ -100,6 +114,10 @@ bool DCiAOKernelImporter::copy_to_database(fail::ProtoIStream &ps) { if (row_count % 1000 == 0) { LOG << "Imported " << row_count << " traces into the database" << std::endl; } + + /* This was the first read, we ignore all further + reads in this kernel transition */ + already_written_addresses.insert(data_address); } } } diff --git a/tools/import-trace/DCiAOKernelImporter.hpp b/tools/import-trace/DCiAOKernelImporter.hpp index bfd3db17..e96a4a28 100644 --- a/tools/import-trace/DCiAOKernelImporter.hpp +++ b/tools/import-trace/DCiAOKernelImporter.hpp @@ -20,8 +20,9 @@ */ class DCiAOKernelImporter : public BasicImporter { protected: - fail::address_t getEnterKernelAddress() { return m_elf->getSymbol("os::dep::KernelStructs::correct").getAddress(); } - fail::address_t getLeaveKernelAddress() { return m_elf->getSymbol("os::dep::KernelStructs::calculate").getAddress(); } + fail::address_t getInjectKernelAddress() { return m_elf->getSymbol("os::dep::KernelStructs::correct").getAddress(); } + fail::address_t getEnterKernelAddress() { return m_elf->getSymbol("os::dep::kernel_protected_open").getAddress(); } + fail::address_t getLeaveKernelAddress() { return m_elf->getSymbol("os::dep::kernel_protected_close").getAddress(); } bool inDynamicKernelMemory(fail::address_t addr); public: diff --git a/tools/import-trace/Importer.cc b/tools/import-trace/Importer.cc index 8c7aafb8..d872eb58 100644 --- a/tools/import-trace/Importer.cc +++ b/tools/import-trace/Importer.cc @@ -82,21 +82,21 @@ bool Importer::copy_to_database(fail::ProtoIStream &ps) { if (m_mm && !m_mm->isMatching(data_address)) { continue; } - instruction_count_t instr1 = - open_ecs[data_address].dyninstr; // defaults to 0 if nonexistent - instruction_count_t instr2 = instr; // the current instruction - simtime_t time1 = open_ecs[data_address].time; + margin_info_t right_margin; + margin_info_t left_margin = open_ecs[data_address]; // defaulting to 0 is not such a good idea, memory reads at the // beginning of the trace would get an unnaturally high weight: - if (time1 == 0) { - time1 = time_trace_start; + if (left_margin.time == 0) { + left_margin.time = time_trace_start; } - simtime_t time2 = curtime; + right_margin.time = curtime; + right_margin.dyninstr = instr; // !< The current instruction + right_margin.ip = ev.ip(); // skip zero-sized intervals: these can occur when an instruction // accesses a memory location more than once (e.g., INC, CMPXCHG) // FIXME: look at timing instead? - if (instr1 > instr2) { + if (left_margin.dyninstr > right_margin.dyninstr) { continue; } @@ -107,7 +107,7 @@ bool Importer::copy_to_database(fail::ProtoIStream &ps) { // we're currently looking at; the EC is defined by // data_address, dynamic instruction start/end, the absolute PC at // the end, and time start/end - if (!add_trace_event(instr1, instr2, time1, time2, ev)) { + if (!add_trace_event(left_margin, right_margin, ev)) { LOG << "add_trace_event failed" << std::endl; return false; } @@ -118,9 +118,10 @@ bool Importer::copy_to_database(fail::ProtoIStream &ps) { // next interval must start at next instruction; the aforementioned // skipping mechanism wouldn't work otherwise - //lastuse_it->second = instr2 + 1; - open_ecs[data_address].dyninstr = instr2 + 1; - open_ecs[data_address].time = time2 + 1; + open_ecs[data_address].dyninstr = instr + 1; + open_ecs[data_address].time = curtime + 1; + // FIXME: This should be the next IP, not the current, or? + open_ecs[data_address].ip = ev.ip(); } } @@ -138,31 +139,30 @@ bool Importer::copy_to_database(fail::ProtoIStream &ps) { fake_ev.set_width(1); fake_ev.set_accesstype(m_faultspace_rightmargin == 'R' ? fake_ev.READ : fake_ev.WRITE); - instruction_count_t instr1 = lastuse_it->second.dyninstr; - simtime_t time1 = lastuse_it->second.time; + margin_info_t left_margin, right_margin; + left_margin = lastuse_it->second; // Why -1? In most cases it does not make sense to inject before the // very last instruction, as we won't execute it anymore. This *only* // makes sense if we also inject into parts of the result vector. This // is not the case in this experiment, and with -1 we'll get a result // comparable to the non-pruned campaign. - instruction_count_t instr2 = instr - 1; - - simtime_t time2 = curtime; // -1? - + right_margin.dyninstr = instr - 1; + right_margin.time = curtime; // -1? + right_margin.ip = ev.ip(); // The last event in the log. // #else // // EcosKernelTestCampaign only variant: fault space ends with the last FI experiment // FIXME probably implement this with cmdline parameter FAULTSPACE_CUTOFF -// int instr2 = instr_rightmost; +// right_margin.dyninstr = instr_rightmost; // #endif // zero-sized? skip. // FIXME: look at timing instead? - if (instr1 > instr2) { + if (left_margin.dyninstr > right_margin.dyninstr) { continue; } - if (!add_trace_event(instr1, instr2, time1, time2, fake_ev, true)) { + if (!add_trace_event(left_margin, right_margin, fake_ev, true)) { LOG << "add_trace_event failed" << std::endl; return false; } diff --git a/tools/import-trace/Importer.hpp b/tools/import-trace/Importer.hpp index 4ac49b5b..60145aca 100644 --- a/tools/import-trace/Importer.hpp +++ b/tools/import-trace/Importer.hpp @@ -21,6 +21,7 @@ protected: public: typedef unsigned instruction_count_t; //!< not big enough for some benchmarks + struct margin_info_t { instruction_count_t dyninstr; fail::guest_address_t ip; fail::simtime_t time; }; Importer() : m_sanitychecks(false) {} bool init(const std::string &variant, const std::string &benchmark, fail::Database *db); @@ -28,8 +29,7 @@ public: virtual bool create_database() = 0; virtual bool copy_to_database(fail::ProtoIStream &ps); virtual bool clear_database(); - virtual bool add_trace_event(instruction_count_t begin, instruction_count_t end, - fail::simtime_t time_begin, fail::simtime_t time_end, + virtual bool add_trace_event(margin_info_t &begin, margin_info_t &end, const Trace_Event &event, bool is_fake = false) = 0; void set_elf_file(fail::ElfReader *elf) { m_elf = elf; } @@ -38,8 +38,8 @@ public: void set_sanitychecks(bool enabled) { m_sanitychecks = enabled; } protected: private: - struct leftmargin_info_t { instruction_count_t dyninstr; fail::simtime_t time; }; - typedef std::map AddrLastaccessMap; + + typedef std::map AddrLastaccessMap; }; #endif diff --git a/tools/prune-trace/BasicPruner.cc b/tools/prune-trace/BasicPruner.cc index 9b5b5f86..4d2402e1 100644 --- a/tools/prune-trace/BasicPruner.cc +++ b/tools/prune-trace/BasicPruner.cc @@ -13,7 +13,7 @@ bool BasicPruner::prune_all() { // 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"; + std::string injection_instr_absolute = this->use_instr1 ? "instr1_absolute" : "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 << ", "