From 420d2ef464d4a741028e132e662d5626806a41f5 Mon Sep 17 00:00:00 2001 From: Jan Huwald Date: Mon, 7 May 2012 22:01:51 +0200 Subject: Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1f2a4c0 --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +.SECONDARY: + +### compiler flags + +CC=g++-4.6.1 -std=c++0x -static-libstdc++ + +#ERR= +ERR=-Wall -Wfatal-errors -Wno-strict-aliasing + +ifeq ($(DBG), 1) + CCOPTS=-ggdb -O1 +else + CCOPTS =-O3 + CCOPTS +=-fwhole-program -march=native -mtune=native + CCOPTS +=-funsafe-math-optimizations -fno-math-errno -frename-registers + CCOPTS +=-freorder-blocks-and-partition +# CCOPTS += -ftree-parallelize-loops=4 +endif + +ifeq ($(PROF), 1) + CCOPTS +=-pg +endif + +CCOPTS += -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS +CCOPTS += -DBOOST_MPL_LIMIT_LIST_SIZE=30 + +.PHONY: all +all: exec doc reports + -echo "not enough yet" + false + +### TARGET FILES +EXEC=all_spikes bootstrap coarse_replay convert_topology list_synapses replay simulate spike_out spike_in track_causality +TEST=test_rng test_movector test_mmap test_mmap2 test_scalar test_vector test_checkpoint test_propcomp test_pla_getset test_pla_evolve test_prioque test_heap test_multi_queue test_typemap test_pla_apply test_index test_filter test_sim_loop +SPEEDTEST=test_index_speed test_prioque_speed test_propcomp_cpp-speed test_vector_speed +REPORT=report_names report_runtimeid report_spacereq + +ALL_EXEC=$(EXEC) $(TEST) $(SPEEDTEST) $(REPORT) + +### SUB MAKE FILES + +include make/asm.make +include make/doc.make +include make/model.make +include make/pgopt.make +include make/plot.make +include make/reports.make +include make/simulate.make +include make/test.make + +-include make/depend_core.mk +make/depend_core.mk: Makefile + @mkdir -p make/core + @for i in $(ALL_EXEC); do echo "-include make/core/$${i}.mk"; done > $@ +make/core/%.mk: core/%.cpp + @echo "Computing dependencies of $<" + @gcc -M -MG -MM -MT "$@ $(shell echo $@ | sed 's#make/core/\(.*\).mk#bin/\1.dep#')" $< | sed 's/properties.hpp//g' > $@; + +-include make/depend_model.mk +make/depend_model.mk: model/*model Makefile + ./toolbin/gen_model_deps.sh >> $@ +bin/%.dep: # deps come from make/core/* + @touch $@ + +### CORE CODE + +# default cases (used outside of sim for test cases, pgopt, ...) +SIM_MODEL=default +SIM_SEED=0 + +# HINT: deps are created automatically +.SECONDEXPANSION: +bin/%: SIM_MODEL=$(shell echo -e "$@\ndefault-" | egrep -o '[^/]*$$' | cut -s -f1 -d- | head -n1) +bin/%: CUR_EXEC= $(shell echo "$@" | egrep -o '[^/]*$$' | cut -f2- -d-) +bin/%: core/$$(CUR_EXEC).cpp bin/$$(CUR_EXEC).dep properties/$$(SIM_MODEL)/properties.hpp + @echo "Compiling $@" + @mkdir -p bin + @$(CC) $(PGOPTS) $(CCOPTS) $(ERR) $< -I. -Iproperties/$(SIM_MODEL) -o $@ + +properties/%/properties.hpp: model/%.model toolbin/transform_dsl.pl + @echo "Compiling $<" + @mkdir -p $(shell dirname $@) + @cd model && (../toolbin/transform_dsl.pl ../$< > ../$@ || (rm ../$@; false)) + + +### STD EXECUTABLES + +.PHONY: exec +exec: $(addprefix bin/,$(EXEC)) + +.PHONY: clean +clean: doc/clean + -rm {asm,asm/bin,bin,make/core}/* \ + {.,core,model,make,octave,R,tex,toolbin}/*{~,.gch} \ + make/depend_*.mk \ + model/*.auto.model + -rm -r {tmp,properties}/* tmp/.passed.test_* diff --git a/R/hist.R b/R/hist.R new file mode 100755 index 0000000..b04ae8e --- /dev/null +++ b/R/hist.R @@ -0,0 +1,12 @@ +files = commandArgs(trailingOnly=TRUE); +if (length(files) < 2) { + quit(); +} + +png(files[1]); +par(mfcol=(2, ceiling((length(files)-1)/2))); + +for (f in files[2:length(files)) { + x = read.table(f, sep="\t")[[2]]; + hist(x); +} diff --git a/R/plot.R b/R/plot.R new file mode 100644 index 0000000..b608148 --- /dev/null +++ b/R/plot.R @@ -0,0 +1,33 @@ +# parse cmd line args +args = commandArgs(trailingOnly=TRUE); +src = args[1]; +dst = args[2]; +yname = args[3]; +ids = as.vector(strsplit(args[4], ","))[[1]]; +#ids = as.vector(sapply(strsplit(args[3], ","), as.numeric)); + +# read data +data = read.table(src, colClasses="double") + +# setup output +format = substr(dst, nchar(dst)-3, nchar(dst)); +if (format == ".pdf" || format == "pdf~") { + pdf(file = dst) +} + +# plot data +nids = length(ids); +xrange = range(data[1]); +yrange = range(data[2:(1+nids)]); + + +colors = rainbow(nids, start=0, end=0.1); +linetype = c(1:nids); + +plot(xrange, yrange, type="n", xlab="time [s]", ylab=yname); +for (i in 1:nids) { + lines(as.vector(data[[1]]), as.vector(data[[1+i]]), lty=linetype[i], col=colors[i]); +} +if (nids > 1) { + legend(x="topleft", legend=ids, lty=linetype, col=colors); +} diff --git a/R/plot_all.R b/R/plot_all.R new file mode 100644 index 0000000..acad509 --- /dev/null +++ b/R/plot_all.R @@ -0,0 +1,21 @@ +# parse cmd line args +args = commandArgs(trailingOnly=TRUE); +src = args[1]; +dst = args[2]; + +# read data +data = read.table(src, colClasses="double") + +# setup output +format = substr(dst, nchar(dst)-3, nchar(dst)); +if (format == ".pdf" || format == "pdf~") { + pdf(file = dst) +} + +# plot data +require(gplots); +hist2d(data, nbins=200, col=c("white", heat.colors(12))); +#fac=0.05; +#rfac=1/fac; +#par(pty="s", pch=22, cex=fac, cex.axis=rfac, cex.lab=rfac, cex.main=rfac, cex.sub=rfac); +#plot.default(data, xlab="time [s]", ylab="neuron #"); diff --git a/TODO b/TODO new file mode 100644 index 0000000..7ce3f28 --- /dev/null +++ b/TODO @@ -0,0 +1,20 @@ +* todos + 1. Parser + 1. selective rule overwriting + 2. define space requirements (especially 1-bit-bools) + 2. Sicherheitsmassnahmen gegen Datenzerstoerung + * Logs der ausgefuehrten Kommandos + 3. PLAs refractorn zur nutzung von pla_filter_{prop,quant} + 4. child-readbaility bzw. on-modifabilty deduzieren und bei + Verletzungen warnen +* Checks: + 1. PLA_get/set/evolve pruefen bei read only continous values: time_t ist Time (nicht void), wird aber beim Zugrif nicht genutzt + 2. alle sync()'s: werden die tiefer liegenden Barriers korrekt besetzt? + +* Optimierungen: + 1. Konstanten als quantor class (WORM) + 2. MAP_HUGETLB (ab 2.6.32) ... if it can be made swappable (or sim + is small enough) + 3. (gcc 07/2011) builtin align for data storage + 4. GCC 4.6: -Wsuggest-attribute=[const|pure|noreturn] + diff --git a/core/all_spikes.cpp b/core/all_spikes.cpp new file mode 100644 index 0000000..5307e8b --- /dev/null +++ b/core/all_spikes.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#include "everything_else.hpp" +#include "index.hpp" +#include "index_spike.hpp" +#include "index_randomspike.hpp" + +#include "mempool.hpp" + +using namespace std; + +int main(int argc, char **argv) { + // read cmd line params + assert(argc == 3); + + errno = 0; + char *tail; + Time start(strtod( argv[1], &tail)); assert(*tail == 0); + Time stop( strtod( argv[2], &tail)); assert(*tail == 0); + assert(errno == 0); + + assertSimDir(); + + { + // go to first spike with time >= start + // Index idx; + // Ptr::ptr_t cur(idx.first(start)); + Index idx; + Ptr::ptr_t cur(idx.first(start)); + + // no spike found? + if (cur == idx.nil()) + return 0; + + // output + cout << "# time\tneuron" << endl; + while (cur <= idx.last() && idx.time(cur) <= stop) { + if (idx.src(cur) < numActualNeurons) // don't plot pseudo neurons + // cout << idx.eventTime(cur) << "\t" << idx.src(cur) << endl; + cout << idx.time(cur) << "\t" << idx.src(cur) << endl; + ++cur; + } + } + + return 0; +} diff --git a/core/array.hpp b/core/array.hpp new file mode 100644 index 0000000..e882f92 --- /dev/null +++ b/core/array.hpp @@ -0,0 +1,53 @@ +#ifndef IuE4Lmq81ZDeAq0u7S79e56kZZQ +#define IuE4Lmq81ZDeAq0u7S79e56kZZQ + +#include +#include +#include + +#include "bit_access.hpp" +#include "template_helpers.hpp" + +// size - number of elements +// width - size of each elements (in bit!) +template +class Array { +public: + typedef uint32_t ptr_t; + + // reader and writer + inline T get(ptr_t id); + inline void set(ptr_t id, T value); + + // allow accessing raw memory (this also encodes the correct size of the object) + uint8_t mem[ size * ((width + 7) / 8) ]; + + // garantuee that all sizes = 2^n + STATIC_ASSERT_IS_POWER_OF_TWO(width); + STATIC_ASSERT_IS_POWER_OF_TWO(size); + // garantue that we do not need bit-level access of the underlying container + BOOST_STATIC_ASSERT((uint64_t) width * size >= 8); +}; + +template +inline T Array::get(ptr_t id) { + assert(id < size); + if (width < 8) { + uint8_t res = bit_extract(mem, (uint8_t) width, id); + return FORCE_CONV(T, res); + }else{ + return *((T*) (((char*) mem) + (width / 8) * id)); // TO CHECK: improve cast? + } +} + +template +inline void Array::set(ptr_t id, T value) { + assert(id < size); + if (width < 8) { + bit_insert(mem, (uint8_t) width, id, value); + }else{ + *((T*) (((char*) mem) + (width / 8) * id)) = value; + } +} + +#endif // IuE4Lmq81ZDeAq0u7S79e56kZZQ diff --git a/core/bit_access.hpp b/core/bit_access.hpp new file mode 100644 index 0000000..566254e --- /dev/null +++ b/core/bit_access.hpp @@ -0,0 +1,38 @@ +#ifndef vjxaugYoBtZu5XZVahcafy1l5XU +#define vjxaugYoBtZu5XZVahcafy1l5XU + +#include +#include + +#include "template_helpers.hpp" + +inline uint8_t bit_extract(void *base, uint8_t width, uint64_t id) { + assert(width < 8); + + uint8_t off, mask, block, result, *addr; + + addr = ((uint8_t*) base) + (id * width / 8); + off = (id % (8 / width)) * width; + mask = (~((~0) << width)) << off; + block = * addr; + result = (block & mask) >> off; + + return result; +} + +template +inline void bit_insert(void *base, uint8_t width, uint64_t id, T rawValue) { + assert(width < 8); + + uint8_t off, mask, block, result, *addr; + uint8_t value(FORCE_CONV(uint8_t, rawValue)); + + addr = ((uint8_t*) base) + (id * width / 8); + off = (id % (8 / width)) * width; + mask = (~((~0) << width)) << off; + block = * addr; + result = (block & (~mask)) | ((value << off) & mask); // mask also value, in case it is larger than allowed + *addr = result; +} + +#endif // vjxaugYoBtZu5XZVahcafy1l5XU diff --git a/core/bootstrap.cpp b/core/bootstrap.cpp new file mode 100644 index 0000000..092d0f2 --- /dev/null +++ b/core/bootstrap.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +#include "index.hpp" +#include "index_spike.hpp" +#include "pla_get.hpp" +#include "property_composition.hpp" +#include "pla_init_default.hpp" +#include "pla_set.hpp" +#include "sim_loop.hpp" + +#include "model.hpp" + +using namespace boost; + +const Time startTime(0.1); + +struct FakeSim { + FakeSim() + : indices(), + queues() + { + using boost::make_tuple; + } + + Ptr addGlobalMsg(RNG::seed_t seed) { + const Time gmStartTime(ModelConsts::TrainerInitialDelay); + // create an discrete quant instance + Ptr res(indices.get>().add + (Time(0), gmStartTime, Ptr())); + // and a corresponding event occuring at time 0.1, stored in start + // interval (t=0) + queues.insert(Time(0), gmStartTime, Event(res)); + pc.cast(PLA_Set(res, TrainerT(seed))); + return res; + } + + Ptr addSpike(Ptr src) { + Time eventTime = startTime + TopologicalTimeOffset()(topo, src); + Ptr res(indices.get>().add(startTime, eventTime, src)); + queues.insert(Time(0), eventTime, Event(startTime, src, res)); + return res; + } + + Ptr addRandomSpike(Ptr src, RNG::seed_t seed) { + Time eventTime = startTime + RNG::expo(seed, 1 / ModelConsts::RandomFreq); + Ptr res(indices.get>().add + (startTime, eventTime, src)); + queues.insert(Time(0), eventTime, + Event(eventTime, src, res)); + return res; + } + + // data structs + typedef SimLoop sim_t; + sim_t::indices_t indices; + sim_t::queues_t queues; + sim_t::pc_t pc; + Topology topo; +}; + +using namespace std; + +int main(int argc, char **argv) { + using boost::mpl::pair; + using boost::mpl::list; + FakeSim data; + + // read cmd line arg + if (argc > 2) { + cout << "Usage: " << argv[0] << " [random-seed=0]"; + } + char *tail; + RNG::seed_t rng(0); + if (argc == 2) { + rng = RNG::seed_t(strtoll(argv[1], &tail, 10)); + assert(*tail == 0); + } + + // init values (except weight) + data.pc.cast(PLA_Init_Default()); + + // init random seed (different one for every neuron) + for (Ptr i : Ptr().childs()) { + data.pc.cast(PLA_Set(Time(0), i, RNG::split(rng))); + rng = RNG::next(rng, 40); + } + + // TODO: add a global event to start trainer + PLA_Get get(Ptr(0)); + data.addGlobalMsg(RNG::split(rng)); + rng = RNG::next(rng, 40); + + // add a random noise source for every neuron + for (Ptr i : Ptr().childs()) + if (i() < ModelConsts::NumExcitatory) { // exclude special neurons + data.addRandomSpike(i, RNG::split(rng)); + rng = RNG::next(rng, 40); + } + + // TODO: add discrete properties to the created events + + return 0; +} diff --git a/core/checkpoint.hpp b/core/checkpoint.hpp new file mode 100644 index 0000000..44457b9 --- /dev/null +++ b/core/checkpoint.hpp @@ -0,0 +1,165 @@ +#ifndef a4jYavu7NKcD1XX5TXFDvm6LUn8 +#define a4jYavu7NKcD1XX5TXFDvm6LUn8 + +#include + +#include "array.hpp" +#include "everything_else.hpp" +#include "simlimits.hpp" +#include "string_helpers.hpp" +#include "template_helpers.hpp" +#include "time.hpp" +#include "vector.hpp" + +template +class Checkpoint { +public: + typedef uint32_t ptr_t; + + Checkpoint() = delete; + Checkpoint(const string name, const T initialValue); + + // read access + inline Time getTime (const Time t, const ptr_t i) __attribute__ ((pure)); // DANGER + inline T getValue(const Time t, const ptr_t i); + inline Time getTime (const Time t); // only with size == 1 + inline T getValue(const Time t); // only with size == 1 + + // write access + inline void set(const Time t, const ptr_t i, const T val); + inline void set(const Time t, const T val); // only with size == 1 + + void sync() const; + + // page turn-over: stores all checkpoints and open a new checkpoint + // table for the next interval + void addCheckpoints(const Time newTime); + + // time managment + static const ptr_t binTime(const Time t) { return t.ceilDiv(interval()); } + static constexpr Time interval() { return checkpointInterval; } + + Time timeLimit, // current interval's time limits (infimum, maximum) + timeInf; + ptr_t currentInterval; + + // file backings; they store for each interval, for each element the ... + Vector< Array< T, size > > content; // ... last known content + Vector< Array< Time, size > > times; // ... associated time +}; + +template +inline void Checkpoint::set(const Time t, const ptr_t i, const T val) { + if (unlikely(t > timeLimit)) addCheckpoints(t); + times (currentInterval).set(i, t); + content(currentInterval).set(i, val); +} + +template +inline void Checkpoint::set(const Time t, const T val) { + BOOST_STATIC_ASSERT(size == 1); + set(t, 0, val); +} + +template +void Checkpoint::sync() const { + content.sync(); + times.sync(); +} + +template +inline Time Checkpoint::getTime(const Time t, const ptr_t i) { + if (unlikely(t > timeLimit)) addCheckpoints(t); + ptr_t ival = likely(t > timeInf) ? currentInterval : binTime(t); + return times(ival).get(i); +} + +template +inline Time Checkpoint::getTime(const Time t) { + BOOST_STATIC_ASSERT(size == 1); + return getTime(t, 0); +} + +template +inline T Checkpoint::getValue(const Time t, const ptr_t i) { + if (unlikely(t > timeLimit)) addCheckpoints(t); + ptr_t ival = likely(t > timeInf) ? currentInterval : binTime(t); + return content(ival).get(i); +} + +template +inline T Checkpoint::getValue(const Time t) { + BOOST_STATIC_ASSERT(size == 1); + return getValue(t, 0); +} + +template +Checkpoint::Checkpoint(const string name, const T initialValue) : + timeLimit(0), + timeInf(Time(0) - interval()), + currentInterval(0), + content("checkpoint_content_" + name, maxCheckpoints), + times( "checkpoint_times_" + name, maxCheckpoints) +{ + assert(content.barrierWrite() == times.barrierWrite()); + + // check if we are the first to use this checkpoint and have to initialize it + if (content.barrierWrite() == 0) { + content.barrierWrite() = 1; + times. barrierWrite() = 1; + content.barrierRead() = 0; + times .barrierRead() = 0; + + for (ptr_t i=0; i +void Checkpoint::addCheckpoints(const Time t) { + assert(content.barrierWrite() == times.barrierWrite()); // is a pre- and postcondition + // check if the write barrier has been updated externally + assert(currentInterval == content.barrierWrite() - 1); + + // now create new checkpoint(s) + // + // usually the loop below is executed exactly once; only in the + // rare case of having no event in an interval it may be + // executed several times; if this happens more often one should + // increase the interval length significantly to avoid wasting + // space + while (t > timeLimit) { + // copy content and associated times to the new checkpoint + // TODO: store chekcpoint number in object, use as cache + currentInterval = content.barrierWrite(); // next checkpoint's number + for (uint32_t i=0; i +#include +#include +#include + +#include + +#include "everything_else.hpp" +#include "id_list.hpp" +#include "time.hpp" +#include "template_helpers.hpp" +#include "pla_getbyname.hpp" +#include "property_composition.hpp" + +#include "model.hpp" + +#include "mempool.hpp" + +using namespace std; + +template +struct CoarseReplay; + +// define base case with virtual op() to runtime dispatch call by property name +template<> +struct CoarseReplay { + virtual void operator() (Time start, Time stop, IdList rawIds) { + assert(false); + } +}; + +template +struct CoarseReplay : CoarseReplay { + virtual void operator() (Time start, Time stop, + IdList rawIds) { + IdList::ptr_t> ids(rawIds); + PropertyInstance pi; + assert(stop <= pi.data.timeLimit); + assert(start >= 0); + + // print header + cout << "#"; + for (auto i : ids) cout << "\tval(" << (uint64_t) i << ")"; + for (auto i : ids) cout << "\ttime(" << (uint64_t) i << ")"; + cout << endl; + + // print data + for (Time t = start; t <= stop; t = t + pi.data.interval()) { + cout << t(); + for (auto i : ids) cout << "\t" << pi.data.getValue(t, i); + for (auto i : ids) cout << "\t" << pi.data.getTime (t, i); + cout << endl; + } + } +}; + +template +struct CoarseReplay : CoarseReplay { + virtual void operator() (Time start, Time stop, uint64_t raw_addr) { + cerr << Prop::name << " is a discrete property" << endl; + exit(-1); + } +}; + + +int main(int argc, char **argv) { + // read cmd line params + assert(argc == 5); + assertSimDir(); + + { + PropertyComposition pc; + PLA_GetByName pla(argv[1]); + CoarseReplay *replay(pc.call(pla)); + assert(replay != NULL); + + errno = 0; + char *tail; + IdList ids(argv[2]); + Time start( strtod( argv[3], &tail)); assert(*tail == 0); + Time stop( strtod( argv[4], &tail)); assert(*tail == 0); + assert(errno == 0); + + // output + (*replay)(start, stop, ids); + } + + return 0; +} diff --git a/core/context.hpp b/core/context.hpp new file mode 100644 index 0000000..dd4ed7e --- /dev/null +++ b/core/context.hpp @@ -0,0 +1,123 @@ +#ifndef sOuC39DJVwHiStoyuZdritpuC5M +#define sOuC39DJVwHiStoyuZdritpuC5M + +#include + +#include +#include +#include +#include +#include + +#include "pointers.hpp" +#include "time.hpp" +#include "type_set.hpp" + +/* methods common to all context's + + getptr() -> return an instance id + + */ + +namespace ContextImpl { + + using namespace boost; + using namespace boost::mpl; + + // common context (internal) + template + struct CCtx : public TypeSet...> { + CCtx(Ptr... ids) : TypeSet...>(std::move(ids)...) {} + + template + typename Quant::instance_ptr_t getptr() { + return this->template get>(); + } + }; + + /// SingleContext: stores a single quant w/o any relation + template + struct SingleContext : public CCtx { + SingleContext(Ptr id) : CCtx(id) {} + }; + + /// ContinuousContext: resembles the global <- neuron <- synapse hierarchy + template + struct ContinuousContext; + + template<> + struct ContinuousContext : CCtx { + ContinuousContext() + : CCtx(Ptr()) {} + explicit ContinuousContext(Ptr p) + : CCtx(p) {} + }; + + template<> + struct ContinuousContext : CCtx { + explicit ContinuousContext(Ptr p) + : CCtx(p, Ptr()) {} + }; + + template<> + struct ContinuousContext + : CCtx { + explicit ContinuousContext(Ptr p) + : CCtx(p, p.extractNeuron(), Ptr()) {} + }; + + // common context with one discrete ptr (internal) + template + struct DCtx { + DCtx(Ptr did, Ptr cid) + : id(did), sub(cid) {} + + template + typename Quant::instance_ptr_t getptr() { + if (boost::is_same::value) { + return FORCE_CONV(typename Quant::instance_ptr_t, id); + }else{ + return sub.getptr(); + } + } + + friend std::ostream& operator<< (std::ostream &os, DCtx val) { + return os << val.id << ":" << val.sub; + } + + Ptr id; + ContinuousContext sub; + }; + + + /// DelieverContext: when a (discrete) event is delievered to a + /// continuous quantity + template + struct DelieverContext : DCtx { + DelieverContext(Ptr did, Ptr cid) + : DCtx(did, cid) {} + }; + + // HACK: allow Neuron to access Synapse on SpikeArrival; this only + // works because SA is send with a zero delay, so synapse is already + // evolved to current time + template<> + struct DelieverContext : DCtx { + DelieverContext(boost::tuple, Ptr> t, Ptr) + : DCtx(t.get<0>(), t.get<1>()) {} + }; + + /// EmitContent: CQ emits event of class DQ + template + struct EmitContext : DCtx { + EmitContext(Ptr cid, Ptr did) + : DCtx(did, cid) {} + }; +} + +using ContextImpl::SingleContext; +using ContextImpl::ContinuousContext; +using ContextImpl::DelieverContext; +using ContextImpl::EmitContext; + +#endif // sOuC39DJVwHiStoyuZdritpuC5M diff --git a/core/continuous_property.hpp b/core/continuous_property.hpp new file mode 100644 index 0000000..bed37cf --- /dev/null +++ b/core/continuous_property.hpp @@ -0,0 +1,93 @@ +#ifndef H3OuNUuw3KK0wmZozXqMmrvzz3M +#define H3OuNUuw3KK0wmZozXqMmrvzz3M + +#include +#include + +#include "context.hpp" +#include "index_global.hpp" +#include "index_spike.hpp" +#include "index_spike_arrival.hpp" +#include "pointers.hpp" +#include "quant_types.hpp" +#include "time.hpp" + +//////////////////////////////////////////////////////////////////////////////// +// event related actions +//////////////////////////////////////////////////////////////////////////////// + +// evolve in time - default case: value remains the same +template +struct ContinuousProperty_Evolve { + static inline typename Prop::type eval + (PropComp &, Context context, Time t, Time dt); +}; + +// apply an incoming event - default case: do not send anything +template +struct ContinuousProperty_Apply { + static inline void eval(PropComp &, Context, Time, IntentMap &, Transaction &) {} +}; + +// apply an incoming event: do we change the prop val at all? +template +struct ContinuousProperty_ApplyChangesProp : boost::mpl::bool_ {}; + +// generate an outgoing event - default case: generate nothing +template +struct ContinuousProperty_Generate { + template + static inline void eval(PropComp &, Context, Time, typename Prop::type &, + MI &, MQ &) {} + static const bool changesValue = false; +}; + +//////////////////////////////////////////////////////////////////////////////// +// definition helpers +//////////////////////////////////////////////////////////////////////////////// + +#define GEN_CP(Quant, nameT, nameS, ValueType, InitialVal) \ +struct nameT { \ + typedef ValueType type; \ + typedef Quant quant; \ + typedef Quant::instance_ptr_t instance_ptr_t; \ + \ + static const ValueType initialValue; \ + static const uint32_t size = sizeof(ValueType); \ + static const char* const name; \ +}; \ + \ +const char* const nameT::name = nameS; \ +const ValueType nameT::initialValue{InitialVal}; + +#define GEN_CPL_EVOLVE(nameT) \ +template \ +struct ContinuousProperty_Evolve { \ + inline static nameT::type eval(PropComp &pc, Context context, Time t, Time td) + +#define GEN_CP_EVOLVE(nameT, ReturnVal) \ +GEN_CPL_EVOLVE(nameT) { \ + return ReturnVal; \ + } \ +}; + +#define GEN_CP_APPLY(Property, EventQuant, ChangeProp) \ +template<> \ +struct ContinuousProperty_ApplyChangesProp \ + : boost::mpl::bool_ {}; \ + \ +template \ +struct ContinuousProperty_Apply { \ + typedef boost::mpl::bool_ changeProp_t; \ + static inline void eval(PropComp &pc, Context context, Time t, IntentMap &intent, Transaction &transaction) + +#define GEN_CP_GENERATE(CQ, DQ, Prop) \ +template<> \ +struct ContinuousProperty_Generate { \ + static const bool changesValue = true; \ + template \ + static inline void eval(PropComp &pc, Context context, Time t, \ + Prop::type &value, MI &indices, MQ &queues) + +#endif // H3OuNUuw3KK0wmZozXqMmrvzz3M diff --git a/core/continuous_property_impl.hpp b/core/continuous_property_impl.hpp new file mode 100644 index 0000000..13695cf --- /dev/null +++ b/core/continuous_property_impl.hpp @@ -0,0 +1,13 @@ +#ifndef LEt1PyaObN7YkjcGFenqweegIyk +#define LEt1PyaObN7YkjcGFenqweegIyk + +#include "property_access.hpp" + +template +inline typename Prop::type +ContinuousProperty_Evolve +::eval(PropComp &pc, Context context, Time t, Time dt) { + return Property_Get::eval(pc, context, t); +} + +#endif // LEt1PyaObN7YkjcGFenqweegIyk diff --git a/core/convert_topology.cpp b/core/convert_topology.cpp new file mode 100644 index 0000000..e348c80 --- /dev/null +++ b/core/convert_topology.cpp @@ -0,0 +1,161 @@ +/* format + "src dst delay weight\n" + multiple src dst combinations are possible (?) + */ +#include +#include +#include + +#include +#include +#include + +#include "pla_set.hpp" +#include "pointers.hpp" +#include "property_composition.hpp" +#include "simlimits.hpp" +#include "time.hpp" +#include "topology.hpp" + +#include "model.hpp" + +#include "mempool.hpp" + +using namespace std; + +typedef Ptr::ptr_t np_t; +typedef Ptr::ptr_t sp_t; +typedef Ptr::offset_t op_t; + +struct Connection { + np_t src, dst; + Weight::type weight; + Time::type delay; +}; + +map*> cons; + +PropertyComposition>, + boost::mpl::pair>, + boost::mpl::pair> +>> pc; + + +void init() { + // check that pc time is 0.0 + assert(pc.properties.data.data.timeLimit == 0.0); + for (np_t i=0; i(); +} + +void read() { + cin >> skipws; + while (!cin.eof()) { + Connection c; + + // read from stream + cin >> c.src >> c.dst >> c.delay >> c.weight; + assert(!cin.fail()); + cin >> ws; + + // first sanity check + assert(c.src < maxNeurons); + assert(c.dst < maxNeurons); + assert(c.delay > 0.0); + assert(c.weight != 0.0); + + // store (to sort) + cons[c.src]->insert(make_pair(c.delay, c)); + } +} + +void addPseudo() { + const Ptr::ptr_t half = maxNeurons/2; + assert(numActualNeurons <= half); + for (Ptr::ptr_t i=0; iinsert(make_pair(c.delay, c)); + } +} + +void setWeight(const sp_t synapse, Weight::type weight) { + PLA_Set pla{Time{0}, Ptr{synapse}, weight}; + pc.call(pla); +} + +void writeTopology() { + // fill topology tables + Array &delay + = *(new Array()); + Array::ptr_t, maxNeurons * maxSynapsesPerNeuron> &target + = *(new Array::ptr_t, maxNeurons * maxSynapsesPerNeuron>()); + + op_t currentSynapse[maxNeurons]; + memset(currentSynapse, 0, sizeof(currentSynapse)); + + for (np_t i=0; i &l = *(cons[i]); + assert(l.size() < maxSynapsesPerNeuron); // last synapse required for nil + + for (multimap::iterator k = l.begin(); k != l.end(); k++) { + sp_t t = i * maxSynapsesPerNeuron + j; + Connection &c = (*k).second; + Time::type dt = c.delay; + sp_t s = c.dst * maxSynapsesPerNeuron + currentSynapse[c.dst]++; + + delay.set (t, dt); + target.set(t, s); + setWeight(s, c.weight); + j++; + } + + // fill unused synapses + for (; j::infinity()); + currentSynapse[i]++; + } + } +} + +void writeWeightSums() { + Topology t; + PropertyInstance weights; + for (auto neuron : Ptr().childs()) { + SumWeight::type weightSum = 0; + for (auto synapse : neuron.childs()) { + Weight::type weight = weights.data.getValue(Time{0}, synapse()); + if (weight > 0 and weight < std::numeric_limits::infinity()) + weightSum += weight; + } + PLA_Set s1{Time{0}, neuron, weightSum}; + PLA_Set s2{Time{0}, neuron, weightSum}; + pc.call(s1); pc.call(s2); + } +} + +int main() { + init(); + read(); + addPseudo(); + writeTopology(); + writeWeightSums(); +} diff --git a/core/discrete_property.hpp b/core/discrete_property.hpp new file mode 100644 index 0000000..741049f --- /dev/null +++ b/core/discrete_property.hpp @@ -0,0 +1,39 @@ +#ifndef iNnFGNqFLlBaWFgGGH0sLM3mh40 +#define iNnFGNqFLlBaWFgGGH0sLM3mh40 + +#include "pointers.hpp" +#include "string_helpers.hpp" +#include "template_helpers.hpp" + +/// Macros + +#define GEN_DP(Quant, nameT, nameS, ValueType) \ +struct nameT { \ + typedef ValueType type; \ + typedef Quant quant; \ + typedef Quant::instance_ptr_t instance_ptr_t; \ + static const uint32_t size = sizeof(ValueType); \ + static const char* const name; \ +}; \ + \ +const char* const nameT::name = nameS; + +#define GEN_DP_DELAY(DQuant, CQuant, Rule) \ +template<> \ +struct DiscreteProperty_ComputeDelay { \ + template \ + inline static Time eval(PC &pc, Context context, \ + Transaction transaction, Time t) { \ + return Rule; \ + } \ +}; + +/// default impls + +template +struct DiscreteProperty_ComputeDelay { + template + inline static Time eval(PC &, Context, Transaction, Time) DO_NOT_CALL +}; + +#endif // iNnFGNqFLlBaWFgGGH0sLM3mh40 diff --git a/core/ephermal_checkpoint.hpp b/core/ephermal_checkpoint.hpp new file mode 100644 index 0000000..1ca59e4 --- /dev/null +++ b/core/ephermal_checkpoint.hpp @@ -0,0 +1,83 @@ +// like Checkpoint, but memory-backed instead of file-backed and only +// storing the last time/value-paiir -> NO ACTUAL CHECKPOINTS +#ifndef kR1Z42gIzRShmbO3sKvSk0HIEo +#define kR1Z42gIzRShmbO3sKvSk0HIEo + +#include + +#include "array.hpp" +#include "string_helpers.hpp" +#include "simlimits.hpp" +#include "template_helpers.hpp" +#include "time.hpp" + +template +class EphermalCheckpoint { +public: + typedef uint32_t ptr_t; + + EphermalCheckpoint(string name, const T initialValue); + + // read access + inline Time getTime (const Time t, const ptr_t i); + inline T getValue(const Time t, const ptr_t i); + inline Time getTime (const Time t); // only with size == 1 + inline T getValue(const Time t); // only with size == 1 + + // write access + inline void set(const Time t, const ptr_t i, const T val); + inline void set(const Time t, const T val); // only with size == 1 + + void sync() const {}; + + // memory backed data; they store for each element the ... + Array content; // ... last known content + Array times; // ... associated time + +private: + EphermalCheckpoint(); +}; + +template +inline void EphermalCheckpoint::set(const Time t, const ptr_t i, const T val) { + times.set(i, t); + content.set(i, val); +} + +template +inline void EphermalCheckpoint::set(const Time t, const T val) { + BOOST_STATIC_ASSERT(size == 1); + setValue(t, 0, val); +} + +template +inline Time EphermalCheckpoint::getTime(const Time t, const ptr_t i) { + return times.get(i); +} + +template +inline Time EphermalCheckpoint::getTime(const Time t) { + BOOST_STATIC_ASSERT(size == 1); + return getTime(t, 0); +} + +template +inline T EphermalCheckpoint::getValue(const Time t, const ptr_t i) { + return content.get(i); +} + +template +inline T EphermalCheckpoint::getValue(const Time t) { + BOOST_STATIC_ASSERT(size == 1); + return getValue(t, 0); +} + +template +EphermalCheckpoint::EphermalCheckpoint(string name, const T initialValue) { + for (ptr_t i=0; i + +#include "pointers.hpp" +#include "index_global.hpp" +#include "index_spike.hpp" +#include "template_helpers.hpp" +#include "topology.hpp" + +template +struct Event { + DO_NOT_INSTANCE(UnknownType); +}; + +template<> +struct Event { + typedef GlobalMsg quant_t; + typedef Ptr msg_ptr_t; + typedef Ptr ptr_t; + + // regular ctors + Event(msg_ptr_t inst) : inst(inst) {} + Event(Time ignored1, ptr_t ignored2, msg_ptr_t inst) : inst(inst) {} + + // ctor for illegal event sources + GEN_ANYCAST_CTOR_3(Event) : inst(0) { DO_NOT_CALL } + + inline ptr_t dst(Topology &ignored) { return ptr_t(); } + inline msg_ptr_t instance() { return inst; } + + msg_ptr_t inst; +}; + +template<> +struct Event { + typedef RandomSpike quant_t; + typedef Ptr msg_ptr_t; + typedef Ptr ptr_t; + + Event(Time, ptr_t neuron, msg_ptr_t inst) : neuron(neuron), inst(inst) {} + GEN_ANYCAST_CTOR_3(Event) : neuron(0), inst(0) { DO_NOT_CALL } + + inline ptr_t dst(Topology &) { return neuron; } + inline msg_ptr_t instance() { return inst; } + + ptr_t neuron; + msg_ptr_t inst; +}; + +template<> +struct Event { + typedef Spike quant_t; + typedef Ptr neuron_ptr_t; + typedef Ptr spike_ptr_t; + typedef uint16_t offset_t; + + // legal ctors + Event(Time baseTime, neuron_ptr_t src, spike_ptr_t spike) + : baseTime(baseTime), + src(src), + offset(0), + spike(spike) + {} + Event(Time baseTime, neuron_ptr_t src, spike_ptr_t spike, offset_t offset) + : baseTime(baseTime), + src(src), + offset(offset), + spike(spike) + {} + + // ctor for illegal event sources + GEN_ANYCAST_CTOR_3(Event) : baseTime(0),src(0),offset(0),spike(0) { DO_NOT_CALL } + // Event(Time baseTime, neuron_ptr_t src, uint16_t offset) + // : baseTime(baseTime), src(src), offset(offset) {} + + inline Ptr dst(Topology &topology) { + return topology.synapse(src, offset); + } + inline spike_ptr_t instance() { return spike; } + + Time baseTime; // time of outgoing spike; add topology.time(src, + // offset) to get spike arrival time + neuron_ptr_t src; + offset_t offset; // HINT: offset in topolgy, _not_ a synapse offset! + spike_ptr_t spike; +}; + +template<> +struct Event { + typedef SpikeArrival quant_t; + + Event(Ptr dst, Ptr sa) + : sdst(dst), sa(sa) {} + inline Ptr dst(Topology &ignored) { return dst(); } + inline Ptr dst() { return sdst.extractNeuron(); } + // HACK for DelieverContext ... what a shame + inline boost::tuple, Ptr> instance() { + return boost::make_tuple(sa, sdst); + } + + Ptr sdst; + Ptr sa; +}; + +#endif // lolpAJAYZev7fEXugmdiNlqUhWA diff --git a/core/everything_else.hpp b/core/everything_else.hpp new file mode 100644 index 0000000..8b18cd5 --- /dev/null +++ b/core/everything_else.hpp @@ -0,0 +1,14 @@ +#ifndef oaRGw4aWx0YufhAmmpm1h6BILQU +#define oaRGw4aWx0YufhAmmpm1h6BILQU + +#include +#include + +void assertSimDir() { + assert(access("topology_initialized", F_OK) == 0); +} + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#endif // oaRGw4aWx0YufhAmmpm1h6BILQU diff --git a/core/evolve.hpp b/core/evolve.hpp new file mode 100644 index 0000000..628c170 --- /dev/null +++ b/core/evolve.hpp @@ -0,0 +1,35 @@ +#ifndef X66AJaG3Qy6m9CIBTEKhiCYWag0 +#define X66AJaG3Qy6m9CIBTEKhiCYWag0 + +#include "pla_evolve.hpp" + + + +namespace EvolveImpl { + + template + struct Evolve { + template + void operator() (PC &pc, const Time ct, const Ptr id) { + typedef typename QuantChild::type Child; + // first evolve childs + for (Ptr i : id.childs()) + Evolve()(pc, ct, i); + // then self + pc.cast(PLA_Evolve{ContinuousContext{id}, ct}); + } + }; + + template<> + struct Evolve { + template + void operator() (PC &pc, const Time ct, const Ptr id) { + // no childs -> evolve only self + pc.cast(PLA_Evolve{ContinuousContext{id}, ct}); + } + }; +} + +using EvolveImpl::Evolve; + +#endif // X66AJaG3Qy6m9CIBTEKhiCYWag0 diff --git a/core/filter.hpp b/core/filter.hpp new file mode 100644 index 0000000..89ebbf6 --- /dev/null +++ b/core/filter.hpp @@ -0,0 +1,379 @@ +#ifndef YFUuCq9eKDuTmNenHAFfkJG3V +#define YFUuCq9eKDuTmNenHAFfkJG3V + +/* a Filter is used soley within MultiQueue. It has to have the same + interface as a Heap. MultiQueue uses Heap, as well + as PriorityQueue features. To simulate this, a filter overloads + operator(Time) to return itself and implements all required methods + of Heap and PriorityQueue in one class */ + +#include +#include +#include +#include +#include +#include +//#include + +#include "index_global.hpp" +#include "index_spike.hpp" +#include "index_randomspike.hpp" +#include "index_spike_arrival.hpp" +#include "time.hpp" +#include "topology.hpp" +#include "id_list.hpp" + +#include "model.hpp" // for QuantDestinationQuant + +namespace FilterImpl { + +using namespace boost; + +// "forward decl" to make iter comparable +typedef Ptr::offset_t FSA_offset_t; +typedef std::list, // 1. dst + FSA_offset_t // 2. offset in topo table + >> FSA_Recv_List; +typedef std::map, FSA_Recv_List> FSA_recv_t; + +// an operator only to be used for std::priority_queue, which returns +// the largest element, not the smallest +template +struct queue_greater_equal { + bool operator() (const T &a, const T &b) { + return a.get<0>() > b.get<0>() + || (a.get<0>() == b.get<0>() + && queue_greater_equal()(a.get_tail(), + b.get_tail())); + } +}; + +#define MKCMP(T) \ + template<> \ + struct queue_greater_equal { \ + bool operator() (const T&, const T&) { \ + return true; \ + } \ + } +MKCMP(tuples::null_type); +MKCMP(FSA_recv_t::mapped_type::iterator); +typedef boost::tuples::cons, unsigned char> >, boost::tuples::null_type> ttttt; +MKCMP(ttttt); +#undef MKCMP + +template struct Filter; + +template< + typename Quant, + typename QueuePayload, + typename Queue = std::priority_queue, + queue_greater_equal>> +struct CommonFilter { + typedef QueuePayload queue_payload_t; + typedef Queue queue_t; + typedef IdList::ptr_t> id_list_t; + + explicit CommonFilter(id_list_t &ids, const Time time) + : currentTime(time), + ids(ids), + queue(), + index() + {} + + Filter & operator() (Time t) { + // helper function to emulate Heap behaviour + assert(t >= currentTime); + currentTime = t; + return *static_cast*>(this); + } + + Time minVal() const { + assert(!isEmpty()); + return queue.top().get<0>(); // by convention first element of + // QueuePayload is Time + } + + bool isEmpty() const { + return queue.empty(); + } + + Time currentTime; + id_list_t &ids; + Queue queue; + Index index; + + struct Payload { + Payload() : src(0), dst(0) {} // fake init + + Ptr src; + Ptr::type> dst; + } payload; + + const Payload & minPayload() const { + return payload; + } + +}; + +template<> +struct Filter + : CommonFilter::ptr_t>> +{ + Filter(Time time) + : CommonFilter(id_list, time), + cur(0), // later + last(index.last()) + { + // late init of CommonFilter + payload.dst = Ptr(); + + // look for first relevant checkpoint + Time tMin(std::min(currentTime, index.maxEventTime.timeLimit)); + for (; tMin > 0 && index.maxEventTime.getTime(tMin) >= currentTime; + tMin -= index.maxEventTime.interval()); + cur = Ptr(index.first(tMin)); + + // init queue + if (cur() != index.nil()) + refillQueue(); + } + + void removeMin() { + assert(currentTime >= minVal()); // assure currentTime is updated + queue.pop(); + refillQueue(); + if (!isEmpty()) + payload.src = Ptr(queue.top().get<1>()); + } + + void refillQueue() { + // add all events until the next event to be inserted is created + // after the queues min event arrives, but at least until currentTime + Time until = queue.empty() ? currentTime : minVal(); + for (; cur() <= last() && index.time(cur()) <= until; ++cur) { + // discard messages for the past + if (index.eventTime(cur()) >= currentTime) { + queue.push(queue_payload_t(index.eventTime(cur()), cur())); + until = minVal(); + } + } + // add at most one message iff. required to make progress + if (queue.empty() && cur() <= last() && index.time(cur()) > until) { + queue.push(queue_payload_t(index.eventTime(cur()), cur())); + ++cur; + } + } + + Ptr cur, last; + static id_list_t id_list; +}; +Filter::id_list_t Filter::id_list((char*) "0"); + +template<> +struct Filter + : CommonFilter::ptr_t>> { + Filter(id_list_t &ids, const Time time) + : CommonFilter(ids, time) + { + // find first spike for each given neuron, following spikes are + // simple (using index.next) + for (auto neuron : ids) { + // find first event via first relevent checkpoints + Time tMin(std::min(currentTime, index.maxEventTime.timeLimit)); + for (; tMin > 0 && index.maxEventTime.getTime(tMin, neuron) >= currentTime; + tMin -= index.maxEventTime.interval()); + auto next = Ptr(index.first(tMin, Ptr(neuron)))(); + // skip events before ct + while (next != index.nil() && index.time(next) < currentTime) + next = index.next(next); + // add event (if) + if (next != index.nil()) + queue.push(queue_payload_t(index.eventTime(next), next)); + } + updatePayload(); + } + + void removeMin() { + assert(!isEmpty()); + queue.pop(); + auto next = index.next(payload.src()); + if (next != index.nil()) + queue.push(queue_payload_t(index.eventTime(next), next)); + updatePayload(); + } + + void updatePayload() { + if (!isEmpty()) { + payload.src = Ptr(queue.top().get<1>()); + payload.dst = Ptr(index.src(payload.src())); + } + } + +}; + +template<> +struct Filter + : CommonFilter, FSA_recv_t::mapped_type::iterator>> { + typedef FSA_offset_t offset_t; + + Filter(id_list_t &ids, const Time time) + : CommonFilter(ids, time) { + // extract topology info + Topology topo; + std::set> used; + std::map, Time> maxDelay; + for (auto neuron : Ptr::all()) { + for (offset_t off(0); off < maxSynapsesPerNeuron; off++) { + Ptr syn(topo.synapse(neuron, off)); + if (syn == topo.nil()) break; + if (ids.count(syn.extractNeuron()())) { + Time delay = topo.time(neuron, off); + recv[neuron].push_back(make_tuple(delay, syn, off)); + maxDelay[neuron] = std::max(delay, maxDelay[neuron]); + used.insert(neuron); + } + } + } + + // insert pending spikes + for (auto neuron : used) { + Ptr spike(index.first(std::min(currentTime - maxDelay[neuron], + index.prevCache.timeLimit), + neuron)); + if (spike() != index.nil()) { + Time baseTime = index.time(spike()); + queue.push(queue_payload_t(baseTime + recv[neuron].front().get<0>(), + spike, + recv[neuron].begin())); + } + } + updatePayload(); + + // remove all arrivals of spikes prior to time + while (!isEmpty() && minVal() < time) + removeMin(); + } + + void updatePayload() { + if (!isEmpty()) { + const queue_payload_t &top(queue.top()); + const auto &recvElem(*(top.get<2>())); + payload.dst = recvElem.get<1>().extractNeuron(); + payload.src.get<0>() = Ptr(top.get<1>(), recvElem.get<2>()); + payload.src.get<1>() = recvElem.get<1>(); + } + } + + void removeMin() { + assert(!isEmpty()); + // reinsert next spike from current min (if it exists) + const queue_payload_t top = queue.top(); // copy, to allow popping early + Ptr neuron(index.src(top.get<1>()())); + FSA_Recv_List &recvList = recv[neuron]; + auto re_iter = top.get<2>(); + + // remove old element + queue.pop(); + + // was this the first element in the rev list? + if (re_iter == recvList.begin()) { + // insert next spike from same neuron + Ptr next(index.next(top.get<1>()())); + if (next() != index.nil()) { + auto re_iter(recvList.begin()); + queue_payload_t payload(index.time(next()) + re_iter->get<0>(), + next, + re_iter); + queue.push(payload); + } + } + + // is there a next element in the recv list? + if (++re_iter != recvList.end()) { + // add SA of remaining list + Time baseTime = index.time(top.get<1>()()); + queue_payload_t payload(baseTime + re_iter->get<0>(), + top.get<1>(), + re_iter); + queue.push(payload); + } + + // update payload from new min + updatePayload(); + } + + FSA_recv_t recv; + Index index; + + struct Payload { + Payload() : src(Ptr(0), Ptr(0)), dst(0) {} // fake init + + boost::tuple, Ptr > src; + Ptr dst; + } payload; + + Payload & minPayload() { + return payload; + } +}; + +template<> +struct Filter : Filter { + typedef Ptr::offset_t offset_t; + + Filter(id_list_t &res, const Time time) + : Filter(res, time) { + updatePayload(); + } + + void removeMin() { + Filter::removeMin(); + updatePayload(); + } + + void updatePayload() { + // we copy from parent unconditionally, assuming valid values + // remain in payload even when queue is empty + payload.src = Filter::payload.src.get<0>().extractSpike(); + payload.dst = Filter::payload.src.get<1>(); + } + + Filter & operator() (Time t) { + // helper function to emulate Heap behaviour + if (t >= currentTime) + assert(t >= currentTime); + currentTime = t; + return *this; + } + + typedef CommonFilter::Payload Payload; // ignore "int" + Payload payload; + + Payload & minPayload() { + return payload; + } +}; + +} // namespace FilterImpl + +using FilterImpl::Filter; + +/// arguments for MultiQueue + +template +struct FilterPayload : Filter::Payload { + typedef Quant quant_type; +}; + +template +struct FilterContainer { + BOOST_STATIC_ASSERT((boost::is_same::value)); + typedef Filter type; +}; + +#endif // YFUuCq9eKDuTmNenHAFfkJG3V diff --git a/core/heap.hpp b/core/heap.hpp new file mode 100644 index 0000000..40c0a55 --- /dev/null +++ b/core/heap.hpp @@ -0,0 +1,157 @@ +#ifndef lxZLmAQ0qUwCFC9Ehehzy92Ldko +#define lxZLmAQ0qUwCFC9Ehehzy92Ldko + +/* warn: heap is sloppy with the write barrier of it's content + mmap()ed data store; the stated barrier is always equal or less + than the actually used amount of space; it is only correct after + sync() calls (which happen implicitely at interval turnover */ + +#include +#include + +#include "checkpoint.hpp" +#include "everything_else.hpp" +#include "scalar.hpp" +#include "string_helpers.hpp" +#include "time.hpp" +#include "vector.hpp" + +template +struct Heap { + // constructor requires a 3-tuple: + // 1. name (used for file name creation) + // 2. average size of contained object + // 3. default payload value (if a new heap is created) + Heap(const string name, const uint64_t avgLength); + Heap(); + + // read & write access + inline Payload & operator() (Time t) __attribute__ ((pure)); + void sync(); + + // intern methods + void addCheckpoints(Time t); + + // intern data + typedef Vector::ptr_t ptr_t; + ptr_t interval; // current interval (number) + Time timeLimit; // current intervals time limit (inclusive) + Time currentTime; // current intervals time (same as times(interval) + // but allows compiler to perform better + // optimizations) + + + // file backings + Vector