Files
fail/tools/import-trace/Importer.hpp
Horst Schirmeier 64b3af299e import-trace: sliding-window AdvancedMemoryImporter
Initially this was implemented by directly passing through trace
events to the MemoryImporter, keeping a record of conditional jumps
and opcodes, and UPDATEing all inserted rows in a second pass when the
MemoryImporter is finished.

Unfortunately, UPDATE is very slow, and keeping all information in
memory till the end doesn't scale indefinitely.  Therefore the
implementation now delays passing memory access events upwards to the
MemoryImporter only until enough branch history is aggregated, and
taps into Importer's database operations with a set of new virtual
functions that are called downwards.

Change-Id: I159b2533932087087fb3049f4ff07a5f17a25a00
2013-09-10 17:37:26 +02:00

134 lines
4.8 KiB
C++

#ifndef __IMPORTER_H__
#define __IMPORTER_H__
#include <mysql/mysql.h>
#include <map>
#include "util/ProtoStream.hpp"
#include "util/ElfReader.hpp"
#include "sal/SALConfig.hpp"
#include "sal/Architecture.hpp"
#include "util/Database.hpp"
#include "util/MemoryMap.hpp"
#include "comm/TracePlugin.pb.h"
class Importer {
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; };
struct access_info_t { char access_type; fail::guest_address_t data_address; int data_width; };
protected:
int m_variant_id;
fail::ElfReader *m_elf;
fail::MemoryMap *m_mm;
char m_faultspace_rightmargin;
bool m_sanitychecks;
bool m_extended_trace;
fail::Database *db;
fail::Architecture m_arch;
fail::UniformRegisterSet *m_extended_trace_regs;
/* How many rows were inserted into the database */
unsigned m_row_count;
// time the trace started/ended
fail::simtime_t m_time_trace_start;
/* map for keeping one "open" EC for every address
(maps injection data address =>
dyn. instruction count / time information for equivalence class
left margin) */
typedef std::map<fail::address_t, margin_info_t> AddrLastaccessMap;
AddrLastaccessMap m_open_ecs;
margin_info_t getOpenEC(fail::address_t data_address) {
margin_info_t ec = m_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 (ec.time == 0) {
ec.time = m_time_trace_start;
}
return ec;
}
void newOpenEC(fail::address_t data_address, fail::simtime_t time, instruction_count_t dyninstr,
fail::guest_address_t ip) {
m_open_ecs[data_address].dyninstr = dyninstr;
m_open_ecs[data_address].time = time;
// FIXME: This should be the next IP, not the current, or?
m_open_ecs[data_address].ip = ip;
}
fail::guest_address_t m_last_ip;
instruction_count_t m_last_instr;
fail::simtime_t m_last_time;
public:
Importer() : m_sanitychecks(false), m_extended_trace(false), m_row_count(0), m_time_trace_start(0) {}
bool init(const std::string &variant, const std::string &benchmark, fail::Database *db);
/**
* Callback function that can be used to add command line options
* to the cmd interface
*/
virtual bool cb_commandline_init() { return true; }
virtual bool create_database();
/**
* Allows specialized importers to add more table columns instead of
* completely overriding create_database(). The returned SQL CREATE TABLE
* snippet should be terminated with a comma if non-empty. Should call and
* pass through their parent's implementation.
*/
virtual std::string database_additional_columns() { return ""; }
/**
* Similar to database_additional_columns(), this allows specialized
* importers to define which additional columns it wants to INSERT
* alongside what add_trace_event() adds by itself. This may be identical
* to or a subset of what database_additional_columns() specifies. The SQL
* snippet should *begin* with a comma if non-empty.
*/
virtual void database_insert_columns(std::string& sql, unsigned& num_columns) { num_columns = 0; }
/**
* Will be called back from add_trace_event() to fill in data for the
* columns specified by database_insert_columns().
*/
virtual bool database_insert_data(Trace_Event &ev, MYSQL_BIND *bind, unsigned num_columns, bool is_fake) { return true; }
virtual bool copy_to_database(fail::ProtoIStream &ps);
virtual bool clear_database();
/**
* Use this variant if passing through the IP/MEM event does not make any
* sense for your Importer implementation.
*/
virtual bool add_trace_event(margin_info_t &begin, margin_info_t &end,
access_info_t &event, bool is_fake = false);
/**
* Use this variant for passing through the IP/MEM event your Importer
* received.
*/
virtual bool add_trace_event(margin_info_t &begin, margin_info_t &end,
Trace_Event &event, bool is_fake = false);
virtual void open_unused_ec_intervals();
virtual bool close_ec_intervals();
virtual bool handle_ip_event(fail::simtime_t curtime, instruction_count_t instr,
Trace_Event &ev) = 0;
virtual bool handle_mem_event(fail::simtime_t curtime, instruction_count_t instr,
Trace_Event &ev) = 0;
/**
* May be overridden by importers that need to do stuff after the last
* event was consumed.
*/
virtual bool trace_end_reached() { return true; }
void set_elf(fail::ElfReader *elf) { m_elf = elf; }
void set_memorymap(fail::MemoryMap *mm) { m_mm = mm; }
void set_faultspace_rightmargin(char accesstype) { m_faultspace_rightmargin = accesstype; }
void set_sanitychecks(bool enabled) { m_sanitychecks = enabled; }
void set_extended_trace(bool enabled) { m_extended_trace = enabled; }
};
#endif