diff --git a/doc/class-diagram.dia b/doc/class-diagram.dia index fa4ef15f..b0016d3e 100644 --- a/doc/class-diagram.dia +++ b/doc/class-diagram.dia @@ -2932,19 +2932,19 @@ - + - + - + - + #EventList# @@ -3149,6 +3149,29 @@ + + + #m_Io_cache# + + + #BufferCache<IOPortEvent*># + + + ## + + + ## + + + + + + + + + + + @@ -3420,54 +3443,6 @@ - - - #makeActive# - - - ## - - - #void# - - - - - - ## - - - - - - - - - - - - - - - - - #ev# - - - #BaseEvent*# - - - ## - - - ## - - - - - - - #makeActive# @@ -3797,6 +3772,192 @@ + + + #getBPBuffer# + + + ## + + + #BufferCache<BPEvent*>&# + + + + + + ## + + + + + + + + + + + + + + + + + + #getIOBuffer# + + + ## + + + #BufferCache<IOPortEvent*>&# + + + + + + ## + + + + + + + + + + + + + + + + + + #addToCaches# + + + ## + + + #void# + + + + + + ## + + + + + + + + + + + + + + + + + #ev# + + + #BaseEvent*# + + + ## + + + ## + + + + + + + + + + #removeFromCaches# + + + ## + + + #void# + + + + + + ## + + + + + + + + + + + + + + + + + #ev# + + + #BaseEvent*# + + + ## + + + ## + + + + + + + + + + #clearCaches# + + + ## + + + #void# + + + + + + ## + + + + + + + + + + + + + + + @@ -4374,17 +4535,17 @@ - + - + - - + + @@ -17451,19 +17612,19 @@ - + - + - + - + - + #BufferCache# @@ -17558,30 +17719,7 @@ #m_Buffer# - #T**# - - - ## - - - ## - - - - - - - - - - - - - - #m_BufferCount# - - - #int# + #std::list<T># ## @@ -17601,102 +17739,6 @@ - - - #setCount# - - - ## - - - #void# - - - - - - ## - - - - - - - - - - - - - - - - - #new_count# - - - #int# - - - ## - - - ## - - - - - - - - - - #reallocate_buffer# - - - ## - - - #int# - - - - - - ## - - - - - - - - - - - - - - - - - #new_size# - - - #int# - - - ## - - - ## - - - - - - - #add# @@ -17731,7 +17773,7 @@ #val# - #T# + #const T&# ## @@ -17779,7 +17821,7 @@ #val# - #T# + #const T&# ## @@ -17801,7 +17843,7 @@ ## - #int# + #iterator# @@ -17827,7 +17869,7 @@ #idx# - #int# + #iterator# ## @@ -17873,61 +17915,13 @@ - #get# + #begin# ## - #T# - - - - - - ## - - - - - - - - - - - - - - - - - #idx# - - - #int# - - - ## - - - ## - - - - - - - - - - #set# - - - ## - - - #void# + #iterator# @@ -17947,52 +17941,17 @@ - - - - #idx# - - - #int# - - - ## - - - ## - - - - - - - - #val# - - - #T# - - - ## - - - ## - - - - - - + - #getCount# + #end# ## - #int# + #iterator# @@ -18007,7 +17966,7 @@ - + @@ -18022,7 +17981,7 @@ ## - #int# + #iterator# @@ -18065,7 +18024,7 @@ #idx# - #int# + #iterator# ## @@ -18132,19 +18091,19 @@ - + - + - + - - + + @@ -18161,8 +18120,8 @@ - - + + diff --git a/doc/class-diagram.png b/doc/class-diagram.png index e45b916f..9c61864b 100644 Binary files a/doc/class-diagram.png and b/doc/class-diagram.png differ diff --git a/src/core/sal/BufferCache.cc b/src/core/sal/BufferCache.cc index 8987ef49..de8a94f4 100644 --- a/src/core/sal/BufferCache.cc +++ b/src/core/sal/BufferCache.cc @@ -7,87 +7,11 @@ namespace fail { template -void BufferCache::add(T val) +typename BufferCache::iterator BufferCache::makeActive(EventList &ev_list, BufferCache::iterator idx) { - int new_size = getCount() + 1; - int new_last_index = getCount(); - - int res = reallocate_buffer(new_size); - assert (res == 0 && "FATAL ERROR: Could not add event to cache"); - - set(new_last_index, val); -} - -template -void BufferCache::remove(T val) -{ - bool do_remove = false; - for (int i = 0; i < getCount(); i++) { - if (get(i) == val) { - do_remove = true; - } - if (do_remove) { - if (i > getCount() - 1) { - set(i, get(i + 1)); - } - } - } - - if (do_remove) { - int new_size = getCount() - 1; - int res = reallocate_buffer(new_size); - assert (res == 0 && "FATAL ERROR: Could not remove event from cache"); - } -} - -template -void BufferCache::clear() -{ - setCount(0); - free(m_Buffer); - m_Buffer = NULL; -} - -template -int BufferCache::erase(int idx) -{ - if(idx < 0 || idx >= getCount()) - return -2; - - for (int i = idx; i < getCount() - 1; i++) { - set(i, get(i + 1)); - } - - int new_size = getCount() - 1; - if (reallocate_buffer(new_size) != 0) - return -1; - return idx; -} - -template -int BufferCache::reallocate_buffer(int new_size) -{ - if (new_size < 0) - return 20; - - if (new_size == 0) { - clear(); - return 0; - } - void *new_buffer = realloc(m_Buffer, new_size * sizeof(T)); - if (new_buffer == NULL) - return 10; - m_Buffer = static_cast(new_buffer); - setCount(new_size); - return 0; -} - -template -int BufferCache::makeActive(EventList &ev_list, int idx) -{ - assert(idx < getCount() && + assert(idx != end() && "FATAL ERROR: Index larger than cache!"); - T ev = get(idx); + T ev = *idx; assert(ev && "FATAL ERROR: Object pointer cannot be NULL!"); ev->decreaseCounter(); if (ev->getCounter() > 0) { @@ -102,7 +26,8 @@ int BufferCache::makeActive(EventList &ev_list, int idx) return erase(idx); } -// Declare whatever instances of the template you are going to use here: +// Declare here whatever instances of the template you are going to use: template class BufferCache; +template class BufferCache; } // end-of-namespace: fail diff --git a/src/core/sal/BufferCache.hpp b/src/core/sal/BufferCache.hpp index 4c26c837..f87ca61c 100644 --- a/src/core/sal/BufferCache.hpp +++ b/src/core/sal/BufferCache.hpp @@ -2,6 +2,7 @@ #define __BUFFER_CACHE_HPP__ #include +#include namespace fail { @@ -12,74 +13,71 @@ class EventList; * * \brief A simple dynamic array * - * This class is intended to serve as a kind of cache for the entirely STL-based, + * This class is intended to serve as a kind of cache for the * untyped and therefore quite slow event handling mechanism of Fail*. - * To keep the code easily readable, some buffer management methods - * perform suboptimally (remove() and erase() have linear complexity). - * - * FIXME: Why not using std::vector? ("A simple dynamic array") */ template class BufferCache { -private: - // TODO: comments ("//!<") needed! - T *m_Buffer; - int m_BufferCount; - /** - * Changes m_BufferCount. Should be inlined. - * @param new_count the new array length - */ - inline void setCount(int new_count) { if(new_count >= 0) m_BufferCount = new_count; } -protected: - /** - * Reallocates the buffer. This implementation is extremely primitive, - * but since the amount of entries is small, - * this will not be significant, hopefully. Should be inlined. - * @param new_size the new number of elements in the array - * @return 0 if successful, an error code otherwise (10 if realloc() fails, 20 for an invalid new size) - */ - inline int reallocate_buffer(int new_size); public: - BufferCache() - : m_Buffer(NULL), m_BufferCount(0) {} + /** + * The list type inherent to this class. Like bufferlist_t in EventList.hpp, + * but dynamically typed. + */ + typedef std::list cachelist_t; + /** + * The iterator of this class used to loop through the list of + * added events. To retrieve an iterator to the first element, call + * begin(). end() returns the iterator, pointing after the last element. + * (This behaviour equals the STL iterator in C++.) + */ + typedef typename cachelist_t::iterator iterator; +private: + cachelist_t m_Buffer; //!< The list holding the cached elements +public: + BufferCache() {} ~BufferCache() {} /** * Add an element to the array. The object pointed to remains untouched. * @param val the element to add */ - void add(T val); + inline void add(const T &val) { m_Buffer.push_back(val); } /** * Remove an element from the array. The object pointed to remains untouched. * @param val the element to remove */ - void remove(T val); + inline void remove(const T &val) { m_Buffer.remove(val); } /** * Remove an element at a specific position. The object pointed to remains untouched. * @param val the element to remove * @return a pointer to the given element's successor if successful, a negative value otherwise */ - int erase(int i); + inline iterator erase(iterator i) { return m_Buffer.erase(i); } /** * Clears the array, removing all elements. The objects pointed to remain untouched. */ - void clear(); + inline void clear() { m_Buffer.clear(); } /** - * Retrieve an element from the array. Should be inlined. - * @param idx the position to retrieve the element from - * @return the element at the given position + * Returns an iterator to the beginning of the internal data structure. + * Don't forget to update the returned iterator when calling one of the + * modifying methods like makeActive() or remove(). Therefore you need + * to call the iterator-based variants of makeActive() and remove(). + * \code + * [X|1|2| ... |n] + * ^ + * \endcode */ - inline T get(int idx) const { return (idx >= 0 && idx < getCount() ? m_Buffer[idx] : NULL); } + inline iterator begin() { return m_Buffer.begin(); } /** - * Set an element at a given position. Should be inlined. - * @param idx the position to change an element at - * @param val the new value of the given element + * Returns an iterator to the end of the interal data structure. + * Don't forget to update the returned iterator when calling one of the + * modifying methods like makeActive() or remove(). Therefore you need + * to call the iterator-based variants of makeActive() and remove(). + * \code + * [1|2| ... |n]X + * ^ + * \endcode */ - inline void set(int idx, T val) { if(idx >= 0 && idx < getCount()) m_Buffer[idx] = val; } - /** - * Retrieves the current length of the array. Should be inlined. - * @return the array length - */ - inline int getCount() const { return m_BufferCount; } + inline iterator end() { return m_Buffer.end(); } /** * Acts as a replacement for EventList::makeActive, manipulating * the buffer cache exclusively. EventList::fireActiveEvents needs @@ -88,7 +86,7 @@ public: * @param idx the index of the event to trigger * @returns an updated index which can be used to update a loop counter */ - int makeActive(EventList &ev_list, int idx); + iterator makeActive(EventList &ev_list, iterator idx); }; } // end-of-namespace: fail diff --git a/src/core/sal/EventList.cc b/src/core/sal/EventList.cc index 571a262c..cf6b73cc 100644 --- a/src/core/sal/EventList.cc +++ b/src/core/sal/EventList.cc @@ -4,7 +4,34 @@ #include "SALInst.hpp" namespace fail { - + +void EventList::addToCaches(BaseEvent *ev) +{ + BPEvent *bps_ev; + if((bps_ev = dynamic_cast(ev)) != NULL) + m_Bp_cache.add(bps_ev); + + IOPortEvent *io_ev; + if((io_ev = dynamic_cast(ev)) != NULL) + m_Io_cache.add(io_ev); +} + +void EventList::removeFromCaches(BaseEvent *ev) +{ + BPEvent *bpr_ev; + if((bpr_ev = dynamic_cast(ev)) != NULL) + m_Bp_cache.remove(bpr_ev); + + IOPortEvent *io_ev; + if((io_ev = dynamic_cast(ev)) != NULL) + m_Io_cache.remove(io_ev); +} + +void EventList::clearCaches() { + m_Bp_cache.clear(); + m_Io_cache.clear(); +} + EventId EventList::add(BaseEvent* ev, ExperimentFlow* pExp) { assert(ev != NULL && "FATAL ERROR: Event (of base type BaseEvent*) cannot be NULL!"); @@ -12,9 +39,7 @@ EventId EventList::add(BaseEvent* ev, ExperimentFlow* pExp) assert(ev->getCounter() != 0); ev->setParent(pExp); // event is linked to experiment flow - BPEvent *bp_ev; - if((bp_ev = dynamic_cast(ev)) != NULL) - m_Bp_cache.add(bp_ev); + addToCaches(ev); m_BufferList.push_back(ev); return (ev->getId()); } @@ -30,7 +55,7 @@ void EventList::remove(BaseEvent* ev) simulator.onEventDeletion(*it); for (firelist_t::iterator it = m_FireList.begin(); it != m_FireList.end(); it++) simulator.onEventDeletion(*it); - m_Bp_cache.clear(); + clearCaches(); m_BufferList.clear(); // all remaining active events must not fire anymore m_DeleteList.insert(m_DeleteList.end(), m_FireList.begin(), m_FireList.end()); @@ -41,9 +66,7 @@ void EventList::remove(BaseEvent* ev) } else { simulator.onEventDeletion(ev); - BPEvent *bp_ev; - if((bp_ev = dynamic_cast(ev)) != NULL) - m_Bp_cache.remove(bp_ev); + removeFromCaches(ev); m_BufferList.remove(ev); firelist_t::const_iterator it = std::find(m_FireList.begin(), m_FireList.end(), ev); @@ -75,9 +98,7 @@ EventList::iterator EventList::m_remove(iterator it, bool skip_deletelist) // BufferCache::remove() from m_remove(). // NOTE: in case the semantics of skip_deletelist change, please adapt the following lines - BPEvent *bp_ev; - if((bp_ev = dynamic_cast(*it)) != NULL) - m_Bp_cache.remove(bp_ev); + removeFromCaches((*it)); } return (m_BufferList.erase(it)); @@ -99,7 +120,7 @@ void EventList::remove(ExperimentFlow* flow) for (bufferlist_t::iterator it = m_BufferList.begin(); it != m_BufferList.end(); it++) simulator.onEventDeletion(*it); // invoke event handler - m_Bp_cache.clear(); + clearCaches(); m_BufferList.clear(); } else { // remove all events corresponding to a specific experiment ("flow"): for (bufferlist_t::iterator it = m_BufferList.begin(); diff --git a/src/core/sal/EventList.hpp b/src/core/sal/EventList.hpp index 8e3c8d0f..61288131 100644 --- a/src/core/sal/EventList.hpp +++ b/src/core/sal/EventList.hpp @@ -30,6 +30,14 @@ typedef std::vector firelist_t; */ typedef std::vector deletelist_t; +/** + * Cache classes for the most commonly used types of events, utilising static typing. + * Apart from that, they work like bufferlist_t. + */ +typedef BufferCache bp_cache_t; +typedef bp_cache_t::iterator bp_iter_t; +typedef BufferCache io_cache_t; +typedef io_cache_t::iterator io_iter_t; /** * \class EventList * @@ -37,7 +45,7 @@ typedef std::vector deletelist_t; * * If a event is triggered, the internal data structure will be updated (id est, * the event will be removed from the so called buffer-list and added to the - * fire-list). Additionaly, if an experiment-flow deletes an "active" event + * fire-list). Additionally, if an experiment-flow deletes an "active" event * which is currently stored in the fire-list, the event (to be removed) will * be added to a -so called- delete-list. This ensures to prevent triggering * "active" events which have already been deleted by a previous experiment @@ -53,8 +61,10 @@ class EventList firelist_t m_FireList; //!< the active events (used temporarily) deletelist_t m_DeleteList; //!< the deleted events (used temporarily) BaseEvent* m_pFired; //!< the recently fired Event-object - BufferCache m_Bp_cache; - friend int BufferCache::makeActive(EventList &ev_list, int idx); + bp_cache_t m_Bp_cache; //!< the storage cache for breakpoint events + io_cache_t m_Io_cache; //!< the storage cache for port i/o events + friend bp_iter_t bp_cache_t::makeActive(EventList &ev_list, bp_iter_t idx); + friend io_iter_t io_cache_t::makeActive(EventList &ev_list, io_iter_t idx); public: /** * The iterator of this class used to loop through the list of @@ -186,7 +196,27 @@ class EventList * Retrieves the BPEvent buffer cache. * @returns the buffer cache */ - inline BufferCache *getBPBuffer() { return &m_Bp_cache; } + inline bp_cache_t &getBPBuffer() { return m_Bp_cache; } + /** + * Retrieves the IOPortEvent buffer cache. + * @returns the buffer cache + */ + inline io_cache_t &getIOBuffer() { return m_Io_cache; } + private: + /** + * Add an event to its appropriate cache. + * @param the event to add + */ + void addToCaches(BaseEvent *ev); + /** + * Remove an event from its cache. + * @param the event to remove + */ + void removeFromCaches(BaseEvent *ev); + /** + * Clear the event caches. + */ + void clearCaches(); }; } // end-of-namespace: fail diff --git a/src/core/sal/bochs/BochsController.cc b/src/core/sal/bochs/BochsController.cc index e012c45a..46b6a14a 100644 --- a/src/core/sal/bochs/BochsController.cc +++ b/src/core/sal/bochs/BochsController.cc @@ -91,33 +91,34 @@ void BochsController::dbgEnableInstrPtrOutput(unsigned regularity, std::ostream* void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_space) { -#if 0 - //the original code - performs magnitudes worse than - //the code below and is responsible for most (~87 per cent) - //of the slowdown of FailBochs #ifdef DEBUG if(m_Regularity != 0 && ++m_Counter % m_Regularity == 0) (*m_pDest) << "0x" << std::hex << instrPtr; #endif + bool do_fire = false; // Check for active breakpoint-events: - EventList::iterator it = m_EvList.begin(); - while(it != m_EvList.end()) + bp_cache_t &buffer_cache = m_EvList.getBPBuffer(); + bp_cache_t::iterator it = buffer_cache.begin(); + while(it != buffer_cache.end()) { - // FIXME: Maybe we need to improve the performance of this check. - BPEvent* pEvBreakpt = dynamic_cast(*it); - if(pEvBreakpt && pEvBreakpt->isMatching(instrPtr, address_space)) + BPEvent* pEvBreakpt = *it; + if(pEvBreakpt->isMatching(instrPtr, address_space)) { pEvBreakpt->setTriggerInstructionPointer(instrPtr); - it = m_EvList.makeActive(it); + it = buffer_cache.makeActive(m_EvList, it); + do_fire = true; // "it" has already been set to the next element (by calling // makeActive()): continue; // -> skip iterator increment } it++; } - m_EvList.fireActiveEvents(); -#endif - //this code is highly optimised for the average case, so it me appear a bit ugly + if(do_fire) + m_EvList.fireActiveEvents(); + // Note: SimulatorController::onBreakpointEvent will not be invoked in this + // implementation. +#if 0 + //deprecated - this code is ugly bool do_fire = false; int i = 0; BufferCache *buffer_cache = m_EvList.getBPBuffer(); @@ -140,21 +141,20 @@ void BochsController::onInstrPtrChanged(address_t instrPtr, address_t address_sp } if(do_fire) m_EvList.fireActiveEvents(); - // Note: SimulatorController::onBreakpointEvent will not be invoked in this - // implementation. +#endif } void BochsController::onIOPortEvent(unsigned char data, unsigned port, bool out) { // Check for active breakpoint-events: - EventList::iterator it = m_EvList.begin(); - while(it != m_EvList.end()) + io_cache_t &buffer_cache = m_EvList.getIOBuffer(); + io_cache_t::iterator it = buffer_cache.begin(); + while(it != buffer_cache.end()) { - // FIXME: Maybe we need to improve the performance of this check. - IOPortEvent* pIOPt = dynamic_cast(*it); - if(pIOPt && pIOPt->isMatching(port, out)) + IOPortEvent* pIOPt = (*it); + if(pIOPt->isMatching(port, out)) { pIOPt->setData(data); - it = m_EvList.makeActive(it); + it = buffer_cache.makeActive(m_EvList, it); // "it" has already been set to the next element (by calling // makeActive()): continue; // -> skip iterator increment diff --git a/src/experiments/l4-sys/experiment.cc b/src/experiments/l4-sys/experiment.cc index 89e31df8..620b30fa 100644 --- a/src/experiments/l4-sys/experiment.cc +++ b/src/experiments/l4-sys/experiment.cc @@ -49,7 +49,7 @@ istream& operator>>(istream& in, trace_instr &val) { return in; } -char const * const state_folder = "l4sys.state"; +char const * const state_folder = "l4sys.state"; char const * const instr_list_fn = "ip.list"; char const * const golden_run_fn = "golden.out"; address_t const aspace = 0x01e00000; @@ -59,8 +59,7 @@ string golden_run; //the program needs to run 5 times without a fault const unsigned times_run = 5; -string L4SysExperiment::sanitised(string in_str) -{ +string L4SysExperiment::sanitised(string in_str) { string result; result.reserve(in_str.size()); for (string::iterator it = in_str.begin(); it != in_str.end(); it++) { @@ -76,8 +75,7 @@ string L4SysExperiment::sanitised(string in_str) return result; } -BaseEvent* L4SysExperiment::waitIOOrOther(bool clear_output) -{ +BaseEvent* L4SysExperiment::waitIOOrOther(bool clear_output) { IOPortEvent ev_ioport(0x3F8, true); BaseEvent* ev = NULL; if (clear_output) @@ -95,8 +93,7 @@ BaseEvent* L4SysExperiment::waitIOOrOther(bool clear_output) return ev; } -bool L4SysExperiment::run() -{ +bool L4SysExperiment::run() { Logger log("L4Sys", false); BPSingleEvent bp(0, aspace); @@ -109,8 +106,7 @@ bool L4SysExperiment::run() simulator.addEventAndWait(&bp); log << "test function entry reached, saving state" << endl; - log << "EIP = " << hex << bp.getTriggerInstructionPointer() - << " or " + log << "EIP = " << hex << bp.getTriggerInstructionPointer() << " or " << simulator.getRegisterManager().getInstructionPointer() << endl; simulator.save(state_folder); @@ -213,7 +209,7 @@ bool L4SysExperiment::run() } // STEP 4: The actual experiment. - for (int i = 0; i < L4SYS_NUMINSTR; i++) { + while (1) { log << "restoring state" << endl; simulator.restore(state_folder); @@ -247,9 +243,8 @@ bool L4SysExperiment::run() simulator.getRegisterManager().getInstructionPointer(); param.msg.set_injection_ip(injection_ip); log << "inject @ ip " << injection_ip << " (offset " << dec - << instr_offset << ")" << " bit " << bit_offset << ": 0x" - << hex << ((int) data) << " -> 0x" << ((int) newdata) - << endl; + << instr_offset << ")" << " bit " << bit_offset << ": 0x" << hex + << ((int) data) << " -> 0x" << ((int) newdata) << endl; // sanity check (only works if we're working with an instruction trace) if (injection_ip != instr_list[instr_offset].trigger_addr) { @@ -263,7 +258,7 @@ bool L4SysExperiment::run() simulator.clearEvents(); m_jc.sendResult(param); - continue; + simulator.terminate(20); } // aftermath @@ -305,8 +300,7 @@ bool L4SysExperiment::run() simulator.getRegisterManager().getInstructionPointer()); param.msg.set_output(sanitised(output.c_str())); } else if (ev == &ev_trap) { - log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() - << endl; + log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl; param.msg.set_resulttype(param.msg.TRAP); param.msg.set_resultdata( simulator.getRegisterManager().getInstructionPointer()); @@ -339,6 +333,7 @@ bool L4SysExperiment::run() #ifdef HEADLESS_EXPERIMENT simulator.terminate(0); #endif -// experiment successfully conducted + + // experiment successfully conducted return true; } diff --git a/src/experiments/l4-sys/experimentInfo.hpp b/src/experiments/l4-sys/experimentInfo.hpp index 266a22b3..56f75737 100644 --- a/src/experiments/l4-sys/experimentInfo.hpp +++ b/src/experiments/l4-sys/experimentInfo.hpp @@ -1,12 +1,15 @@ #ifndef __EXPERIMENT_INFO_HPP__ #define __EXPERIMENT_INFO_HPP__ -// FIXME autogenerate this +//experiment types: +#define GPRFLIP 10 +#define IDCFLIP 20 #define L4SYS_FUNC_ENTRY 0x1007cd0 #define L4SYS_FUNC_EXIT 0x1007d3a #define L4SYS_NUMINSTR 3184 -//#define HEADLESS_EXPERIMENT -#define PREPARE_EXPERIMENT +#define HEADLESS_EXPERIMENT +#define EXPERIMENT_TYPE IDCFLIP +//#define PREPARE_EXPERIMENT #endif // __EXPERIMENT_INFO_HPP__