cpn: Generic wrapper for injection point

As for the pandaboard to navigate fast to the injection
instruction we need to deliver a hop chain to the fail-client,
this commit adds a generic wrapper for a injection point.
For now we have only the two options hop chain and instruction
offset, so it is activated via a cmake ON/OFF switch.

Change-Id: Ic01a07a30ac386d4316e6d6d271baf1549db966a
This commit is contained in:
Lars Rademacher
2013-11-14 23:58:02 +01:00
parent 227f0fd7b4
commit c142818325
18 changed files with 747 additions and 4 deletions

View File

@ -43,7 +43,17 @@ if(BUILD_PANDA)
target_link_libraries(fail-client ${openocd_src_dir}/src/.libs/libopenocd.a ${openocd_src_dir}/jimtcl/libjim.a fail ${openocd_library_dependencies})
add_dependencies(fail-client libfailopenocd_external)
#copy the conf-files to build directory
# ensure, elf path is set for enabling openocd to read elf symbols
if(EXISTS $ENV{FAIL_ELF_PATH})
SET(PANDA_ELF_PATH $ENV{FAIL_ELF_PATH})
message(STATUS "[Fail*] PandaBoard ELF under test: ${PANDA_ELF_PATH}")
else()
message(FATAL_ERROR "Please set the FAIL_ELF_PATH enviroment variable to the binary under test.")
endif()
# copy the conf-files to build directory
# TODO: copy to install path on install!?
file(COPY ${openocd_src_dir}/tcl/ DESTINATION oocd_conf/ PATTERN openocd EXCLUDE)
get_filename_component(OOCD_CONF_FILES_PATH ${CMAKE_BINARY_DIR}/oocd_conf/ REALPATH)

View File

@ -7,15 +7,31 @@ set(SRCS
## Setup desired protobuf descriptions HERE ##
set(PROTOS
FailControlMessage.proto
DatabaseCampaignMessage.proto
${CMAKE_CURRENT_BINARY_DIR}/DatabaseCampaignMessage.proto
TracePlugin.proto
)
## Set concrete implementation of InjectionPointMessage
# ToDo: Define seperate symbol, so it can also be used in other build types
if(CONFIG_INJECTIONPOINT_HOPS)
set(PROTOS ${PROTOS} InjectionPointHopsMessage.proto)
set(CONCRETE_INJECTION_POINT InjectionPointHopsMessage.proto)
else(CONFIG_INJECTIONPOINT_HOPS)
set(PROTOS ${PROTOS} InjectionPointStepsMessage.proto)
set(CONCRETE_INJECTION_POINT InjectionPointStepsMessage.proto)
endif(CONFIG_INJECTIONPOINT_HOPS)
# Configure concrete protobuf message to be included by campaign message
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DatabaseCampaignMessage.proto.in
${CMAKE_CURRENT_BINARY_DIR}/DatabaseCampaignMessage.proto)
#### PROTOBUFS ####
find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Let protobuf compiler find defined file (DatabaseCampaignMessage) in binary tree
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${PROTOS})
add_library(fail-comm ${SRCS} ${PROTO_SRCS} ${PROTO_HDRS})

View File

@ -4,14 +4,22 @@ extend google.protobuf.FieldOptions {
optional bool sql_ignore = 32383 [ default = false];
}
import "@CONCRETE_INJECTION_POINT@";
message DatabaseCampaignMessage {
required int32 pilot_id = 1 [(sql_primary_key) = true];
required int32 variant_id = 2 [(sql_ignore) = true];
required int32 fspmethod_id = 3 [(sql_ignore) = true];
// ToDo: injection_instr can be deleted if all experiments switched to
// using generic InjectionPointMessage
required int32 injection_instr = 4 [(sql_ignore) = true];
optional int32 injection_instr_absolute = 5 [(sql_ignore) = true];
required int32 data_address = 6 [(sql_ignore) = true];
required int32 data_width = 7 [(sql_ignore) = true];
required string variant = 8 [(sql_ignore) = true];
required string benchmark = 9 [(sql_ignore) = true];
required InjectionPointMessage injection_point = 10 [(sql_ignore) = true];
}

View File

