diff options
Diffstat (limited to 'core/sim_loop.hpp')
-rw-r--r-- | core/sim_loop.hpp | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/core/sim_loop.hpp b/core/sim_loop.hpp new file mode 100644 index 0000000..0ef748d --- /dev/null +++ b/core/sim_loop.hpp @@ -0,0 +1,218 @@ +#ifndef Lh5wJREkwqXIDpptCEqbkLO3ed4 +#define Lh5wJREkwqXIDpptCEqbkLO3ed4 + +#include <boost/tuple/tuple.hpp> +#include <boost/mpl/joint_view.hpp> + +#include "context.hpp" +#include "event.hpp" +#include "evolve.hpp" +#include "index.hpp" +#include "index_global.hpp" +#include "index_randomspike.hpp" +#include "index_spike.hpp" +#include "index_spike_arrival.hpp" +#include "multi_queue.hpp" +#include "pla_apply.hpp" +#include "pla_evolve.hpp" +#include "pla_generate.hpp" +#include "pla_sync.hpp" +#include "time.hpp" +#include "topology.hpp" +#include "type_set.hpp" + +namespace SimLoopImpl { + +using namespace boost; +using namespace boost::mpl; + +template<typename PropList> +struct SimLoop { + typedef PropertyComposition<PropList> pc_t; + + SimLoop() + : indices(), + queues() + {} + + bool run(const Time until, uint64_t maxEvents) __attribute__((noinline)) { + Time old(queues.min()); + while (queues.min() <= until && maxEvents) { + assert(old <= queues.min()); + old = queues.min(); + switch (queues.minType()) { +#define HT(T) case RuntimeID<T>::value: handleEvent<T>(); break; + HT(SpikeArrival); + HT(Spike); + HT(RandomSpike); + HT(GlobalMsg); +#undef HT + default: assert(false); + } + maxEvents--; + } + return maxEvents; + } + + template<typename Quant> + inline void handleEvent() { + typedef typename QuantDestinationQuant<Quant>::type DstQuant; + Time ct(queues.min()); + Event<Quant> &event = queues.get<Quant>()(ct).minPayload(); + Ptr<DstQuant> dst(event.dst(topology)); + + // deliever the event and check if to create new events + DelieverContext<Quant, DstQuant> delieverContext(event.instance(), dst); + PLA_Apply<Quant, DstQuant, pc_t> apply(ct, delieverContext); + pc.call(apply); + + // if we create any events + if (apply.generateAny()) { + // evolve all entities which depend on our pre-event values + Evolve<DstQuant>()(pc, ct, dst); + + // compute delay values (they require access to the pre- and + // post-event values and can thus only be computed here) + apply.computeDelay(pc); + } + + // commit data calculated during apply + // this is necessary because childs are only eventually evolved, + // but require the pre-event values of the instance we are + // committing to now + apply.commit(pc); + + // generate events and compute discrete properties +#define MGE(DQ) \ + if (apply.template generate<DQ>()) \ + generateEvent<DstQuant, DQ, Quant> (ct, dst, apply); + + MGE(GlobalMsg); + MGE(Spike); + MGE(RandomSpike); +#undef MGE + if (apply.template generate<SpikeArrival>()) + generateSAEvent(ct, event, apply); + + if (boost::is_same<Quant, Spike>::value) { + // reinsert spike to get to the next neuron; also handles + // removing current min element from the queue (because of a + // race condition) + reinsertSpike(ct, FORCE_CONV(Event<Spike>, event)); + }else{ + queues.removeLocalMin<Quant>(ct); + } + } + + template<typename ContQuant, typename EventQuant, typename SrcEvQuant> + inline void generateEvent(Time ct, + typename ContQuant::instance_ptr_t src, + PLA_Apply<SrcEvQuant, ContQuant, pc_t> &apply) { + // generate new discrete quant instance + Time eventTime = ct + apply.template getDelay<EventQuant>(); + Ptr<EventQuant> ptrNE(indices.get<Index<EventQuant>>().add(ct, eventTime, src)); + EmitContext<ContQuant, EventQuant> emitContext(src, ptrNE); + PLA_Generate<ContQuant, EventQuant, indices_t, queues_t> + pla_gen(ct, emitContext, indices, queues); + pc.call(pla_gen); + + // generate new event + if (likely((not TopologicalEventDiscard<ContQuant, EventQuant>()(topology, src)))) + queues.insert + (ct, + eventTime + TopologicalTimeOffset<ContQuant, EventQuant>()(topology, src), + Event<EventQuant>(eventTime, src, ptrNE)); + } + + template<typename EventT, typename ContQuant, typename SrcEvQuant> + inline void generateSAEvent(Time ct, + EventT &rawEvent, + PLA_Apply<SrcEvQuant, ContQuant, pc_t> &apply) { + // garantuee that we are called by spike event and cast alike + assert((boost::is_same<EventT, Event<Spike>>::value)); + assert((boost::is_same<ContQuant, Synapse>::value)); + Event<Spike> &event(FORCE_CONV(Event<Spike>, rawEvent)); + Ptr<Synapse> src(event.dst(topology)); + + // calculate the SA-ptr + Ptr<SpikeArrival> ptrNE(event.instance(), event.offset); + + // generate all SA properties (except voltage difference) + EmitContext<Synapse, SpikeArrival> emitContext(src, ptrNE); + PLA_Generate<Synapse, SpikeArrival, indices_t, queues_t> + pla_gen(ct, emitContext, indices, queues); + pc.call(pla_gen); + + // generate event and add to queues + queues.insert(ct, ct, Event<SpikeArrival>(src, ptrNE)); + } + + inline void reinsertSpike(Time ct, Event<Spike> &event) { + // TODO (optimize): reuse the current event + Event<Spike>::offset_t offset(event.offset + 1); + + if (unlikely((topology.synapse(event.src, offset)() == Topology::nil()()))) { + queues.removeLocalMin<Spike>(ct); + }else{ + // create new event (depends on old) + Event<Spike> newEvent + (event.baseTime, + event.src, + event.spike, + offset); + + // delete old event; this must happen before insertion of the + // new event to avoid race in case of equal times + queues.removeLocalMin<Spike>(ct); + + // insert new event + queues.insert + (ct, + newEvent.baseTime + topology.time(newEvent.src, offset), + newEvent); + } + } + + void sync() { + // TODO: sync all or remove method + pc.cast(PLA_Sync{}); + indices.get<Index<GlobalMsg>>().sync(); + queues.get<GlobalMsg>().sync(); + } + + Time currentTime() { + return queues.min(); + } + + /// persistant data storage (holds every mmap'ed data structure) + + // properties + pc_t pc; + Topology topology; + + // indices + template<typename T> struct index_from_type { + typedef Index<T> type; + }; + typedef typename boost::mpl::transform< + DiscreteQuantorList, + index_from_type<boost::mpl::_> + >::type indices_list_t; + typedef typename UnpackTypeList<TypeSet, indices_list_t>::type indices_t; + indices_t indices; + + // event queues + typedef MultiQueue< + Time, Event, DiscreteQuantorList + > queues_t; + queues_t queues; + + // TODO (beauty): add checks for proper r/w status in pc_t (all + // writable) +}; + +} // Namespace SimLoopImpl + +using SimLoopImpl::SimLoop; + +#endif // Lh5wJREkwqXIDpptCEqbkLO3ed4 |