diff --git a/src/core/sal/perf/FastWatchpoints.ah b/src/core/sal/perf/FastWatchpoints.ah new file mode 100644 index 00000000..c6962aa3 --- /dev/null +++ b/src/core/sal/perf/FastWatchpoints.ah @@ -0,0 +1,75 @@ +#ifndef __FAST_WATCHPOINTS_AH__ + #define __FAST_WATCHPOINTS_AH__ + +#include "config/FailConfig.hpp" + +#ifdef CONFIG_FAST_WATCHPOINTS + +#if !defined(CONFIG_EVENT_MEMREAD) && !defined(CONFIG_EVENT_MEMWRITE) +#error Watchpoint events (i.e. memory read or write accesses) are required for fast watchpoints! +#endif + +#include "WatchpointManagerSlice.ah" // slice class "WatchpointManagerSlice" +#include "WatchpointControllerSlice.ah" // slice class "WatchpointControllerSlice" +#include "../ListenerManager.hpp" +#include "../Listener.hpp" +#include "WatchpointBuffer.hpp" +#include "../SALInst.hpp" + +// Warning: Do not import namespace using "using namespace"! +// (It may yields collisions due to woven aspect code.) + +aspect FastWatchpoints { + + // Refer to slice classes: + advice "fail::ListenerManager" : slice WatchpointManagerSlice; + advice "fail::SimulatorController" : slice WatchpointControllerSlice; + + // These around-advices handle the (special) case where an experiment + // adds a listener object casted to the base type but actually has the + // MemRead- or MemWriteListener 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::MemAccessListener* pma = dynamic_cast(*(tjp->arg<0>())); + // (MemRead- and MemWriteListener are derived classes of MemAccessListener!) + if (pma != NULL) + *(tjp->result()) = tjp->that()->addListener(pma); + 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::MemAccessListener* pma = dynamic_cast(*(tjp->arg<0>())); + if (pma != NULL) + *(tjp->result()) = tjp->that()->addListenerAndResume(pma); + else + tjp->proceed(); + } + + // The event handler for employing watchpoint (aka memory access) events. + advice execution("void fail::%Controller::onMemoryAccess(...)") : around () + { + // Note: "BPListener" is an abstract class anyway. + fail::ListenerManager& ref = tjp->target()->m_LstList; + + #define TJPARG(i) *(tjp->arg()) + fail::MemAccessEvent tmp(TJPARG(0), TJPARG(1), TJPARG(3), + TJPARG(2) ? fail::MemAccessEvent::MEM_WRITE : fail::MemAccessEvent::MEM_READ); + #undef TJPARG + + // Check for matching MemAccessListener: + fail::ResultSet& res = ref.getMemoryListeners().gather(&tmp); + while (res.hasMore()) + ref.makeActive(ref.dereference(res.getNext())); + + ref.triggerActiveListeners(); + } +}; + +#endif // CONFIG_FAST_WATCHPOINTS + +#endif // __FAST_WATCHPOINTS_AH__ diff --git a/src/core/sal/perf/WatchpointBuffer.cc b/src/core/sal/perf/WatchpointBuffer.cc new file mode 100644 index 00000000..3bf81894 --- /dev/null +++ b/src/core/sal/perf/WatchpointBuffer.cc @@ -0,0 +1,28 @@ +#include "WatchpointBuffer.hpp" +#include "../Listener.hpp" +#include "../Event.hpp" +#include "../SALInst.hpp" + +namespace fail { + +// FIXME: Can not be inlined this way! +ResultSet& PerfVectorWatchpoints::gather(MemAccessEvent* pData) +{ + static ResultSet res; + res.clear(); // FIXME: This should not free the memory of the underlying std::vector. + // Search for all indices of matching listener objects: + for(std::vector::iterator it = m_BufList.begin(); it != m_BufList.end(); ++it) { + MemAccessListener* pmal = static_cast(simulator.dereference(*it)); + if (pmal->isMatching(pData)) { + // Update trigger data: + pmal->setTriggerInstructionPointer(pData->getTriggerInstructionPointer()); + pmal->setTriggerAddress(pData->getTriggerAddress()); + pmal->setTriggerWidth(pData->getTriggerWidth()); + pmal->setTriggerAccessType(pData->getTriggerAccessType()); + res.add(*it); + } + } + return res; +} + +} // end-of-namespace: fail diff --git a/src/core/sal/perf/WatchpointBuffer.hpp b/src/core/sal/perf/WatchpointBuffer.hpp new file mode 100644 index 00000000..32c40ce6 --- /dev/null +++ b/src/core/sal/perf/WatchpointBuffer.hpp @@ -0,0 +1,20 @@ +#ifndef __WATCHPOINT_BUFFER_HPP__ + #define __WATCHPOINT_BUFFER_HPP__ + +#include "BufferInterface.hpp" + +namespace fail { + +class MemAccessEvent; + +/** + * Concrete implementation of the PerfVector class for \c MemAccessListener. + */ +class PerfVectorWatchpoints : public DefPerfVector { +public: + ResultSet& gather(MemAccessEvent* pData); +}; + +} // end-of-namespace: fail + +#endif // __WATCHPOINT_BUFFER_HPP__ diff --git a/src/core/sal/perf/WatchpointControllerSlice.ah b/src/core/sal/perf/WatchpointControllerSlice.ah new file mode 100644 index 00000000..3a33a1b1 --- /dev/null +++ b/src/core/sal/perf/WatchpointControllerSlice.ah @@ -0,0 +1,40 @@ +#ifndef __WATCHPOINT_CONTROLLER_SLICE_AH__ + #define __WATCHPOINT_CONTROLLER_SLICE_AH__ + +#include "config/FailConfig.hpp" + +#ifdef CONFIG_FAST_WATCHPOINTS + +#include +#include "../Listener.hpp" + +/** + * \class WatchpointControllerSlice + * + * The slice class definition to be used with FastWatchpoints.ah. + * The members of this class will be sliced into the \c SimulatorController class. + */ +slice class WatchpointControllerSlice { +public: + bool addListener(fail::MemAccessListener* mli) + { + assert(mli != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!"); + // Check whether we were called from onTrigger (see SimulatorController.cc@addListener). + fail::ExperimentFlow* pFlow = m_Flows.getCurrent(); + if (pFlow == CoroutineManager::SIM_FLOW) + pFlow = mli->getParent(); + m_LstList.add(mli, pFlow); // preserve type of mli + // Call the common postprocessing function: + if (!mli->onAddition()) { // If the return value signals "false"..., + m_LstList.remove(mli); // ...skip the addition + return false; + } + return true; + } + fail::BaseListener* addListenerAndResume(fail::MemAccessListener* mli) + { addListener(mli); return resume(); } +}; + +#endif // CONFIG_FAST_WATCHPOINTS + +#endif // __WATCHPOINT_CONTROLLER_SLICE_AH__ diff --git a/src/core/sal/perf/WatchpointManagerSlice.ah b/src/core/sal/perf/WatchpointManagerSlice.ah new file mode 100644 index 00000000..f67a5bb2 --- /dev/null +++ b/src/core/sal/perf/WatchpointManagerSlice.ah @@ -0,0 +1,42 @@ +#ifndef __WATCHPOINT_MANAGER_SLICE_AH__ + #define __WATCHPOINT_MANAGER_SLICE_AH__ + +#include "config/FailConfig.hpp" + +#ifdef CONFIG_FAST_WATCHPOINTS + +#include +#include "WatchpointBuffer.hpp" +#include "../Listener.hpp" + +/** + * \class WatchpointManagerSlice + * + * The slice class definition to be used with FastWatchpoints.ah. + * The members of this class will be sliced into the \c ListenerManager class. + */ +slice class WatchpointManagerSlice { +private: + fail::PerfVectorWatchpoints m_MemListeners; +public: + fail::PerfVectorWatchpoints& getMemoryListeners() { return m_MemListeners; } + + void add(fail::MemAccessListener* mli, fail::ExperimentFlow* flow) + { + assert(mli != NULL && "FATAL ERROR: Argument (ptr) cannot be NULL!"); + mli->setParent(flow); + // (1) Add mli to the main buffer-list, ... + m_BufferList.push_back(mli); + // (2) ... update it's location (index) / performance-buffer (ptr) and ... + fail::index_t idx = m_BufferList.size()-1; + assert(m_BufferList[idx] == mli && "FATAL ERROR: Invalid index after push_back() unexpected!"); + mli->setLocation(idx); + mli->setPerformanceBuffer(&m_MemListeners); + // (3) ... add this index to the m_SingleListeners vector. + m_MemListeners.add(idx); + } +}; + +#endif // CONFIG_FAST_WATCHPOINTS + +#endif // __WATCHPOINT_MANAGER_SLICE_AH__