@ -0,0 +1,23 @@
message InjectionPointMessage {
// Costs of the hop chain on the PandaBoard
// ToDo: Could be eliminated, but it is nice for evaluation
optional uint32 costs = 3;
// If checkpoint must be used for this hop chain, id is set properly
optional uint32 checkpoint_id = 1;
// Repeated groups can't be defined as notempty, so a manual
// non-empty check is required at usage
// As we assume hops to always watch addresses of length 1, we
// don't encode the length in here
repeated group Hops = 2 {
required uint64 address = 1;
enum AccessType {
EXECUTE = 1;
READ = 2;
WRITE = 3;
}
required AccessType accesstype = 2;
}
}

View File

@ -0,0 +1,3 @@
message InjectionPointMessage {
required int32 injection_instr = 1;
}

View File

@ -23,6 +23,7 @@ OPTION(CONFIG_DISABLE_KEYB_INTERRUPTS "Target backend: Suppress keyboard inter
OPTION(SERVER_PERFORMANCE_MEASURE "Performance measurement in job-server" OFF)
OPTION(CONFIG_FAST_BREAKPOINTS "Enable fast breakpoints (requires breakpoint events to be enabled)" OFF)
OPTION(CONFIG_FAST_WATCHPOINTS "Enable fast watchpoints (requires memory access events to be enabled)" OFF)
OPTION(CONFIG_INJECTIONPOINT_HOPS "Enable hop chain trace navigation to injection point" OFF)
SET(SERVER_COMM_HOSTNAME "localhost" CACHE STRING "Job-server hostname or IP")
SET(SERVER_COMM_TCP_PORT "1111" CACHE STRING "Job-server TCP port")
SET(SERVER_OUT_QUEUE_SIZE "0" CACHE STRING "Queue size for outbound jobs (0 = unlimited)")

View File

@ -19,6 +19,7 @@
// Performance options
#cmakedefine CONFIG_FAST_BREAKPOINTS
#cmakedefine CONFIG_FAST_WATCHPOINTS
#cmakedefine CONFIG_INJECTIONPOINT_HOPS
// Save/restore functionality
#cmakedefine CONFIG_SR_RESTORE

View File

@ -4,6 +4,19 @@ set(SRCS
DatabaseCampaign.cc
)
# only compile concrete implementation of InjectionPoint
if(CONFIG_INJECTIONPOINT_HOPS)
set (SRCS ${SRCS} InjectionPointHops.cc)
else(CONFIG_INJECTIONPOINT_HOPS)
set (SRCS ${SRCS} InjectionPointSteps.cc)
endif(CONFIG_INJECTIONPOINT_HOPS)
add_library(fail-cpn ${SRCS})
# if hop-chains need to be calculated by the server, we
# the smarthopping module
if(CONFIG_INJECTIONPOINT_HOPS)
add_dependencies(fail-cpn fail-smarthopping)
endif(CONFIG_INJECTIONPOINT_HOPS)
add_dependencies(fail-cpn fail-comm)

View File

@ -4,7 +4,7 @@
#include "util/Logger.hpp"
#include "util/Database.hpp"
#include "comm/ExperimentData.hpp"
#include "InjectionPoint.hpp"
#ifndef __puma
#include <boost/thread.hpp>
@ -135,6 +135,11 @@ bool DatabaseCampaign::run_variant(Database::Variant variant) {
log_send << "Found " << experiment_count << " unfinished experiments in database. ("
<< variant.variant << "/" << variant.benchmark << ")" << std::endl;
// abstraction of injection point
// must not be initialized in loop, because hop chain calculator would loose state after loop pass
// and so for every hop chain it would have to begin calculating at trace instruction zero
ConcreteInjectionPoint ip;
sent_pilots = 0;
while ((row = mysql_fetch_row(pilots)) != 0) {
unsigned pilot_id = atoi(row[0]);
@ -147,10 +152,14 @@ bool DatabaseCampaign::run_variant(Database::Variant variant) {
pilot.set_pilot_id(pilot_id);
pilot.set_fspmethod_id(fspmethod_id);
pilot.set_variant_id(variant.id);
// ToDo: Remove this, if all experiments work with abstract API (InjectionPoint)
pilot.set_injection_instr(injection_instr);
pilot.set_variant(variant.variant);
pilot.set_benchmark(variant.benchmark);
ip.parseFromInjectionInstr(injection_instr);
ip.addToCampaignMessage(pilot);
if (row[4]) {
unsigned injection_instr_absolute = atoi(row[4]);
pilot.set_injection_instr_absolute(injection_instr_absolute);

View File

@ -0,0 +1,104 @@
#ifndef INJECTIONPOINT_HPP_
#define INJECTIONPOINT_HPP_
#include "comm/DatabaseCampaignMessage.pb.h"
#include "util/Logger.hpp"
#include "config/FailConfig.hpp"
namespace fail {
/**
* \class InjectionPointBase
*
* Interface for a generic InjectionPoint (e.g. trace instruction offset or
* hop chain) for use in the generic DatabaseCampaign. Every
* DataBaseCampaignMessage contains a concrete InjectionPoint.
*/
class InjectionPointBase {
protected:
InjectionPointMessage m_ip; // !< Protobuf message of concrete injection point, this class wraps
Logger m_log;
public:
InjectionPointBase() : m_log("InjectionPoint") {}
/**
* Parses generic representation from a injection instruction (trace offset).
* Used by server.
* @param inj_instr trace instruction offset to be parsed
*/
virtual void parseFromInjectionInstr(unsigned inj_instr) = 0;
/**
* Parses (extracts) generic representation from a DatabaseCampaignMessage.
* Used by client.
* @param pilot DatabaseCampaignMessage which contains a InjectionPoint
*/
void parseFromCampaignMessage(const DatabaseCampaignMessage &pilot) {m_ip.CopyFrom(pilot.injection_point());}
/**
* Adds generic representation to a DatabaseCampaignMessage
* @param pilot DatabaseCampaignMessage to which the generic protobuf representation will be added
*/
void addToCampaignMessage(DatabaseCampaignMessage &pilot) {pilot.mutable_injection_point()->CopyFrom(m_ip);}
/**
* Get a copy of the contained InjectionPointMessage
* @param ipm Generic InjectionPointMessage to which the content will be copied
*/
void copyInjectionPointMessage(InjectionPointMessage &ipm) {ipm.CopyFrom(m_ip);}
};
#ifdef CONFIG_INJECTIONPOINT_HOPS
#include "comm/InjectionPointHopsMessage.pb.h"
class SmartHops;
/**
* \class InjectionPointHops
*
* Concrete injection point which contains a hop chain to the target
* trace instruction.
*/
class InjectionPointHops : public InjectionPointBase {
private:
SmartHops *m_sa; // !< Hop calculator which generates the hop chain
uint32_t m_curr_inst; // !< Instruction for which currently a hop chain is available
public:
InjectionPointHops();
virtual ~InjectionPointHops();
/**
* Parses a hop chain from a injection instruction (trace offset).
* @param inj_instr trace instruction offset to be parsed
*/
virtual void parseFromInjectionInstr(unsigned inj_instr);
};
typedef InjectionPointHops ConcreteInjectionPoint;
#else
#include "comm/InjectionPointStepsMessage.pb.h"
/**
* \class InjectionPointSteps
*
* Concrete injection point which contains a trace instruction offset.
*/
class InjectionPointSteps : public InjectionPointBase {
public:
virtual ~InjectionPointSteps() {}
/**
* Parses a trace offset from a injection instruction (trace offset),
* so it effectively just stores the value in the protobuf message.
* @param inj_instr trace instruction offset to be parsed
*/
virtual void parseFromInjectionInstr(unsigned inj_instr);
};
typedef InjectionPointSteps ConcreteInjectionPoint;
#endif
} /* namespace fail */
#endif /* INJECTIONPOINT_HPP_ */

View File

@ -0,0 +1,40 @@
#include "InjectionPoint.hpp"
#include "util/smarthops/SmartHops.hpp"
namespace fail {
InjectionPointHops::InjectionPointHops() : InjectionPointBase(), m_sa(new SmartHops()), m_curr_inst(0) {
char * elfpath = getenv("FAIL_TRACE_PATH");
if(elfpath == NULL){
m_log << "FAIL_TRACE_PATH not set :(" << std::endl;
exit(-1);
}else{
m_sa->init((const char*)elfpath);
}
}
InjectionPointHops::~InjectionPointHops() {
delete m_sa;
}
void InjectionPointHops::parseFromInjectionInstr(unsigned inj_instr) {
// Already calculated result needed?
if (m_curr_inst == inj_instr) {
return;
}
// Non monotonic ascending injection instruction given?
if (m_curr_inst > inj_instr) {
m_log << "FATAL ERROR: Got not monotonic ascending values of injection instruction" << std::endl;
exit(-1);
}
if (!m_sa->calculateFollowingHop(m_ip, inj_instr)) {
m_log << "FATAL ERROR: Trace does not contain enough instructions (" << inj_instr << ")" << std::endl;
exit(-1);
}
m_curr_inst = inj_instr;
}
} /* namespace fail */

View File

@ -0,0 +1,10 @@
#include "InjectionPoint.hpp"
namespace fail {
void InjectionPointSteps::parseFromInjectionInstr(unsigned inj_instr) {
// compute hops
m_ip.set_injection_instr(inj_instr);
}
} /* namespace fail */

View File

@ -63,9 +63,16 @@ else()
endif()
mark_as_advanced(FAIL_OBJDUMP)
# compile smarthops calculator if needed
if(CONFIG_INJECTIONPOINT_HOPS)
add_subdirectory(smarthops)
set(ADDITIONAL_LIBS fail-smarthops)
endif(CONFIG_INJECTIONPOINT_HOPS)
add_library(fail-util ${SRCS})
add_dependencies(fail-util fail-comm)
target_link_libraries(fail-util ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LIB_IBERTY} ${ZLIB_LIBRARIES})
target_link_libraries(fail-util ${ADDITIONAL_LIBS} ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LIB_IBERTY} ${ZLIB_LIBRARIES})
option(BUILD_LLVM_DISASSEMBLER "Build the LLVM-based disassembler (LLVM 3.3 preferred, for 3.1 and 3.2 read doc/how-to-build.txt)" OFF)
if (BUILD_LLVM_DISASSEMBLER)

View File

@ -0,0 +1,10 @@
set(SRCS
SmartHops.cc
SmartHops.hpp
TraceReader.cc
TraceReader.hpp
)
add_library(fail-smarthops ${SRCS})
# ToDo: Do we really need this dependency?
add_dependencies(fail-smarthops fail-comm)

View File

@ -0,0 +1,247 @@
#include "SmartHops.hpp"
#include <algorithm>
#include <limits>
#include <vector>
namespace fail {
#define COST_CHANGE 1
#define COST_NO_CHANGE 2
void SmartHops::init(const char *filename) {
m_trace_reader.openTraceFile(filename);
}
void SmartHops::convertToIPM(std::vector<result_tuple > &result, unsigned costs, InjectionPointMessage &ipm) {
ipm.Clear();
// If checkpoint at beginning of hop-chain, add its id to HopChain
std::vector<result_tuple >::iterator it_hop = result.begin();
if (it_hop != result.end() && it_hop->first.second == ACCESS_CHECKPOINT) {
ipm.set_checkpoint_id(it_hop->first.first);
it_hop++;
}
ipm.set_costs(costs);
for(;it_hop != result.end();
it_hop++) {
InjectionPointMessage_Hops *hop = ipm.add_hops();
hop->set_address(it_hop->first.first);
enum InjectionPointMessage_Hops_AccessType at;
switch (it_hop->first.second) {
case ACCESS_NONE:
at = InjectionPointMessage_Hops_AccessType_EXECUTE;
break;
case ACCESS_READ:
at = InjectionPointMessage_Hops_AccessType_READ;
break;
case ACCESS_WRITE:
at = InjectionPointMessage_Hops_AccessType_WRITE;
break;
case ACCESS_READORWRITE:
m_log << "ReadOrWrite memory access event not yet"
" covered" << std::endl;
exit(-1);
break;
case ACCESS_CHECKPOINT:
m_log << "Checkpoint not allowed after beginning of hop chain" << std::endl;
exit(-1);
}
hop->set_accesstype(at);
}
}
bool SmartHops::calculateFollowingHop(InjectionPointMessage &ip, unsigned instruction_offset) {
while (m_trace_pos < instruction_offset) {
if (!m_trace_reader.getNextTraceEvents(m_trace_pos, m_trace_events)) {
return false;
}
// Policy when multiple trace events: Choose the one with smallest last_pos
trace_event_tuple_t *best_te = NULL;
trace_pos_t last_pos = std::numeric_limits<trace_pos_t>::max();
bool hop_found = false;
bool checkpoint_forbidden = false;
for (std::vector<trace_event_tuple_t >::iterator it_te = m_trace_events.begin();
it_te != m_trace_events.end();
it_te++) {
// Don't use watchpoints?
if (!m_use_watchpoints && it_te->second != ACCESS_NONE) {
continue;
}
// Find last pos of current trace event
std::map<trace_event_tuple_t, trace_pos_t>::iterator it_lp = m_last_positions.find(*it_te);
// Not known? => Single hop, result calculation complete
if (it_lp == m_last_positions.end()) {
m_last_positions.insert(std::pair<trace_event_tuple_t, trace_pos_t>(*it_te, m_trace_pos));
// New instruction => single hop
if (!hop_found) {
m_result.clear();
m_result.push_back(result_tuple(*it_te, m_trace_pos));
m_costs = COST_CHANGE;
hop_found = true;
}
} else {
if (it_lp->second < last_pos) {
last_pos = it_lp->second;
best_te = (trace_event_tuple_t*)&(it_lp->first);
}
it_lp->second = m_trace_pos;
}
}
if (hop_found) {
continue;
}
// Deltion of unnecessary hops
/*
* |----------------|
* |pos bigger than |
* |last pos of new | --> delete -->-|
* |trace_event? | |
* |----------------| |
* ^ |
* | v
* A B A C <<< Last result
* ^ ^
* Reverse Reverse
* iterator iterator
* rit_pre_last rit_last
*
*/
std::vector<result_tuple >::reverse_iterator rit_pre_last, rit_last, end;
rit_last = m_result.rbegin();
rit_pre_last = m_result.rbegin();
rit_pre_last++;
while (rit_last != m_result.rend()) {
trace_pos_t left_pos;
// Policy switch:
// No weights => last pos <= pos of rit_pre_last
// Weights => last pos < pos of rit_pre_last
if ((rit_pre_last == m_result.rend())) {
// First node in hop list is Checkpoint? => Look at result before CP-Creation
if (rit_last->first.second == ACCESS_CHECKPOINT) {
rit_pre_last = (m_checkpoints[rit_last->first.first]).second.rbegin();
// This should never happen:
if (rit_pre_last == (m_checkpoints[rit_last->first.first]).second.rend()) {
break;
}
// Don't allow deletion of CP, if afterwards
// too few of the olf hops would be deleted.
// (past before to be deleted CP)
// Should not exceed vector boundaries, if
// g_rollback_thresh*2 < (g_cp_thresh - g_cost_cp)
if ((*(rit_pre_last + m_rollback_thresh)).second < last_pos) {
checkpoint_forbidden = true;
break;
}
} else {
break;
}
}
left_pos = rit_pre_last->second;
if ((!m_use_weights && !(last_pos <= left_pos))
|| (m_use_weights && !(last_pos < left_pos))) {
break;
}
// Hop a->b is not allowed if last pos of b is at a
// but a is not b
// e.g. instruction x with mem access at y
// a is WP y, and b is BP x
// OR a is BP x, and b is WP y but instruction
// at position a has also memory access at y
if (rit_pre_last != m_result.rend()) {
if ((last_pos == rit_pre_last->second) &&
rit_pre_last->first != *best_te) {
break;
}
}
// Right hop will be deleted
// => Recalculate costs
// If to be deleted hop is a checkpoint:
// There will be no past in the trace
// Reconfigure result and iterators
if (rit_last->first.second == ACCESS_CHECKPOINT) {
m_costs = m_checkpoints[rit_last->first.first].first;
m_result.clear();
std::vector<result_tuple > *tmp = &(m_checkpoints[rit_last->first.first].second);
m_result.insert(m_result.end(), tmp->begin(), tmp->end());
rit_last = m_result.rbegin();
rit_pre_last = m_result.rbegin();
rit_pre_last++;
// CP could be removed from m_checkpoints, but to do this
// m_checkpoints needs to be a map (CP-ID is implicit as vector index)
continue;
}
if (rit_pre_last->first == rit_last->first) {
m_costs -= COST_NO_CHANGE;
} else {
m_costs -= COST_CHANGE;
}
// Delete element described by rit_last
// Deletion of elements described by reverse iterator works like this
m_result.erase((rit_last+1).base());
rit_last = rit_pre_last;
rit_pre_last++;
}
// Add costs for new hop
if (*best_te == (m_result.back()).first) {
m_costs += COST_NO_CHANGE;
} else {
m_costs += COST_CHANGE;
}
// Check if Checkpoint needed
if (m_use_checkpoints && (m_costs > m_cp_thresh) && !checkpoint_forbidden) {
checkpoint_tuple_t new_cp(m_costs, std::vector<result_tuple >(m_result));
m_checkpoints.push_back(new_cp);
m_result.clear();
m_result.push_back(result_tuple(trace_event_tuple_t(m_next_cp_id++,
ACCESS_CHECKPOINT),
m_trace_pos));
m_costs = m_cost_cp;
} else {
// Add new hop
m_result.push_back(result_tuple(*best_te, m_trace_pos));
}
}
InjectionPointMessage ipm;
convertToIPM(m_result, m_costs, ip);
return true;
}
} // end of namespace

View File

@ -0,0 +1,90 @@
#ifndef SMART_ALGORITHM__HPP
#define SMART_ALGORITHM__HPP
#include <map>
#include <vector>
#include "TraceReader.hpp"
#include "comm/InjectionPointHopsMessage.pb.h"
#include "util/Logger.hpp"
namespace fail {
typedef std::pair<trace_event_tuple_t, trace_pos_t > result_tuple;
// COSTS NAVIGATIONAL RECORD
typedef std::pair<unsigned int, std::vector<result_tuple > > checkpoint_tuple_t;
/**
* \class SmartHops
*
* Calculator for (optimal) hop chains on the basis of a simple cost model.
* Currently hardcoded cost model for PandaBoard (horizontal hops cost
* twice as much as diagonal hops).
* Calculates stream based (only regarding the next trace event) and so
* it can only calculate for ascending trace instruction offsets.
*/
class SmartHops {
public:
// ToDo: If you want to use checkoints as additional hop-chain-element, you may switch
// m_use_checkpoints to true, but there will be additional changes needed for this to fully work.
// The sal must, for example, generate CPs at the given positions
SmartHops() : m_trace_pos(0), m_costs(0), m_next_cp_id(0), m_log("SmartHops", false), m_use_watchpoints(true),
m_use_weights(true), m_use_checkpoints(false), m_cp_thresh(0), m_cost_cp(0), m_rollback_thresh(0){}
/**
* Initializes the used TraceReader with given trace file path
* @param filename Path to the trace file
*/
void init(const char *filename);
/**
* Initializes the used TraceReader with given trace file path
* @param filename Path to the trace file
* @returns \c true if calculation succeeded and \c false if it did not
*/
bool calculateFollowingHop(InjectionPointMessage &ip, unsigned instruction_offset);
private:
/**
* Converts internal representation of a hop chain to a
* InjectionPointMessage. The delivered InjectionPointMessage is
* cleared before parsing.
* @param result Internal representation of a hop chain
* @param costs Costs of the hop chain (extracted from cost model)
* @param ipm InjectionPointMessage to which the hop chain is parsed
*/
void convertToIPM(std::vector<result_tuple > &result, unsigned costs, InjectionPointMessage &ipm);
unsigned int m_trace_pos;
unsigned int m_costs;
TraceReader m_trace_reader;
unsigned int m_next_cp_id;
Logger m_log;
bool m_use_watchpoints;
bool m_use_weights;
bool m_use_checkpoints;
unsigned int m_cp_thresh;
unsigned int m_cost_cp;
// Must be smaller than ((COST_CP_THRESH - COST_CP) / 2)
// If too high: Costs per dynamic instruction will approach
// COST_CP_THRESH but number of CPs can be reduced drastically
unsigned int m_rollback_thresh;
std::map<trace_event_tuple_t, trace_pos_t> m_last_positions;
std::vector<checkpoint_tuple_t > m_checkpoints;
std::vector<trace_event_tuple_t > m_trace_events;
std::vector<result_tuple > m_result;
};
} // end of namespace
#endif // SMART_ALGORITHM__HPP

View File

@ -0,0 +1,97 @@
#include "TraceReader.hpp"
#include <iostream>
#include <fstream>
#include <string>
using std::endl;
using fail::ProtoIStream;
namespace fail {
TraceReader::~TraceReader()
{
delete ps;
delete normal_stream;
delete gz_stream;
}
std::istream& openStream(const char *input_file,
std::ifstream& normal_stream, igzstream& gz_stream, Logger &out_stream) {
normal_stream.open(input_file);
if (!normal_stream) {
out_stream << "FATAL ERROR: couldn't open " << input_file << endl;
exit(-1);
}
unsigned char b1, b2;
normal_stream >> b1 >> b2;
if (b1 == 0x1f && b2 == 0x8b) {
normal_stream.close();
gz_stream.open(input_file);
if (!gz_stream) {
out_stream << "couldn't open " << input_file << endl;
exit(-1);
}
return gz_stream;
}
normal_stream.seekg(0);
return normal_stream;
}
void TraceReader::openTraceFile(const char *filename)
{
normal_stream = new std::ifstream();
gz_stream = new igzstream();
ps = new fail::ProtoIStream(&openStream(filename, *normal_stream, *gz_stream, m_log));
}
bool TraceReader::getNextTraceEvents(trace_pos_t& trace_pos,
std::vector<trace_event_tuple_t >& trace_events)
{
trace_pos = m_current_position;
// Delivered trace_events vector does not have to be
// empty, so it must be cleared
trace_events.clear();
if (m_current_position == 1) {
if (!ps->getNext(&ev)) {
return false;
}
ev_avail = true;
}
if (!ev_avail) {
return false;
}
trace_events.push_back(trace_event_tuple_t(ev.ip(), ACCESS_NONE));
ev_avail = false;
// read possible memory accesses and the next instruction
while (ps->getNext(&ev)) {
if (!ev.has_memaddr()) {
ev_avail = true;
break;
}
// Add a trace_event for every byte in memory access.
// This breaks down the calculations to multiple
// memory accesses of length 1. No more complexity
// is needed in hop calculations.
if (ev.has_width()) {
for (unsigned int i = 0; i < ev.width(); i++) {
trace_events.push_back(
trace_event_tuple_t(ev.memaddr() + i,
ev.accesstype() == ev.READ ? ACCESS_READ : ACCESS_WRITE));
}
}
}
m_current_position++;
return true;
}
} // end of namespace

View File

@ -0,0 +1,54 @@
#ifndef __TRACE_READER_HPP
#define __TRACE_READER_HPP
#include <vector>
#include <iostream>
#include "../ProtoStream.hpp"
#include "comm/TracePlugin.pb.h"
#include "../gzstream/gzstream.h"
#include "util/Logger.hpp"
namespace fail {
typedef enum {
ACCESS_NONE ,
ACCESS_READ ,
ACCESS_WRITE ,
ACCESS_READORWRITE , // some architectures can't distinguish read and write WPs in general (e.g. x86)
ACCESS_CHECKPOINT ,
} mem_access_type_e;
typedef uint32_t address_t;
typedef uint32_t trace_pos_t;
typedef std::pair<address_t, mem_access_type_e> trace_event_tuple_t;
class TraceReader {
public:
TraceReader() : m_current_position(1), ps(0), normal_stream(0),
gz_stream(0), ev_avail(false), m_log("TraceReader", false) {}
~TraceReader();
// Returns ACCESS_NONE in mem_access if current instruction does not access memory
bool getNextTraceEvents(trace_pos_t& trace_pos,
std::vector<trace_event_tuple_t >& trace_events);
void openTraceFile(const char *filename);
private:
unsigned int m_current_position;
ProtoIStream* ps;
std::ifstream *normal_stream;
igzstream *gz_stream;
Trace_Event ev;
bool ev_avail;
Logger m_log;
};
} // end of namespace
#endif //__TRACE_HPP