Aspect-based implementation of fast breakpoints added (optional).
git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1685 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
23
src/core/sal/perf/BreakpointBuffer.cc
Normal file
23
src/core/sal/perf/BreakpointBuffer.cc
Normal file
@ -0,0 +1,23 @@
|
||||
#include "BreakpointBuffer.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
namespace fail {
|
||||
|
||||
// FIXME: not inlined
|
||||
ResultSet& PerfVectorBreakpoints::gather(BPEvent* pData)
|
||||
{
|
||||
static ResultSet res;
|
||||
res.clear();
|
||||
// Search for all indices of matching listener objects:
|
||||
for(std::vector<index_t>::iterator it = m_BufList.begin(); it != m_BufList.end(); ++it) {
|
||||
BPListener* pLi = static_cast<BPListener*>(simulator.dereference(*it));
|
||||
if (pLi->isMatching(pData)) {
|
||||
// Update trigger IPtr:
|
||||
pLi->setTriggerInstructionPointer(pData->getTriggerInstructionPointer());
|
||||
res.add(*it);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // end-of-namespace: fail
|
||||
157
src/core/sal/perf/BreakpointBuffer.hpp
Normal file
157
src/core/sal/perf/BreakpointBuffer.hpp
Normal file
@ -0,0 +1,157 @@
|
||||
#ifndef __BREAKPOINT_BUFFER_HPP__
|
||||
#define __BREAKPOINT_BUFFER_HPP__
|
||||
|
||||
#include "BufferInterface.hpp"
|
||||
#include "../Listener.hpp"
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
// TODOs:
|
||||
// - Make these implementations even faster (see below: continue PerfVecSortedSingleBP).
|
||||
// - The implementation of gather() (see below) in BreakpointBuffer.cc (not inlined in
|
||||
// .hpp) avoids an include cycle. Unfortunately, this may cause a bad performance
|
||||
// because gather() won't be inlined anymore! (The method is called quite often.)
|
||||
|
||||
namespace fail {
|
||||
|
||||
class BPEvent;
|
||||
|
||||
/**
|
||||
* \class ResultSet
|
||||
*
|
||||
* Results (= indices of matching listeners) returned by the "gather"-method,
|
||||
* see below. (This class can be seen as a "temporary fire-list".)
|
||||
*/
|
||||
class ResultSet {
|
||||
std::vector<index_t> m_Res;
|
||||
public:
|
||||
ResultSet() { }
|
||||
bool hasMore() const { return !m_Res.empty(); }
|
||||
index_t getNext() { index_t idx = m_Res.back(); m_Res.pop_back(); return idx; }
|
||||
void add(index_t idx) { m_Res.push_back(idx); }
|
||||
size_t size() const { return m_Res.size(); }
|
||||
void clear() { m_Res.clear(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Concrete implementation of the PerfBufferBase class for \c std::vector
|
||||
* and \c BPSingleListener.
|
||||
*/
|
||||
class PerfVectorBreakpoints : public PerfBufferBase {
|
||||
protected:
|
||||
std::vector<index_t> m_BufList;
|
||||
public:
|
||||
void add(index_t idx) { m_BufList.push_back(idx); }
|
||||
void remove(index_t idx)
|
||||
{
|
||||
for (std::vector<index_t>::iterator it = m_BufList.begin();
|
||||
it != m_BufList.end(); ++it) {
|
||||
if (*it == idx) {
|
||||
m_BufList.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void clear() { m_BufList.clear(); }
|
||||
size_t size() const { return m_BufList.size(); }
|
||||
ResultSet& gather(BPEvent* pData);
|
||||
};
|
||||
|
||||
/**
|
||||
* \class PerfVecSortedSingleBP
|
||||
*
|
||||
* This class implements a faster mechanism to store BPSingleListener
|
||||
* based on binary search on their corresponding instruction pointer.
|
||||
*/
|
||||
/*
|
||||
class PerfVecSortedSingleBP : public PerfVectorBreakpoints {
|
||||
private:
|
||||
SimulatorController* m_Sim;
|
||||
public:
|
||||
PerfVecSortedSingleBP(SimulatorController* pSim) : m_Sim(pSim) { }
|
||||
**
|
||||
* TODO.
|
||||
* @warning The method expects that \c idx is a valid index within the main
|
||||
* buffer-list. Therefore we are allowed to call \c SimulatorController::dereference().
|
||||
* Additionally, the indexed listener is epected to be of type \c BPListener*.
|
||||
*
|
||||
void add(index_t idx)
|
||||
{
|
||||
address_t watchIP = static_cast<BPSingleListener*>(m_Sim->dereference(idx))->getWatchInstructionPointer();
|
||||
// Keep the indices sorted in ascending order regarding their instr. ptr.
|
||||
// Search for the slot to insert the element (skip lower IPs):
|
||||
int pos = binarySearch(m_BufList, 0, m_BufList.size()-1, idx);
|
||||
assert(pos < 0 && "FATAL ERROR: Element already inserted!");
|
||||
m_BufList.insert(it + (pos * (-1) + 1), idx);
|
||||
// for (std::vector<index_t>::iterator it = m_BufList.begin(); it != m_BufList.end(); ++it) {
|
||||
// if (static_cast<BPSingleListener*>(
|
||||
// m_Sim->dereference(*it))->getWatchInstructionPointer() > watchIP) {
|
||||
// m_BufList.insert(it, idx); // Insert the element before "it"
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
static bool CompareInstrPtr(index_t arg1, index_t arg2, void* pStuff)
|
||||
{
|
||||
SimulatorController* pSim = static_cast<SimulatorController*>(pStuff);
|
||||
#define VAL(idx) \
|
||||
static_cast<BPSingleListener*>(pSim->dereference(idx))->getWatchInstructionPointer()
|
||||
return (VAL(arg1) > VAL(arg2);
|
||||
}
|
||||
|
||||
**
|
||||
* Searches vec[first]...vec[last] for \c key. Returns the index of the matching
|
||||
* element if it finds key, otherwise -(index where it could be inserted)-1.
|
||||
* @param vec array of sorted (ascending) values.
|
||||
* @param first lower subscript bound
|
||||
* @param last upper subscript bound
|
||||
* @param key value to search for
|
||||
* @param pfnCmp a function pointer to a comparison function, returning \c true
|
||||
* if the first argument is greater than the second, otherwise \c false.
|
||||
* The last parameter equals the last parameter provided by calling this
|
||||
* method. It can be used to pass additional data.
|
||||
* @return index of key, or -insertion_position -1 if key is not in the array.
|
||||
* This value can easily be transformed into the position to insert it.
|
||||
*
|
||||
int binarySearch(const std::vector<index_t>& vec, index_t first, index_t last, index_t key, bool (*pfnCmp)(index_t, index_t, void*), void* pStuff = NULL)
|
||||
{
|
||||
|
||||
while (first <= last) {
|
||||
int mid = (first + last) / 2; // compute mid point.
|
||||
if (VAL(key) > VAL(vec[mid]))
|
||||
first = mid + 1; // repeat search in top half.
|
||||
else if (VAL(key) < VAL(vec[mid]))
|
||||
last = mid - 1; // repeat search in bottom half.
|
||||
else
|
||||
return mid; // found it. return position
|
||||
}
|
||||
return -(first + 1); // failed to find key
|
||||
}
|
||||
void remove(index_t idx)
|
||||
{
|
||||
int pos = binarySearch(m_BufList, 0, m_BufList.size()-1, idx, CompareInstrPtr, m_Sim);
|
||||
if (pos >= 0)
|
||||
m_BufList.erase(m_BufList.begin() + pos);
|
||||
}
|
||||
ResultSet& gather(BPEvent* pData)
|
||||
{
|
||||
// TODO: Improve this by using binary search, too!
|
||||
ResultSet res;
|
||||
// Search for all indices of matching listener objects:
|
||||
for(std::vector<index_t>::iterator it = m_BufList.begin(); it != m_BufList.end(); ++it) {
|
||||
BPListener* pLi = static_cast<BPListener*>(simulator.dereference(*it));
|
||||
if (pLi->isMatching(pData)) {
|
||||
// Update trigger IPtr:
|
||||
pLi->setTriggerInstructionPointer(pData->getTriggerInstructionPointer());
|
||||
res.add(*it);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __BREAKPOINT_BUFFER_HPP__
|
||||
49
src/core/sal/perf/BreakpointControllerSlice.ah
Normal file
49
src/core/sal/perf/BreakpointControllerSlice.ah
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef __BREAKPOINT_CONTROLLER_SLICE_AH__
|
||||
#define __BREAKPOINT_CONTROLLER_SLICE_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_FAST_BREAKPOINTS
|
||||
|
||||
#include <iostream>
|
||||
#include "../Listener.hpp"
|
||||
|
||||
/**
|
||||
* \class BreakpointControllerSlice
|
||||
*
|
||||
* The slice class definition to be used with FastBreakpoint.ah.
|
||||
* The members of this class will be sliced into the \c SimulatorController class.
|
||||
*/
|
||||
slice class BreakpointControllerSlice {
|
||||
public:
|
||||
bool addListener(fail::BPSingleListener* sli)
|
||||
{
|
||||
assert(sli != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!");
|
||||
m_LstList.add(sli, m_Flows.getCurrent());
|
||||
// Call the common postprocessing function:
|
||||
if (!sli->onAddition()) { // If the return value signals "false"...,
|
||||
m_LstList.remove(sli); // ...skip the addition
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fail::BaseListener* addListenerAndResume(fail::BPSingleListener* sli)
|
||||
{ addListener(sli); return resume(); }
|
||||
bool addListener(fail::BPRangeListener* rli)
|
||||
{
|
||||
assert(rli != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!");
|
||||
m_LstList.add(rli, m_Flows.getCurrent());
|
||||
// Call the common postprocessing function:
|
||||
if (!rli->onAddition()) { // If the return value signals "false"...,
|
||||
m_LstList.remove(rli); // ...skip the addition
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
fail::BaseListener* addListenerAndResume(fail::BPRangeListener* rli)
|
||||
{ addListener(rli); return resume(); }
|
||||
};
|
||||
|
||||
#endif // CONFIG_FAST_BREAKPOINTS
|
||||
|
||||
#endif // __BREAKPOINT_CONTROLLER_SLICE_AH__
|
||||
56
src/core/sal/perf/BreakpointManagerSlice.ah
Normal file
56
src/core/sal/perf/BreakpointManagerSlice.ah
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef __BREAKPOINT_MANAGER_SLICE_AH__
|
||||
#define __BREAKPOINT_MANAGER_SLICE_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_FAST_BREAKPOINTS
|
||||
|
||||
#include "BreakpointBuffer.hpp"
|
||||
|
||||
/**
|
||||
* \class BreakpointManagerSlice
|
||||
*
|
||||
* The slice class definition to be used with FastBreakpoint.ah.
|
||||
* The members of this class will be sliced into the \c ListenerManager class.
|
||||
*/
|
||||
slice class BreakpointManagerSlice {
|
||||
private:
|
||||
fail::PerfVectorBreakpoints m_SingleListeners;
|
||||
fail::PerfVectorBreakpoints m_RangeListeners;
|
||||
public:
|
||||
fail::PerfVectorBreakpoints& getSingleListeners() { return m_SingleListeners; }
|
||||
fail::PerfVectorBreakpoints& getRangeListeners() { return m_RangeListeners; }
|
||||
|
||||
void add(fail::BPSingleListener* sli, fail::ExperimentFlow* flow)
|
||||
{
|
||||
assert(sli != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!");
|
||||
sli->setParent(flow);
|
||||
// (1) Add sli to the main buffer-list, ...
|
||||
m_BufferList.push_back(sli);
|
||||
// (2) ... update it's location (index) / performance-buffer (ptr) and ...
|
||||
fail::index_t idx = m_BufferList.size()-1;
|
||||
assert(m_BufferList[idx] == sli && "FATAL ERROR: Invalid index after push_back() unexpected!");
|
||||
sli->setLocation(idx);
|
||||
sli->setPerformanceBuffer(&m_SingleListeners);
|
||||
// (3) ... add this index to the m_SingleListeners vector.
|
||||
m_SingleListeners.add(idx);
|
||||
}
|
||||
void add(fail::BPRangeListener* rli, fail::ExperimentFlow* flow)
|
||||
{
|
||||
assert(rli != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!");
|
||||
rli->setParent(flow);
|
||||
// (1) Add sli to the main buffer-list, ...
|
||||
m_BufferList.push_back(rli);
|
||||
// (2) ... update it's location (index) / performance-buffer (ptr) and ...
|
||||
fail::index_t idx = m_BufferList.size()-1;
|
||||
assert(m_BufferList[idx] == rli && "FATAL ERROR: Invalid index after push_back() unexpected!");
|
||||
rli->setLocation(idx);
|
||||
rli->setPerformanceBuffer(&m_RangeListeners);
|
||||
// (3) ... add this index to the m_RangeListeners vector.
|
||||
m_RangeListeners.add(idx);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_FAST_BREAKPOINTS
|
||||
|
||||
#endif // __BREAKPOINT_MANAGER_SLICE_AH__
|
||||
42
src/core/sal/perf/BufferInterface.hpp
Normal file
42
src/core/sal/perf/BufferInterface.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef __BUFFER_INTERFACE_HPP__
|
||||
#define __BUFFER_INTERFACE_HPP__
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace fail {
|
||||
|
||||
typedef std::size_t index_t; //!< the index type of elements, stored in the buffer-list
|
||||
const index_t INVALID_INDEX = static_cast<index_t>(-1); //!< a constant, representing an invalid idx
|
||||
|
||||
/**
|
||||
* \class PerfBufferBase
|
||||
*
|
||||
* Generic performance data structure for storing often used listener objects
|
||||
* (This class can be seen as a "fast, type specific buffer-list".)
|
||||
*/
|
||||
class PerfBufferBase {
|
||||
public:
|
||||
/**
|
||||
* Adds the index \c idx to the performance buffer-list.
|
||||
* @param idx the element to be added
|
||||
*/
|
||||
virtual void add(index_t idx) = 0;
|
||||
/**
|
||||
* Removes the specified index \c idx.
|
||||
* @param idx the element to be deleted
|
||||
*/
|
||||
virtual void remove(index_t idx) = 0;
|
||||
/**
|
||||
* Removes all elements from the perf. buffer-list.
|
||||
*/
|
||||
virtual void clear() = 0;
|
||||
/**
|
||||
* Retrieves the number of elements in this data structure.
|
||||
* @return the number of elements in the perf. buffer-list
|
||||
*/
|
||||
virtual std::size_t size() const = 0;
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
#endif // __BUFFER_INTERFACE_HPP__
|
||||
85
src/core/sal/perf/FastBreakpoints.ah
Normal file
85
src/core/sal/perf/FastBreakpoints.ah
Normal file
@ -0,0 +1,85 @@
|
||||
#ifndef __FAST_BREAKPOINTS_AH__
|
||||
#define __FAST_BREAKPOINTS_AH__
|
||||
|
||||
#include "config/FailConfig.hpp"
|
||||
|
||||
#ifdef CONFIG_FAST_BREAKPOINTS
|
||||
|
||||
#ifndef CONFIG_EVENT_BREAKPOINTS
|
||||
#error Breakpoint events are required for fast breakpoints!
|
||||
#endif
|
||||
|
||||
#include "BreakpointManagerSlice.ah" // slice class "BreakpointManagerSlice"
|
||||
#include "BreakpointControllerSlice.ah" // slice class "BreakpointControllerSlice"
|
||||
#include "../ListenerManager.hpp"
|
||||
#include "../Listener.hpp"
|
||||
#include "BreakpointBuffer.hpp"
|
||||
#include "../SALInst.hpp"
|
||||
|
||||
// TODOs:
|
||||
// - Check if this solutation works, even if there are more than one
|
||||
// active performance aspects.
|
||||
|
||||
aspect FastBreakpoints {
|
||||
|
||||
// Refer to slice classes:
|
||||
advice "fail::ListenerManager" : slice BreakpointManagerSlice;
|
||||
advice "fail::SimulatorController" : slice BreakpointControllerSlice;
|
||||
|
||||
// These around-advices handle the (special) case where an experiment
|
||||
// adds a listener object casted to the base type but actually has the
|
||||
// BPSingle- or BPRangeListener type.
|
||||
advice execution("bool fail::SimulatorController::addListener(fail::BaseListener*)") : around ()
|
||||
{
|
||||
// Note: The logic to update the performance buffer-list is
|
||||
// placed in the addListener() methods.
|
||||
fail::BaseListener* pLi = *(tjp->arg<0>());
|
||||
fail::BPSingleListener* pSi = dynamic_cast<fail::BPSingleListener*>(pLi);
|
||||
fail::BPRangeListener* pRi = dynamic_cast<fail::BPRangeListener*>(pLi);
|
||||
if (pSi != NULL)
|
||||
*(tjp->result()) = tjp->that()->addListener(pSi);
|
||||
else if (pRi != NULL)
|
||||
*(tjp->result()) = tjp->that()->addListener(pRi);
|
||||
else
|
||||
tjp->proceed();
|
||||
}
|
||||
advice call("BaseListener* fail::SimulatorController::addListenerAndResume(fail::BaseListener*)") : around ()
|
||||
{
|
||||
// Note: The logic to update the performance buffer-list is
|
||||
// placed in the addListenerAndResume methods.
|
||||
fail::BaseListener* pLi = *(tjp->arg<0>());
|
||||
fail::BPSingleListener* pSi = dynamic_cast<fail::BPSingleListener*>(pLi);
|
||||
fail::BPRangeListener* pRi = dynamic_cast<fail::BPRangeListener*>(pLi);
|
||||
if (pSi != NULL)
|
||||
*(tjp->result()) = tjp->that()->addListenerAndResume(pSi);
|
||||
else if (pRi != NULL)
|
||||
*(tjp->result()) = tjp->that()->addListenerAndResume(pRi);
|
||||
else
|
||||
tjp->proceed();
|
||||
}
|
||||
|
||||
// The event handler for employing breakpoint events.
|
||||
advice execution("void fail::%Controller::onBreakpoint(...)") : around ()
|
||||
{
|
||||
// Note: "BPListener" is an abstract class anyway.
|
||||
|
||||
fail::ListenerManager& ref = tjp->target()->m_LstList;
|
||||
fail::BPEvent tmp(*(tjp->arg<0>()), *(tjp->arg<1>()));
|
||||
|
||||
// Check for matching BPSingleListeners:
|
||||
fail::ResultSet& res1 = ref.getSingleListeners().gather(&tmp);
|
||||
while (res1.hasMore())
|
||||
ref.makeActive(ref.dereference(res1.getNext()));
|
||||
|
||||
// Check for matching BPRangeListeners:
|
||||
fail::ResultSet& res2 = ref.getRangeListeners().gather(&tmp);
|
||||
while (res2.hasMore())
|
||||
ref.makeActive(ref.dereference(res2.getNext()));
|
||||
|
||||
ref.triggerActiveListeners();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONFIG_FAST_BREAKPOINTS // see above
|
||||
|
||||
#endif // __FAST_BREAKPOINTS_AH__
|
||||
Reference in New Issue
Block a user