DCiAOKernelImporter: different injection semantic.

Is now very similar to normal importer, and may be deleted in the future, but
at the moment, this should be merged, since it is the importer used in the
sobres-2013 paper.

This changes the MySQL Schema. instr1_absolute was introduced.

Change-Id: I1bc2919bd14c335beca6d586b7cc0f80767ad7d5
This commit is contained in:
Christian Dietrich
2013-04-10 17:37:23 +02:00
parent 6d8b3331d8
commit 6789a313a9
10 changed files with 85 additions and 62 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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<fail::address_t, leftmargin_info_t> AddrLastaccessMap;
typedef std::map<fail::address_t, margin_info_t> AddrLastaccessMap;
};
#endif