Skip to content
Snippets Groups Projects
Unverified Commit 69b90b2f authored by thorstenhater's avatar thorstenhater Committed by GitHub
Browse files

MechABI Prelim: Add parameter packs for multicore (#1406)

- Use parameter packs for multicore mechanisms.
- Adjust unit tests and modcc.
- CPU and GPU use the same mechanism_ppack_base.
- CPU code uses a split similar to GPU with `mech_XYZ_foo` and `kernel::mech_XYZ_foo.
- Make mechanism_ppack_base header public.
- Tracing macros for modcc code gen.
parent 45c70caf
No related branches found
No related tags found
No related merge requests found
Showing
with 475 additions and 454 deletions
......@@ -80,7 +80,7 @@ void mechanism::instantiate(unsigned id,
// Assign non-owning views onto shared state:
mechanism_ppack_base* pp = ppack_ptr(); // From derived class instance.
mechanism_ppack* pp = ppack_ptr(); // From derived class instance.
pp->width_ = width_;
pp->n_detectors_ = shared.n_detector;
......@@ -213,7 +213,7 @@ fvm_value_type* mechanism::field_data(const std::string& field_var) {
void multiply_in_place(fvm_value_type* s, const fvm_index_type* p, int n);
void mechanism::initialize() {
mechanism_ppack_base* pp = ppack_ptr();
mechanism_ppack* pp = ppack_ptr();
pp->vec_t_ = vec_t_ptr_->data();
init();
......
#include <iostream>
#include <backends/event.hpp>
#include <backends/multi_event_stream_state.hpp>
#include <arbor/fvm_types.hpp>
#include <backends/gpu/gpu_common.hpp>
#include <backends/gpu/math_cu.hpp>
#include <backends/gpu/mechanism_ppack_base.hpp>
#include <backends/gpu/reduce_by_key.hpp>
namespace arb {
namespace gpu {
......
......@@ -13,7 +13,6 @@
#include "backends/gpu/fvm.hpp"
#include "backends/gpu/gpu_store_types.hpp"
#include "backends/gpu/mechanism_ppack_base.hpp"
namespace arb {
namespace gpu {
......@@ -22,74 +21,10 @@ namespace gpu {
class mechanism: public arb::concrete_mechanism<arb::gpu::backend> {
public:
protected:
using array = arb::gpu::array;
using iarray = arb::gpu::iarray;
public:
std::size_t size() const override {
return width_;
}
std::size_t memory() const override {
std::size_t s = object_sizeof();
s += sizeof(value_type) * data_.size();
s += sizeof(index_type) * indices_.size();
return s;
}
void instantiate(fvm_size_type id, backend::shared_state& shared, const mechanism_overrides&, const mechanism_layout&) override;
void deliver_events() override {
// Delegate to derived class, passing in event queue state.
apply_events(event_stream_ptr_->marked_events());
}
void update_current() override {
mechanism_ppack_base* pp = ppack_ptr();
pp->vec_t_ = vec_t_ptr_->data();
compute_currents();
}
void update_state() override {
mechanism_ppack_base* pp = ppack_ptr();
pp->vec_t_ = vec_t_ptr_->data();
advance_state();
}
void update_ions() override {
mechanism_ppack_base* pp = ppack_ptr();
pp->vec_t_ = vec_t_ptr_->data();
write_ions();
}
void initialize() override;
void set_parameter(const std::string& key, const std::vector<fvm_value_type>& values) override;
// Peek into mechanism state variable; implements arb::gpu::backend::mechanism_field_data.
// Returns pointer to GPU memory corresponding to state variable data.
fvm_value_type* field_data(const std::string& state_var) override;
void initialize() override;
protected:
size_type width_ = 0; // Instance width (number of CVs/sites)
size_type num_ions_ = 0;
// Returns pointer to (derived) parameter-pack object that holds:
// * pointers to shared cell state `vec_ci_` et al.,
// * pointer to mechanism weights `weight_`,
// * pointer to mechanism node indices `node_index_`,
// * mechanism global scalars and pointers to mechanism range parameters.
// * mechanism ion_state_view objects and pointers to mechanism ion indices.
virtual mechanism_ppack_base* ppack_ptr() = 0;
deliverable_event_stream* event_stream_ptr_;
const array* vec_t_ptr_;
// Bulk storage for index vectors and state and parameter variables.
iarray indices_;
array data_;
bool mult_in_place_;
};
} // namespace gpu
......
......@@ -62,23 +62,25 @@ void mechanism::instantiate(unsigned id, backend::shared_state& shared, const me
width_ = pos_data.cv.size();
// Assign non-owning views onto shared state:
auto pp = (arb::multicore::mechanism_ppack*) ppack_ptr();
vec_ci_ = shared.cv_to_cell.data();
vec_di_ = shared.cv_to_intdom.data();
vec_dt_ = shared.dt_cv.data();
pp->width_ = width_;
pp->vec_ci_ = shared.cv_to_cell.data();
pp->vec_di_ = shared.cv_to_intdom.data();
pp->vec_dt_ = shared.dt_cv.data();
vec_v_ = shared.voltage.data();
vec_i_ = shared.current_density.data();
vec_g_ = shared.conductivity.data();
pp->vec_v_ = shared.voltage.data();
pp->vec_i_ = shared.current_density.data();
pp->vec_g_ = shared.conductivity.data();
temperature_degC_ = shared.temperature_degC.data();
diam_um_ = shared.diam_um.data();
time_since_spike_ = shared.time_since_spike.data();
pp->temperature_degC_ = shared.temperature_degC.data();
pp->diam_um_ = shared.diam_um.data();
pp->time_since_spike_ = shared.time_since_spike.data();
n_detectors_ = shared.n_detector;
pp->n_detectors_ = shared.n_detector;
auto ion_state_tbl = ion_state_table();
n_ion_ = ion_state_tbl.size();
num_ions_ = ion_state_tbl.size();
for (auto i: ion_state_tbl) {
auto ion_binding = value_by_key(overrides.ion_rebind, i.first).value_or(i.first);
......@@ -117,12 +119,11 @@ void mechanism::instantiate(unsigned id, backend::shared_state& shared, const me
// Take reference to corresponding derived (generated) mechanism value pointer member.
fvm_value_type*& field_ptr = *(fields[i].second);
field_ptr = data_.data()+(i+1)*width_padded_;
if (auto opt_value = value_by_key(field_default_table(), fields[i].first)) {
std::fill(field_ptr, field_ptr+width_padded_, *opt_value);
}
}
weight_ = data_.data();
pp->weight_ = data_.data();
// Allocate and copy local state: weight, node indices, ion indices.
// The tail comprises those elements between width_ and width_padded_:
......@@ -131,26 +132,27 @@ void mechanism::instantiate(unsigned id, backend::shared_state& shared, const me
// * For indices in the padded tail of node_index_, set index to last valid CV index.
// * For indices in the padded tail of ion index maps, set index to last valid ion index.
copy_extend(pos_data.weight, make_range(data_.data(), data_.data()+width_padded_), 0);
if (mult_in_place_) {
multiplicity_ = iarray(width_padded_, pad);
copy_extend(pos_data.multiplicity, multiplicity_, 1);
}
util::copy_extend(pos_data.weight, make_range(data_.data(), data_.data()+width_padded_), 0);
// Make index bulk storage
{
auto table = ion_index_table();
// Allocate bulk storage
auto count = (table.size() + 1)*width_padded_;
indices_ = iarray(count, 0, pad);
auto count = table.size() + 1 + (mult_in_place_ ? 1 : 0);
indices_ = iarray(count*width_padded_, 0, pad);
auto base_ptr = indices_.data();
auto append_chunk = [&](const auto& input, auto& output, const auto& pad) {
copy_extend(input, make_range(base_ptr, base_ptr + width_padded_), pad);
output = base_ptr;
base_ptr += width_padded_;
};
// Setup node indices
node_index_ = base_ptr;
base_ptr += width_padded_;
auto node_index = make_range(node_index_, node_index_ + width_padded_);
copy_extend(pos_data.cv, node_index, pos_data.cv.back());
index_constraints_ = make_constraint_partition(node_index, width_, simd_width());
append_chunk(pos_data.cv, pp->node_index_, pos_data.cv.back());
auto node_index = make_range(pp->node_index_, pp->node_index_ + width_padded_);
pp->index_constraints_ = make_constraint_partition(node_index, width_, simd_width());
// Create ion indices
for (const auto& [ion_name, ion_index_ptr]: table) {
......@@ -160,19 +162,18 @@ void mechanism::instantiate(unsigned id, backend::shared_state& shared, const me
if (!oion) {
throw arbor_internal_error("multicore/mechanism: mechanism holds ion with no corresponding shared state");
}
// Set the table entry, step offset to next location
*ion_index_ptr = base_ptr;
base_ptr += width_padded_;
// Obtain index and move data
auto indices = util::index_into(node_index, oion->node_index_);
auto ion_index = make_range(*ion_index_ptr, *ion_index_ptr + width_padded_);
copy_extend(indices, ion_index, util::back(indices));
auto indices = util::index_into(node_index, oion->node_index_);
append_chunk(indices, *ion_index_ptr, util::back(indices));
// Check SIMD constraints
auto ion_index = make_range(*ion_index_ptr, *ion_index_ptr + width_padded_);
arb_assert(compatible_index_constraints(node_index, ion_index, simd_width()));
}
if (mult_in_place_) {
append_chunk(pos_data.multiplicity, pp->multiplicity_, 0);
}
}
}
......@@ -196,7 +197,8 @@ void mechanism::set_parameter(const std::string& key, const std::vector<fvm_valu
}
void mechanism::initialize() {
vec_t_ = vec_t_ptr_->data();
auto pp_ptr = ppack_ptr();
pp_ptr->vec_t_ = vec_t_ptr_->data();
init();
auto states = state_table();
......@@ -204,7 +206,7 @@ void mechanism::initialize() {
if (mult_in_place_) {
for (auto& state: states) {
for (std::size_t j = 0; j < width_; ++j) {
(*state.second)[j] *= multiplicity_[j];
(*state.second)[j] *= pp_ptr->multiplicity_[j];
}
}
}
......
......@@ -10,6 +10,7 @@
#include <arbor/common_types.hpp>
#include <arbor/fvm_types.hpp>
#include <arbor/mechanism.hpp>
#include <arbor/mechanism_ppack.hpp>
#include "backends/multicore/fvm.hpp"
#include "backends/multicore/multicore_common.hpp"
......@@ -18,86 +19,22 @@
namespace arb {
namespace multicore {
// Base class for all generated mechanisms for multicore back-end.
// Parameter pack extended for multicore.
struct mechanism_ppack: arb::mechanism_ppack {
constraint_partition index_constraints_; // Per-mechanism index and weight data, excepting ion indices.
};
// Base class for all generated mechanisms for multicore back-end.
class mechanism: public arb::concrete_mechanism<arb::multicore::backend> {
protected:
using array = arb::multicore::array;
using iarray = arb::multicore::iarray;
public:
std::size_t size() const override {
return width_;
}
std::size_t memory() const override {
std::size_t s = object_sizeof();
s += sizeof(data_[0]) * data_.size();
s += sizeof(indices_[0]) * indices_.size();
return s;
}
void instantiate(fvm_size_type id, backend::shared_state& shared, const mechanism_overrides&, const mechanism_layout&) override;
void initialize() override;
void deliver_events() override {
// Delegate to derived class, passing in event queue state.
apply_events(event_stream_ptr_->marked_events());
}
void update_current() override {
vec_t_ = vec_t_ptr_->data();
compute_currents();
}
void update_state() override {
vec_t_ = vec_t_ptr_->data();
advance_state();
}
void update_ions() override {
vec_t_ = vec_t_ptr_->data();
write_ions();
}
void set_parameter(const std::string& key, const std::vector<fvm_value_type>& values) override;
// Peek into mechanism state variable; implements arb::multicore::backend::mechanism_field_data.
fvm_value_type* field_data(const std::string& state_var) override;
protected:
fvm_size_type width_ = 0; // Instance width (number of CVs/sites)
fvm_size_type width_padded_ = 0; // Width rounded up to multiple of pad/alignment.
fvm_size_type n_ion_ = 0;
fvm_size_type n_detectors_ = 0;
// Non-owning views onto shared cell state, excepting ion state.
const fvm_index_type* vec_ci_; // CV to cell index
const fvm_index_type* vec_di_; // CV to indom index
const fvm_value_type* vec_t_; // Cell index to cell-local time.
const fvm_value_type* vec_dt_; // CV to integration time step.
const fvm_value_type* vec_v_; // CV to cell membrane voltage.
fvm_value_type* vec_i_; // CV to cell membrane current density.
fvm_value_type* vec_g_; // CV to cell membrane conductivity.
const fvm_value_type* temperature_degC_; // CV to temperature.
const fvm_value_type* diam_um_; // CV to diameter.
const fvm_value_type* time_since_spike_; // Vector containing time since last spike, indexed by cell index and n_detectors_
const array* vec_t_ptr_;
deliverable_event_stream* event_stream_ptr_;
// Per-mechanism index and weight data, excepting ion indices.
fvm_index_type* node_index_;
iarray multiplicity_;
bool mult_in_place_;
constraint_partition index_constraints_;
const fvm_value_type* weight_; // Points within data_ after instantiation.
// Bulk storage for state and parameter variables.
array data_;
iarray indices_;
virtual unsigned simd_width() const { return 1; }
fvm_size_type width_padded_ = 0; // Width rounded up to multiple of pad/alignment.
};
} // namespace multicore
......
......@@ -6,6 +6,7 @@
#include <arbor/fvm_types.hpp>
#include <arbor/mechinfo.hpp>
#include <arbor/mechanism_ppack.hpp>
namespace arb {
......@@ -118,9 +119,27 @@ public:
// Instantiation: allocate per-instance state; set views/pointers to shared data.
virtual void instantiate(unsigned id, typename backend::shared_state&, const mechanism_overrides&, const mechanism_layout&) = 0;
std::size_t size() const override { return width_; }
std::size_t memory() const override {
std::size_t s = object_sizeof();
s += sizeof(data_[0]) * data_.size();
s += sizeof(indices_[0]) * indices_.size();
return s;
}
// Delegate to derived class.
virtual void deliver_events() override { apply_events(event_stream_ptr_->marked_events()); }
virtual void update_current() override { set_time_ptr(); compute_currents(); }
virtual void update_state() override { set_time_ptr(); advance_state(); }
virtual void update_ions() override { set_time_ptr(); write_ions(); }
protected:
using deliverable_event_stream = typename backend::deliverable_event_stream;
using iarray = typename backend::iarray;
using array = typename backend::array;
void set_time_ptr() { ppack_ptr()->vec_t_ = vec_t_ptr_->data(); }
// Generated mechanism field, global and ion table lookup types.
// First component is name, second is pointer to corresponing member in
......@@ -148,13 +167,22 @@ protected:
// Member tables: introspection into derived mechanism fields, views etc.
// Default implementations correspond to no corresponding fields/globals/ions.
virtual mechanism_field_table field_table() { return {}; }
virtual mechanism_field_table field_table() { return {}; }
virtual mechanism_field_default_table field_default_table() { return {}; }
virtual mechanism_global_table global_table() { return {}; }
virtual mechanism_state_table state_table() { return {}; }
virtual mechanism_ion_state_table ion_state_table() { return {}; }
virtual mechanism_ion_index_table ion_index_table() { return {}; }
virtual mechanism_global_table global_table() { return {}; }
virtual mechanism_state_table state_table() { return {}; }
virtual mechanism_ion_state_table ion_state_table() { return {}; }
virtual mechanism_ion_index_table ion_index_table() { return {}; }
// Returns pointer to (derived) parameter-pack object that holds:
// * pointers to shared cell state `vec_ci_` et al.,
// * pointer to mechanism weights `weight_`,
// * pointer to mechanism node indices `node_index_`,
// * mechanism global scalars and pointers to mechanism range parameters.
// * mechanism ion_state_view objects and pointers to mechanism ion indices.
virtual mechanism_ppack* ppack_ptr() = 0;
// to be overridden in mechanism implemetations
virtual void advance_state() {};
virtual void compute_currents() {};
virtual void apply_events(typename deliverable_event_stream::state) {};
......@@ -162,6 +190,20 @@ protected:
virtual void init() {};
// Report raw size in bytes of mechanism object.
virtual std::size_t object_sizeof() const = 0;
// events to be processed
// indirection for accessing time in mechanisms
const array* vec_t_ptr_;
deliverable_event_stream* event_stream_ptr_;
size_type width_ = 0; // Instance width (number of CVs/sites)
size_type num_ions_ = 0; // Ion count
bool mult_in_place_; // perform multipliction in place?
// Bulk storage for index vectors and state and parameter variables.
iarray indices_;
array data_;
};
} // namespace arb
#pragma once
// Base class for parameter packs for GPU generated kernels:
// will be included by .cu generated sources.
#include <arbor/mechanism.hpp>
#include <arbor/fvm_types.hpp>
namespace arb {
namespace gpu {
// Parameter pack base:
struct mechanism_ppack_base {
struct mechanism_ppack {
fvm_index_type width_;
fvm_index_type n_detectors_;
const fvm_index_type* vec_ci_;
const fvm_index_type* vec_di_;
const fvm_value_type* vec_t_;
......@@ -24,12 +16,8 @@ struct mechanism_ppack_base {
const fvm_value_type* temperature_degC_;
const fvm_value_type* diam_um_;
const fvm_value_type* time_since_spike_;
const fvm_index_type* node_index_;
const fvm_index_type* multiplicity_;
const fvm_value_type* weight_;
};
} // namespace gpu
} // namespace arb
......@@ -51,8 +51,10 @@ Special variables
* Arbor exposes some parameters from the simulation to the NMODL mechanisms.
These include ``v``, ``diam``, ``celsius`` and ``t`` in addition to the previously
mentioned ion parameters.
* Special variables should not be ``ASSIGNED`` or ``CONSTANT``,
they are ``PARAMETER``.
* The ``area`` is not currently exposed to NMODL.
* Special variables should not be ``ASSIGNED`` or ``CONSTANT``, they are
``PARAMETER``. This is different from NEURON where a built-in variable is
declared ``ASSIGNED`` to make it accessible.
* ``diam`` and ``celsius`` can be set from the simulation side.
* ``v`` is a reserved variable name and can be written in NMODL.
* If Special variables are used in a ``PROCEDURE`` or ``FUNCTION``, they need
......@@ -77,7 +79,7 @@ Unsupported features
However, ``CONSERVE`` statements are supported.
* ``TABLE`` is not supported, calculations are exact.
* ``derivimplicit`` solving method is not supported, use ``cnexp`` instead.
* `verbatim` blocks are not supported.
* ``VERBATIM`` blocks are not supported.
Arbor-specific features
-----------------------
......
......@@ -21,6 +21,7 @@ set(libmodcc_sources
io/prefixbuf.cpp
printer/cexpr_emit.cpp
printer/cprinter.cpp
printer/marks.cpp
printer/gpuprinter.cpp
printer/infoprinter.cpp
printer/printerutil.cpp
......
......@@ -141,6 +141,7 @@ const char* usage_str =
"-P|--profile [Build with profiled kernels]\n"
"-V|--verbose [Toggle verbose mode]\n"
"-A|--analyse [Toggle analysis mode]\n"
"-T|--trace-codegen [Leave trace marks in generated source]\n"
"<filename> [File to be compiled]\n";
int main(int argc, char **argv) {
......@@ -167,16 +168,17 @@ int main(int argc, char **argv) {
to::option options[] = {
{ opt.modfile, to::mandatory},
{ opt.outprefix, "-o", "--output" },
{ to::set(opt.verbose), to::flag, "-V", "--verbose" },
{ to::set(opt.analysis), to::flag, "-A", "--analyse" },
{ opt.modulename, "-m", "--module" },
{ to::set(popt.profile), to::flag, "-P", "--profile" },
{ popt.cpp_namespace, "-N", "--namespace" },
{ to::action(enable_simd), to::flag, "-s", "--simd" },
{ popt.simd, "-S", "--simd-abi" },
{ opt.outprefix, "-o", "--output" },
{ to::set(opt.verbose), to::flag, "-V", "--verbose" },
{ to::set(opt.analysis), to::flag, "-A", "--analyse" },
{ opt.modulename, "-m", "--module" },
{ to::set(popt.profile), to::flag, "-P", "--profile" },
{ popt.cpp_namespace, "-N", "--namespace" },
{ to::action(enable_simd), to::flag, "-s", "--simd" },
{ popt.simd, "-S", "--simd-abi" },
{ to::set(popt.trace_codegen), to::flag, "-T", "--trace-codegen"},
{ {to::action(add_target, to::keywords(targetKindMap))}, "-t", "--target" },
{ to::action(help), to::flag, to::exit, "-h", "--help" }
{ to::action(help), to::flag, to::exit, "-h", "--help" }
};
if (!to::run(options, argc, argv+1)) return 0;
......
......@@ -221,6 +221,20 @@ void SimdExprEmitter::visit(UnaryExpression* e) {
}
}
std::string id_prefix(IdentifierExpression* id) {
if (id) {
if (auto symbol = id->symbol()->is_symbol()) {
if (auto var = symbol->is_variable()) {
if (!var->is_local_variable()) {
return "pp->"+id->name();
}
}
}
}
return id->name();
}
void SimdExprEmitter::visit(BinaryExpression* e) {
static std::unordered_map<tok, const char *> func_tbl = {
{tok::minus, "S::sub"},
......@@ -262,7 +276,7 @@ void SimdExprEmitter::visit(BinaryExpression* e) {
"CExprEmitter: unsupported binary operator " + token_string(e->op()), e->location());
}
std::string rhs_name, lhs_name;
std::string rhs_name, lhs_name, rhs_pfxd, lhs_pfxd;
auto rhs = e->rhs();
auto lhs = e->lhs();
......@@ -270,11 +284,13 @@ void SimdExprEmitter::visit(BinaryExpression* e) {
const char *op_spelling = binop_tbl.at(e->op());
const char *func_spelling = func_tbl.at(e->op());
if (rhs->is_identifier()) {
rhs_name = rhs->is_identifier()->name();
if (auto id = rhs->is_identifier()) {
rhs_name = id->name();
rhs_pfxd = id_prefix(id);
}
if (lhs->is_identifier()) {
lhs_name = lhs->is_identifier()->name();
if (auto id = lhs->is_identifier()) {
lhs_name = id->name();
lhs_pfxd = id_prefix(id);
}
if (scalars_.count(rhs_name) && scalars_.count(lhs_name)) {
......@@ -313,10 +329,10 @@ void SimdExprEmitter::visit(BinaryExpression* e) {
} else if (scalars_.count(rhs_name) && !scalars_.count(lhs_name)) {
out_ << func_spelling << '(';
lhs->accept(this);
out_ << ", simd_cast<simd_value>(" << rhs_name ;
out_ << ", simd_cast<simd_value>(" << rhs_pfxd;
out_ << "))";
} else if (!scalars_.count(rhs_name) && scalars_.count(lhs_name)) {
out_ << func_spelling << "(simd_cast<simd_value>(" << lhs_name << "), ";
out_ << func_spelling << "(simd_cast<simd_value>(" << lhs_pfxd << "), ";
rhs->accept(this);
out_ << ")";
} else {
......@@ -365,14 +381,17 @@ void SimdExprEmitter::visit(AssignmentExpression* e) {
auto mask = processing_true_ ? current_mask_ : current_mask_bar_;
Symbol* lhs = e->lhs()->is_identifier()->symbol();
auto lhs_pfxd = id_prefix(e->lhs()->is_identifier());
if (lhs->is_variable() && lhs->is_variable()->is_range()) {
if (!input_mask_.empty()) {
mask = "S::logical_and(" + mask + ", " + input_mask_ + ")";
}
if(is_indirect_)
out_ << "indirect(" << lhs->name() << "+index_, simd_width_) = ";
out_ << "indirect(" << lhs_pfxd << "+index_, simd_width_) = ";
else
out_ << "indirect(" << lhs->name() << "+i_, simd_width_) = ";
out_ << "indirect(" << lhs_pfxd << "+i_, simd_width_) = ";
out_ << "S::where(" << mask << ", ";
......
......@@ -5,6 +5,7 @@
#include "expression.hpp"
#include "visitor.hpp"
#include "marks.hpp"
// Common functionality for generating source from binary expressions
// and conditional structures with C syntax.
......
This diff is collapsed.
......@@ -68,9 +68,8 @@ std::string emit_gpu_cpp_source(const Module& module_, const printer_options& op
"#include <" << arb_private_header_prefix() << "backends/event.hpp>\n"
"#include <" << arb_private_header_prefix() << "backends/multi_event_stream_state.hpp>\n";
out <<
"#include <" << arb_private_header_prefix() << "backends/gpu/mechanism.hpp>\n"
"#include <" << arb_private_header_prefix() << "backends/gpu/mechanism_ppack_base.hpp>\n";
out << "#include <" << arb_private_header_prefix() << "backends/gpu/mechanism.hpp>\n"
<< "#include <arbor/mechanism_ppack.hpp>\n";
out << "\n" << namespace_declaration_open(ns_components) << "\n";
......@@ -128,7 +127,7 @@ std::string emit_gpu_cpp_source(const Module& module_, const printer_options& op
out << popindent <<
"protected:\n" << indent <<
"std::size_t object_sizeof() const override { return sizeof(*this); }\n"
"::arb::gpu::mechanism_ppack_base* ppack_ptr() override { return &pp_; }\n\n";
"::arb::mechanism_ppack* ppack_ptr() override { return &pp_; }\n\n";
io::separator sep("\n", ",\n");
if (!vars.scalars.empty()) {
......@@ -243,7 +242,8 @@ std::string emit_gpu_cu_source(const Module& module_, const printer_options& opt
"#include <" << arb_private_header_prefix() << "backends/multi_event_stream_state.hpp>\n"
"#include <" << arb_private_header_prefix() << "backends/gpu/gpu_common.hpp>\n"
"#include <" << arb_private_header_prefix() << "backends/gpu/math_cu.hpp>\n"
"#include <" << arb_private_header_prefix() << "backends/gpu/mechanism_ppack_base.hpp>\n";
"#include <arbor/mechanism.hpp>\n" <<
"#include <arbor/mechanism_ppack.hpp>\n";
is_point_proc && out <<
"#include <" << arb_private_header_prefix() << "backends/gpu/reduce_by_key.hpp>\n";
......@@ -397,7 +397,7 @@ void emit_common_defs(std::ostream& out, const Module& module_) {
"using deliverable_event_stream_state =\n"
" ::arb::multi_event_stream_state<::arb::deliverable_event_data>;\n\n";
out << "struct " << ppack_name << ": ::arb::gpu::mechanism_ppack_base {\n" << indent;
out << "struct " << ppack_name << ": ::arb::mechanism_ppack {\n" << indent;
for (const auto& scalar: vars.scalars) {
out << "::arb::fvm_value_type " << scalar->name() << " = " << as_c_double(scalar->value()) << ";\n";
......
#include "marks.hpp"
bool options_trace_codegen = false;
#pragma once
#include "printeropt.hpp"
extern bool options_trace_codegen;
#define ENTERM(stream, msg) do { \
if (options_trace_codegen) { \
(stream) << " /* " << __FUNCTION__ << ":" << (msg) << ":enter */ "; \
} \
} while(0)
#define EXITM(stream, msg) do { \
if (options_trace_codegen) { \
(stream) << " /* " << __FUNCTION__ << ":" << (msg) << ":exit */ "; \
} \
} while(0)
#define ENTER(stream) ENTERM(stream, "")
#define EXIT(stream) EXITM(stream, "")
......@@ -6,6 +6,7 @@
#include <string>
#include "simd.hpp"
struct printer_options {
// C++ namespace for generated code.
std::string cpp_namespace;
......@@ -17,4 +18,5 @@ struct printer_options {
// Currently only supported for C printer.
bool profile = false;
bool trace_codegen = false;
};
......@@ -125,10 +125,10 @@ TEST(CPrinter, proc_body) {
"}"
,
"::arb::fvm_value_type k;\n"
"minf[i_] = 1.0-1.0/(1.0+exp((v-k)/k));\n"
"hinf[i_] = 1.0/(1.0+exp((v-k)/k));\n"
"mtau[i_] = 0.5;\n"
"htau[i_] = 1500.0;\n"
"pp->minf[i_] = 1.0-1.0/(1.0+exp((v-k)/k));\n"
"pp->hinf[i_] = 1.0/(1.0+exp((v-k)/k));\n"
"pp->mtau[i_] = 0.5;\n"
"pp->htau[i_] = 1500.0;\n"
}
};
......@@ -167,7 +167,7 @@ TEST(CPrinter, proc_body_const) {
" mtau = 0.5 - t0 + t1\n"
"}"
,
"mtau[i_] = 0.5 - -0.5 + 1.2;\n"
"pp->mtau[i_] = 0.5 - -0.5 + 1.2;\n"
}
};
......@@ -204,27 +204,27 @@ TEST(CPrinter, proc_body_inlined) {
"r_6_ = 0.;\n"
"r_7_ = 0.;\n"
"r_8_ = 0.;\n"
"r_9_=s2[i_]*0.33333333333333331;\n"
"r_8_=s1[i_]+2.0;\n"
"if(s1[i_]==3.0){\n"
"r_9_=pp->s2[i_]*0.33333333333333331;\n"
"r_8_=pp->s1[i_]+2.0;\n"
"if(pp->s1[i_]==3.0){\n"
" r_7_=2.0*r_8_;\n"
"}\n"
"else{\n"
" if(s1[i_]==4.0){\n"
" if(pp->s1[i_]==4.0){\n"
" r_11_ = 0.;\n"
" r_12_ = 0.;\n"
" r_12_=6.0+s1[i_];\n"
" r_12_=6.0+pp->s1[i_];\n"
" r_11_=r_12_;\n"
" r_7_=r_8_*r_11_;\n"
" }\n"
" else{\n"
" r_10_=exp(r_8_);\n"
" r_7_=r_10_*s1[i_];\n"
" r_7_=r_10_*pp->s1[i_];\n"
" }\n"
"}\n"
"r_13_=0.;\n"
"r_14_=0.;\n"
"r_14_=r_9_/s2[i_];\n"
"r_14_=r_9_/pp->s2[i_];\n"
"r_15_=log(r_14_);\n"
"r_13_=42.0*r_15_;\n"
"r_6_=r_9_*r_13_;\n"
......@@ -247,7 +247,7 @@ TEST(CPrinter, proc_body_inlined) {
" t2=r_16_*ll0_;\n"
" }\n"
"}\n"
"s2[i_]=t2+4.0;\n";
"pp->s2[i_]=t2+4.0;\n";
Module m(io::read_all(DATADIR "/mod_files/test6.mod"), "test6.mod");
Parser p(m, false);
......@@ -280,22 +280,22 @@ TEST(SimdPrinter, simd_if_else) {
"simd_mask mask_0_ = S::cmp_gt(i, (double)2.0);\n"
"S::where(mask_0_,u) = (double)7.0;\n"
"S::where(S::logical_not(mask_0_),u) = (double)5.0;\n"
"indirect(s+i_, simd_width_) = S::where(S::logical_not(mask_0_),simd_cast<simd_value>((double)42.0));\n"
"indirect(s+i_, simd_width_) = u;"
"indirect(pp->s+i_, simd_width_) = S::where(S::logical_not(mask_0_),simd_cast<simd_value>((double)42.0));\n"
"indirect(pp->s+i_, simd_width_) = u;"
,
"simd_value u;\n"
"simd_mask mask_1_ = S::cmp_gt(i, (double)2.0);\n"
"S::where(mask_1_,u) = (double)7.0;\n"
"S::where(S::logical_not(mask_1_),u) = (double)5.0;\n"
"indirect(s+i_, simd_width_) = S::where(S::logical_and(S::logical_not(mask_1_), mask_input_),simd_cast<simd_value>((double)42.0));\n"
"indirect(s+i_, simd_width_) = S::where(mask_input_, u);"
"indirect(pp->s+i_, simd_width_) = S::where(S::logical_and(S::logical_not(mask_1_), mask_input_),simd_cast<simd_value>((double)42.0));\n"
"indirect(pp->s+i_, simd_width_) = S::where(mask_input_, u);"
,
"simd_mask mask_2_ = S::cmp_gt(simd_cast<simd_value>(indirect(g+i_, simd_width_)), (double)2.0);\n"
"simd_mask mask_3_ = S::cmp_gt(simd_cast<simd_value>(indirect(g+i_, simd_width_)), (double)3.0);\n"
"simd_mask mask_2_ = S::cmp_gt(simd_cast<simd_value>(indirect(pp->g+i_, simd_width_)), (double)2.0);\n"
"simd_mask mask_3_ = S::cmp_gt(simd_cast<simd_value>(indirect(pp->g+i_, simd_width_)), (double)3.0);\n"
"S::where(S::logical_and(mask_2_,mask_3_),i) = (double)0.;\n"
"S::where(S::logical_and(mask_2_,S::logical_not(mask_3_)),i) = (double)1.0;\n"
"simd_mask mask_4_ = S::cmp_lt(simd_cast<simd_value>(indirect(g+i_, simd_width_)), (double)1.0);\n"
"indirect(s+i_, simd_width_) = S::where(S::logical_and(S::logical_not(mask_2_),mask_4_),simd_cast<simd_value>((double)2.0));\n"
"simd_mask mask_4_ = S::cmp_lt(simd_cast<simd_value>(indirect(pp->g+i_, simd_width_)), (double)1.0);\n"
"indirect(pp->s+i_, simd_width_) = S::where(S::logical_and(S::logical_not(mask_2_),mask_4_),simd_cast<simd_value>((double)2.0));\n"
"rates(i_, S::logical_and(S::logical_not(mask_2_),S::logical_not(mask_4_)), i);"
};
......
......@@ -57,7 +57,7 @@ mechanism_info fleeb_info = {
template <typename B>
struct common_impl: concrete_mechanism<B> {
void instantiate(fvm_size_type id, typename B::shared_state& state, const mechanism_overrides& o, const mechanism_layout& l) override {
width_ = l.cv.size();
this->width_ = l.cv.size();
// Write mechanism global values to shared state to test instatiation call and catalogue global
// variable overrides.
for (auto& kv: o.globals) {
......@@ -67,15 +67,13 @@ struct common_impl: concrete_mechanism<B> {
for (auto& ion: mech_ions) {
if (o.ion_rebind.count(ion)) {
ion_bindings_[ion] = state.ions.at(o.ion_rebind.at(ion));
}
else {
} else {
ion_bindings_[ion] = state.ions.at(ion);
}
}
}
std::size_t memory() const override { return 10u; }
std::size_t size() const override { return width_; }
void set_parameter(const std::string& key, const std::vector<fvm_value_type>& vs) override {}
......@@ -88,11 +86,12 @@ struct common_impl: concrete_mechanism<B> {
void deliver_events() override {}
void update_ions() override {}
std::size_t width_ = 0;
std::vector<std::string> mech_ions;
std::unordered_map<std::string, std::string> ion_bindings_;
protected:
mechanism_ppack* ppack_ptr() override { return nullptr; }
};
template <typename B>
......@@ -105,10 +104,13 @@ struct foo_stream_state {};
struct foo_stream {
using state = foo_stream_state;
state& marked_events() { return state_; }
state state_;
};
struct foo_backend {
using iarray = std::vector<fvm_index_type>;
using array = std::vector<fvm_value_type>;
using deliverable_event_stream = foo_stream;
struct shared_state {
......@@ -130,10 +132,13 @@ struct bar_stream_state {};
struct bar_stream {
using state = bar_stream_state;
state& marked_events() { return state_; }
state state_;
};
struct bar_backend {
using iarray = std::vector<fvm_index_type>;
using array = std::vector<fvm_value_type>;
using deliverable_event_stream = bar_stream;
struct shared_state {
std::unordered_map<std::string, fvm_value_type> overrides;
......
......@@ -6,6 +6,8 @@
#include <arbor/constants.hpp>
#include <arbor/mechcat.hpp>
#include <arbor/mechanism.hpp>
#include <arbor/mechanism_ppack.hpp>
#include <arbor/cable_cell.hpp>
#include "backends/multicore/fvm.hpp"
......@@ -25,9 +27,7 @@ using value_type = backend::value_type;
using size_type = backend::size_type;
// Access to more mechanism protected data:
ACCESS_BIND(const value_type* multicore::mechanism::*, vec_v_ptr, &multicore::mechanism::vec_v_)
ACCESS_BIND(value_type* multicore::mechanism::*, vec_i_ptr, &multicore::mechanism::vec_i_)
ACCESS_BIND(::arb::mechanism_ppack* (::arb::concrete_mechanism<backend>::*)(), pp_ptr, &::arb::concrete_mechanism<backend>::ppack_ptr);
TEST(synapses, add_to_cell) {
using namespace arb;
......@@ -130,17 +130,17 @@ TEST(synapses, syn_basic_state) {
// Current and voltage views correctly hooked up?
const value_type* v_ptr;
v_ptr = expsyn.get()->*vec_v_ptr;
v_ptr = (expsyn.get()->*pp_ptr)()->vec_v_;
EXPECT_TRUE(all_equal_to(util::make_range(v_ptr, v_ptr+num_comp), -65.));
v_ptr = exp2syn.get()->*vec_v_ptr;
v_ptr = (exp2syn.get()->*pp_ptr)()->vec_v_;
EXPECT_TRUE(all_equal_to(util::make_range(v_ptr, v_ptr+num_comp), -65.));
const value_type* i_ptr;
i_ptr = expsyn.get()->*vec_i_ptr;
i_ptr = (expsyn.get()->*pp_ptr)()->vec_i_;
EXPECT_TRUE(all_equal_to(util::make_range(i_ptr, i_ptr+num_comp), 1.));
i_ptr = exp2syn.get()->*vec_i_ptr;
i_ptr = (exp2syn.get()->*pp_ptr)()->vec_i_;
EXPECT_TRUE(all_equal_to(util::make_range(i_ptr, i_ptr+num_comp), 1.));
// Initialize state then check g, A, B have been set to zero.
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment