Merge branch 'failpanda'

Conflicts:
	src/core/comm/DatabaseCampaignMessage.proto.in
	src/core/cpn/CMakeLists.txt
	src/core/cpn/DatabaseCampaign.cc
	src/core/sal/ConcreteCPU.hpp
	src/core/sal/SALConfig.hpp
	src/core/util/CMakeLists.txt

Change-Id: Id86b93d0e3ea4d9963fcc88605eec0603575ec83
This commit is contained in:
Horst Schirmeier
2014-06-03 12:24:38 +02:00
1230 changed files with 579380 additions and 28 deletions

View File

@ -70,15 +70,21 @@ 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 fail-comm ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LibIberty_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBDWARF_LIBRARIES} ${LIBELF_LIBRARIES})
target_link_libraries(fail-util fail-comm ${ADDITIONAL_LIBS} ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LibIberty_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBDWARF_LIBRARIES} ${LIBELF_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)
add_subdirectory(llvmdisassembler)
endif (BUILD_LLVM_DISASSEMBLER)
### Tests
add_executable(memorymap-test testing/memorymap-test.cc)
target_link_libraries(memorymap-test fail-util)

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,260 @@
#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++;
}
if (result.size() > 0 && result.back().first.second != ACCESS_CHECKPOINT) {
ipm.set_target_trace_position(result.back().second);
} else {
ipm.set_target_trace_position(0);
}
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) {
if (instruction_offset == 0) {
m_result.clear();
m_costs = 0;
convertToIPM(m_result, m_costs, ip);
return true;
}
while (m_trace_pos < instruction_offset) {
//m_log << "Calculating " << instruction_offset << std::endl;
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;
}
// Deletion 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,106 @@
#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;
}
bool TraceReader::openTraceFile(const char *filename, unsigned int num_inst)
{
normal_stream = new std::ifstream();
gz_stream = new igzstream();
ps = new fail::ProtoIStream(&openStream(filename, *normal_stream, *gz_stream, m_log));
m_max_num_inst = num_inst;
return true;
}
bool TraceReader::getNextTraceEvents(trace_pos_t& trace_pos,
std::vector<trace_event_tuple_t >& trace_events)
{
// Stop after fixed number of instructions, if given as command line argument
if ((m_max_num_inst > 0) && (m_current_position > m_max_num_inst)) {
return false;
}
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,60 @@
#ifndef __TRACE_READER_HPP
#define __TRACE_READER_HPP
#include <vector>
#include <iostream>
#include "sal/SALConfig.hpp"
#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 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),
m_max_num_inst(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);
bool openTraceFile(const char *filename, unsigned int num_inst = 0);
private:
unsigned int m_current_position;
ProtoIStream* ps;
std::ifstream *normal_stream;
igzstream *gz_stream;
unsigned int m_max_num_inst;
Trace_Event ev;
bool ev_avail;
Logger m_log;
};
} // end of namespace
#endif //__TRACE_HPP