Skip to content
Snippets Groups Projects
Commit f0710c48 authored by Johannes Weis's avatar Johannes Weis
Browse files

Move hagen.multiplication._send_vectors to ccalix

Move to a c++ implementation to save runtime.

Change-Id: I85132ea07f4ce5cc22d112a63e1d890a083e3099
parent f825b433
No related branches found
No related tags found
No related merge requests found
#include "ccalix/genpybind.h" #include "ccalix/genpybind.h"
#include "ccalix/hagen/multiplication.h"
#include "ccalix/helpers.h" #include "ccalix/helpers.h"
GENPYBIND_MANUAL({ GENPYBIND_MANUAL({
......
#pragma once
#include "ccalix/genpybind.h"
#include "halco/hicann-dls/vx/v3/synapse_driver.h"
#include "halco/hicann-dls/vx/v3/synram.h"
#include "haldls/vx/v3/event.h"
#include "haldls/vx/v3/synapse.h"
#include "stadls/vx/v3/playback_program_builder.h"
#include <pybind11/numpy.h>
namespace ccalix GENPYBIND_TAG_CCALIX {
namespace hagen GENPYBIND_MODULE {
namespace multiplication {
/**
* Generate events for the given vector in hagen mode.
*
* @param builder Builder to append writes to
* @param vector Array containing the input vector
* @param num_sends Number of repeats of the whole vector
* @param wait_period Wait time between two successive events
* @param synram_coord Coordinate of synapse array to target with the events
* @param synram_selection_bit Determines which bit in the event label selects the synram
*/
SYMBOL_VISIBLE GENPYBIND(visible) void send_vectors(
stadls::vx::v3::PlaybackProgramBuilder& builder,
const pybind11::array_t<uint_fast16_t>& vector,
const size_t num_sends,
const size_t wait_period,
const halco::hicann_dls::vx::v3::SynramOnDLS synram_coord,
const size_t synram_selection_bit);
namespace detail {
/**
* Return a spike pack to chip, containing an event reaching the desired
* synapse driver on the desired synram.
*
* @param address Address that is sent to the driver. The MSB reaches the synapses, the lower 5 bit
* encode the desired activation.
* @param target_driver Coordinate of target synapse driver.
* @param synram_coord Coordinate of target synapse array.
* @param synram_selection_bit Bit position that selects synapse array.
*
* @return Spike packet to chip.
*/
haldls::vx::v3::SpikePack1ToChip prepare_event(
const haldls::vx::v3::SynapseQuad::Label address,
const halco::hicann_dls::vx::v3::SynapseDriverOnSynapseDriverBlock target_driver,
const halco::hicann_dls::vx::v3::SynramOnDLS synram_coord,
const size_t synram_selection_bit);
} // namespace detail
} // namespace multiplication
} // namespace hagen
} // namespace ccalix
#include "ccalix/hagen/multiplication.h"
#include "halco/hicann-dls/vx/v3/timing.h"
#include "haldls/vx/v3/timer.h"
#include <sstream>
#include <stdexcept>
#include <pybind11/numpy.h>
namespace ccalix::hagen::multiplication {
namespace detail {
haldls::vx::v3::SpikePack1ToChip prepare_event(
const haldls::vx::v3::SynapseQuad::Label address,
const halco::hicann_dls::vx::v3::SynapseDriverOnSynapseDriverBlock target_driver,
const halco::hicann_dls::vx::v3::SynramOnDLS synram_coord,
const size_t synram_selection_bit)
{
halco::hicann_dls::vx::v3::SpikeLabel label;
// select target PADI bus
label.set_spl1_address(
halco::hicann_dls::vx::SPL1Address(target_driver.toPADIBusOnPADIBusBlock()));
// select target synram
label.set_neuron_label(
halco::hicann_dls::vx::NeuronLabel(synram_coord << synram_selection_bit));
// select target driver on the PADI bus
label.set_row_select_address(
halco::hicann_dls::vx::PADIRowSelectAddress(target_driver.toSynapseDriverOnPADIBus()));
// set address sent to the driver (MSB + hagen activation)
label.set_synapse_label(address);
haldls::vx::v3::SpikePack1ToChip::labels_type labels;
labels[0] = label;
return haldls::vx::v3::SpikePack1ToChip(labels);
}
} // namespace detail
void send_vectors(
stadls::vx::v3::PlaybackProgramBuilder& builder,
const pybind11::array_t<uint_fast16_t>& vector,
const size_t num_sends,
const size_t wait_period,
const halco::hicann_dls::vx::v3::SynramOnDLS synram_coord,
const size_t synram_selection_bit)
{
if (vector.size() != halco::hicann_dls::vx::v3::SynapseRowOnSynram::size) {
std::stringstream ss;
ss << "Length of vector (" << vector.size()
<< ") does not match number of synapse rows in hemisphere ("
<< halco::hicann_dls::vx::v3::SynapseRowOnSynram::size << ").";
throw std::runtime_error(ss.str());
}
const size_t num_loops = (num_sends > 1 and wait_period <= 1) ? 1 : num_sends;
const size_t num_copies = (num_sends > 1 and wait_period <= 1) ? num_sends : 1;
size_t entry_counter = 0;
builder.write(halco::hicann_dls::vx::v3::TimerOnDLS(), haldls::vx::v3::Timer());
stadls::vx::v3::PlaybackProgramBuilder vector_builder;
for (size_t i = 0; i < num_loops; ++i) {
for (size_t row = 0; row < halco::hicann_dls::vx::v3::SynapseRowOnSynram::size; ++row) {
uint_fast16_t entry = vector.at(row);
if (entry == 0)
continue;
// send event on a different address in order to
// select one of the two rows connected to a driver
if ((row % halco::hicann_dls::vx::v3::SynapseRowOnSynapseDriver::size) == 0)
entry += 32;
vector_builder.write(
halco::hicann_dls::vx::v3::SpikePack1ToChipOnDLS(),
detail::prepare_event(
halco::hicann_dls::vx::v3::SynapseLabel(entry),
halco::hicann_dls::vx::v3::SynapseDriverOnSynapseDriverBlock(
row / halco::hicann_dls::vx::v3::SynapseRowOnSynapseDriver::size),
synram_coord, synram_selection_bit));
// wait only if needed:
if (wait_period > 1) {
vector_builder.block_until(
halco::hicann_dls::vx::v3::TimerOnDLS(),
haldls::vx::v3::Timer::Value(wait_period * entry_counter));
}
entry_counter += 1;
}
}
for (size_t i = 0; i < num_copies; ++i)
builder.copy_back(vector_builder);
}
} // namespace ccalix::hagen::multiplication
...@@ -10,6 +10,8 @@ import quantities as pq ...@@ -10,6 +10,8 @@ import quantities as pq
from dlens_vx_v3 import lola, halco, hal, sta, logger, hxcomm from dlens_vx_v3 import lola, halco, hal, sta, logger, hxcomm
import pyccalix
from calix.common import base, helpers from calix.common import base, helpers
from calix.hagen import neuron_helpers from calix.hagen import neuron_helpers
from calix import constants from calix import constants
...@@ -291,41 +293,6 @@ class Multiplication: ...@@ -291,41 +293,6 @@ class Multiplication:
return synapses return synapses
def prepare_event(
self, address: hal.SynapseQuad.Label,
target_driver: halco.SynapseDriverOnSynapseDriverBlock
) -> hal.SpikePack1ToChip:
"""
Return a spike pack to chip, containing an event reaching
the desired synapse driver on the synram in use.
:param address: Address that is sent to the driver. The
MSB reaches the synapses, the lower 5 bit encode the desired
activation.
:param target_driver: Coordinate of the targeted driver.
:return: Spike packet to chip.
"""
label = halco.SpikeLabel()
# select target PADI bus
label.spl1_address = int(
target_driver.toPADIBusOnPADIBusBlock().toEnum())
# select target synram
label.neuron_label = (int(
self._synram_coord.toEnum()) << self.synram_selection_bit)
# select target driver on the PADI bus
label.row_select_address = int(
target_driver.toSynapseDriverOnPADIBus().toEnum())
# set address sent to the driver (MSB + hagen activation)
label.synapse_label = address
return hal.SpikePack1ToChip([label])
def reset_synin(self, def reset_synin(self,
builder: sta.PlaybackProgramBuilder): builder: sta.PlaybackProgramBuilder):
""" """
...@@ -402,42 +369,11 @@ class Multiplication: ...@@ -402,42 +369,11 @@ class Multiplication:
builder.copy_back(self.cached_reset_synin) builder.copy_back(self.cached_reset_synin)
helpers.wait(builder, 10 * pq.us) helpers.wait(builder, 10 * pq.us)
# Optimize runtime if wait_period is 1 and multiple sends pyccalix.hagen.send_vectors(
# are requested by copying a vector_builder for each send builder, vector, num_sends=self.num_sends,
if self.num_sends > 1 and self.wait_period <= 1: # pylint: disable=chained-comparison wait_period=self.wait_period,
num_loops = 1 synram_coord=self.synram_coord,
num_copies = self.num_sends synram_selection_bit=self.synram_selection_bit)
else:
num_loops = self.num_sends
num_copies = 1
entry_counter = 0
builder.write(halco.TimerOnDLS(), hal.Timer())
vector_builder = sta.PlaybackProgramBuilder()
for _ in range(num_loops):
for row, entry in enumerate(vector):
if entry == 0:
continue
# send event on a different address in order to
# select one of the two rows connected to a driver
entry += 32 if row % 2 == 1 else 0
vector_builder.write(
halco.SpikePack1ToChipOnDLS(),
self.prepare_event(
halco.SynapseLabel(entry),
halco.SynapseDriverOnSynapseDriverBlock(row // 2)))
# wait only if needed:
if self.wait_period > 1:
vector_builder.block_until(
halco.TimerOnDLS(), hal.Timer.Value(
int(self.wait_period * entry_counter)))
entry_counter += 1
for _ in range(num_copies):
builder.copy_back(vector_builder)
# Read amplitudes # Read amplitudes
coord = halco.CADCSampleRowOnDLS( coord = halco.CADCSampleRowOnDLS(
......
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