#ifndef Lh5wJREkwqXIDpptCEqbkLO3ed4 #define Lh5wJREkwqXIDpptCEqbkLO3ed4 #include #include #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 struct SimLoop { typedef PropertyComposition 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::value: handleEvent(); break; HT(SpikeArrival); HT(Spike); HT(RandomSpike); HT(GlobalMsg); #undef HT default: assert(false); } maxEvents--; } return maxEvents; } template inline void handleEvent() { typedef typename QuantDestinationQuant::type DstQuant; Time ct(queues.min()); Event &event = queues.get()(ct).minPayload(); Ptr dst(event.dst(topology)); // deliever the event and check if to create new events DelieverContext delieverContext(event.instance(), dst); PLA_Apply 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()(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()) \ generateEvent (ct, dst, apply); MGE(GlobalMsg); MGE(Spike); MGE(RandomSpike); #undef MGE if (apply.template generate()) generateSAEvent(ct, event, apply); if (boost::is_same::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, event)); }else{ queues.removeLocalMin(ct); } } template inline void generateEvent(Time ct, typename ContQuant::instance_ptr_t src, PLA_Apply &apply) { // generate new discrete quant instance Time eventTime = ct + apply.template getDelay(); Ptr ptrNE(indices.get>().add(ct, eventTime, src)); EmitContext emitContext(src, ptrNE); PLA_Generate pla_gen(ct, emitContext, indices, queues); pc.call(pla_gen); // generate new event if (likely((not TopologicalEventDiscard()(topology, src)))) queues.insert (ct, eventTime + TopologicalTimeOffset()(topology, src), Event(eventTime, src, ptrNE)); } template inline void generateSAEvent(Time ct, EventT &rawEvent, PLA_Apply &apply) { // garantuee that we are called by spike event and cast alike assert((boost::is_same>::value)); assert((boost::is_same::value)); Event &event(FORCE_CONV(Event, rawEvent)); Ptr src(event.dst(topology)); // calculate the SA-ptr Ptr ptrNE(event.instance(), event.offset); // generate all SA properties (except voltage difference) EmitContext emitContext(src, ptrNE); PLA_Generate pla_gen(ct, emitContext, indices, queues); pc.call(pla_gen); // generate event and add to queues queues.insert(ct, ct, Event(src, ptrNE)); } inline void reinsertSpike(Time ct, Event &event) { // TODO (optimize): reuse the current event Event::offset_t offset(event.offset + 1); if (unlikely((topology.synapse(event.src, offset)() == Topology::nil()()))) { queues.removeLocalMin(ct); }else{ // create new event (depends on old) Event 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(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>().sync(); queues.get().sync(); } Time currentTime() { return queues.min(); } /// persistant data storage (holds every mmap'ed data structure) // properties pc_t pc; Topology topology; // indices template struct index_from_type { typedef Index type; }; typedef typename boost::mpl::transform< DiscreteQuantorList, index_from_type >::type indices_list_t; typedef typename UnpackTypeList::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