summaryrefslogtreecommitdiff
path: root/src/online_crossbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/online_crossbar.c')
-rw-r--r--src/online_crossbar.c161
1 files changed, 113 insertions, 48 deletions
diff --git a/src/online_crossbar.c b/src/online_crossbar.c
index b01ea19..ff346bd 100644
--- a/src/online_crossbar.c
+++ b/src/online_crossbar.c
@@ -8,6 +8,7 @@
#include <ngspice/sharedspice.h>
#include <pthread.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -32,14 +33,41 @@ struct Online_Crossbar {
pthread_cond_t progress;
};
+static int config_is_valid(const Online_Crossbar_Config *config)
+{
+ if (!config || config->num_neurons == 0 || config->num_outputs == 0 ||
+ config->num_timesteps == 0 || !isfinite(config->time_step) ||
+ config->time_step <= 0.0 || !isfinite(config->spike_amplitude) ||
+ config->spike_amplitude == 0.0 ||
+ !isfinite(config->load_resistance) ||
+ config->load_resistance <= 0.0 || !isfinite(config->r_on) ||
+ !isfinite(config->r_off) || config->r_on <= 0.0 ||
+ config->r_off <= config->r_on || !config->model_path ||
+ !config->subcircuit_name || !config->netlist_path) {
+ return 0;
+ }
+
+ if (config->num_outputs > SIZE_MAX / 2 ||
+ config->num_neurons > SIZE_MAX / 2 ||
+ config->num_timesteps > SIZE_MAX / config->num_outputs ||
+ config->num_timesteps * config->num_outputs >
+ SIZE_MAX / sizeof(double)) {
+ return 0;
+ }
+
+ double stop_time = config->num_timesteps * config->time_step;
+ return isfinite(stop_time) && stop_time > 0.0;
+}
+
static int callback_text(char *text, int ident, void *user_data)
{
(void)ident;
(void)user_data;
if (text &&
(strncmp(text, "stderr", 6) == 0 || strstr(text, "Error") != NULL ||
- strstr(text, "error") != NULL))
+ strstr(text, "error") != NULL)) {
fprintf(stderr, "ngspice: %s\n", text);
+ }
return 0;
}
@@ -77,12 +105,14 @@ static int callback_background(NG_BOOL running, int ident, void *user_data)
(void)ident;
Online_Crossbar *crossbar = user_data;
/* libngspice passes false at worker start and true at worker exit. */
- if (!running)
+ if (!running) {
return 0;
+ }
pthread_mutex_lock(&crossbar->mutex);
crossbar->simulation_done = 1;
- if (crossbar->result_count < crossbar->config.num_timesteps)
+ if (crossbar->result_count < crossbar->config.num_timesteps) {
fail_locked(crossbar);
+ }
pthread_cond_broadcast(&crossbar->progress);
pthread_cond_broadcast(&crossbar->state_available);
pthread_mutex_unlock(&crossbar->mutex);
@@ -92,28 +122,33 @@ static int callback_background(NG_BOOL running, int ident, void *user_data)
static int row_from_name(const char *name, size_t *row_out)
{
const char *digits = name + strlen(name);
- while (digits > name && isdigit((unsigned char)digits[-1]))
+ while (digits > name && isdigit((unsigned char)digits[-1])) {
digits--;
- if (*digits == '\0')
+ }
+ if (*digits == '\0') {
return -1;
+ }
char *end = NULL;
unsigned long value = strtoul(digits, &end, 10);
- if (end == digits || *end != '\0')
+ if (end == digits || *end != '\0') {
return -1;
+ }
*row_out = (size_t)value;
return 0;
}
static size_t timestep_for_time(const Online_Crossbar *crossbar, double time)
{
- if (time <= 0.0)
+ if (time <= 0.0) {
return 0;
+ }
double scaled = time / crossbar->config.time_step;
/* Hold state[t] over the full interval (t*dt, (t+1)*dt]. */
double interval = ceil(scaled - 1.0e-9);
size_t timestep = interval <= 1.0 ? 0 : (size_t)interval - 1;
- if (timestep >= crossbar->config.num_timesteps)
+ if (timestep >= crossbar->config.num_timesteps) {
timestep = crossbar->config.num_timesteps - 1;
+ }
return timestep;
}
@@ -132,8 +167,9 @@ static int callback_voltage(double *voltage, double time, char *name, int ident,
size_t timestep = timestep_for_time(crossbar, time);
pthread_mutex_lock(&crossbar->mutex);
- while (!crossbar->failed && crossbar->published_count <= timestep)
+ while (!crossbar->failed && crossbar->published_count <= timestep) {
pthread_cond_wait(&crossbar->state_available, &crossbar->mutex);
+ }
if (crossbar->failed) {
pthread_mutex_unlock(&crossbar->mutex);
return 1;
@@ -178,8 +214,9 @@ static int callback_data(pvecvaluesall values, int count, int ident,
continue;
}
const char *col = strstr(value->name, "col");
- if (!col)
+ if (!col) {
continue;
+ }
char *end = NULL;
unsigned long index = strtoul(col + 3, &end, 10);
if (end != col + 3 &&
@@ -197,8 +234,9 @@ static int callback_data(pvecvaluesall values, int count, int ident,
size_t timestep = (size_t)rounded - 1;
int complete = 1;
for (size_t i = 0; i < crossbar->config.num_outputs * 2;
- i++)
+ i++) {
complete = complete && found[i];
+ }
if (complete) {
double *decoded =
crossbar->results +
@@ -213,14 +251,16 @@ static int callback_data(pvecvaluesall values, int count, int ident,
decoded) == 0) {
pthread_mutex_lock(&crossbar->mutex);
if (crossbar->result_count <
- timestep + 1)
+ timestep + 1) {
crossbar->result_count =
timestep + 1;
+ }
if (timestep + 1 <
- crossbar->config.num_timesteps)
+ crossbar->config.num_timesteps) {
ngSpice_SetBkpt(
(timestep + 2) *
crossbar->config.time_step);
+ }
pthread_cond_broadcast(
&crossbar->progress);
pthread_mutex_unlock(&crossbar->mutex);
@@ -238,38 +278,44 @@ int online_crossbar_init(const Online_Crossbar_Config *config,
const spires_reservoir *reservoir,
Online_Crossbar **crossbar_out)
{
- if (!config || !reservoir || !crossbar_out ||
- config->num_neurons == 0 || config->num_outputs == 0 ||
- config->num_timesteps == 0 || config->time_step <= 0.0 ||
- config->spike_amplitude == 0.0 || config->load_resistance <= 0.0 ||
- !config->model_path || !config->subcircuit_name ||
- !config->netlist_path)
+ if (!crossbar_out) {
return -1;
+ }
+ *crossbar_out = NULL;
+ if (!reservoir || !config_is_valid(config)) {
+ return -1;
+ }
Online_Crossbar *crossbar = calloc(1, sizeof(*crossbar));
- if (!crossbar)
+ if (!crossbar) {
return -1;
+ }
crossbar->config = *config;
- if (pthread_mutex_init(&crossbar->mutex, NULL) != 0)
+ if (pthread_mutex_init(&crossbar->mutex, NULL) != 0) {
goto fail;
+ }
crossbar->mutex_initialized = 1;
- if (pthread_cond_init(&crossbar->state_available, NULL) != 0)
+ if (pthread_cond_init(&crossbar->state_available, NULL) != 0) {
goto fail;
+ }
crossbar->state_condition_initialized = 1;
- if (pthread_cond_init(&crossbar->progress, NULL) != 0)
+ if (pthread_cond_init(&crossbar->progress, NULL) != 0) {
goto fail;
+ }
crossbar->progress_condition_initialized = 1;
crossbar->state_ring = calloc(2 * config->num_neurons, sizeof(double));
crossbar->results =
calloc(config->num_timesteps * config->num_outputs, sizeof(double));
- if (!crossbar->state_ring || !crossbar->results)
+ if (!crossbar->state_ring || !crossbar->results) {
goto fail;
+ }
if (convert_weights_to_resistances(
reservoir, config->num_neurons, config->num_outputs,
config->r_on, config->r_off, &crossbar->resistances,
- &crossbar->mapping) != 0)
+ &crossbar->mapping) != 0) {
goto fail;
+ }
Crossbar_Config netlist = {.rows = config->num_neurons,
.columns = config->num_outputs * 2,
@@ -283,8 +329,9 @@ int online_crossbar_init(const Online_Crossbar_Config *config,
.stop_time = config->num_timesteps *
config->time_step,
.print_state_nodes = 0};
- if (generate_online_crossbar(config->netlist_path, &netlist) != 0)
+ if (generate_online_crossbar(config->netlist_path, &netlist) != 0) {
goto fail;
+ }
*crossbar_out = crossbar;
return 0;
@@ -296,23 +343,32 @@ fail:
int online_crossbar_start(Online_Crossbar *crossbar)
{
- if (!crossbar || crossbar->started)
+ if (!crossbar || crossbar->started) {
return -1;
+ }
if (ngSpice_Init(callback_text, callback_text, callback_exit,
callback_data, callback_init_data, callback_background,
- crossbar) != 0 ||
- ngSpice_Init_Sync(callback_voltage, NULL, NULL, NULL, crossbar) !=
- 0)
+ crossbar) != 0) {
return -1;
+ }
+ if (ngSpice_Init_Sync(callback_voltage, NULL, NULL, NULL, crossbar) !=
+ 0) {
+ ngSpice_Reset();
+ return -1;
+ }
char command[4096];
- if (snprintf(command, sizeof(command), "source %s",
- crossbar->config.netlist_path) >= (int)sizeof(command) ||
- ngSpice_Command(command) != 0)
+ int written = snprintf(command, sizeof(command), "source %s",
+ crossbar->config.netlist_path);
+ if (written < 0 || (size_t)written >= sizeof(command) ||
+ ngSpice_Command(command) != 0) {
+ ngSpice_Reset();
return -1;
+ }
crossbar->started = 1;
ngSpice_SetBkpt(crossbar->config.time_step);
if (ngSpice_Command("bg_run") != 0) {
+ ngSpice_Reset();
crossbar->started = 0;
return -1;
}
@@ -325,12 +381,15 @@ int online_crossbar_submit(Online_Crossbar *crossbar, size_t timestep,
{
if (!crossbar || !state || !output_ready || !crossbar->started ||
timestep >= crossbar->config.num_timesteps ||
- timestep != crossbar->published_count)
+ timestep != crossbar->published_count ||
+ (timestep != 0 && !previous_output)) {
return -1;
+ }
pthread_mutex_lock(&crossbar->mutex);
- while (!crossbar->failed && timestep >= crossbar->consumed_count + 2)
+ while (!crossbar->failed && timestep >= crossbar->consumed_count + 2) {
pthread_cond_wait(&crossbar->progress, &crossbar->mutex);
+ }
if (crossbar->failed) {
pthread_mutex_unlock(&crossbar->mutex);
return -1;
@@ -343,13 +402,10 @@ int online_crossbar_submit(Online_Crossbar *crossbar, size_t timestep,
*output_ready = timestep != 0;
if (timestep != 0) {
- if (!previous_output) {
- pthread_mutex_unlock(&crossbar->mutex);
- return -1;
- }
- while (!crossbar->failed && crossbar->result_count < timestep)
+ while (!crossbar->failed && crossbar->result_count < timestep) {
pthread_cond_wait(&crossbar->progress,
&crossbar->mutex);
+ }
if (crossbar->failed) {
pthread_mutex_unlock(&crossbar->mutex);
return -1;
@@ -366,12 +422,14 @@ int online_crossbar_submit(Online_Crossbar *crossbar, size_t timestep,
int online_crossbar_finish(Online_Crossbar *crossbar, double *final_output)
{
if (!crossbar || !final_output ||
- crossbar->published_count != crossbar->config.num_timesteps)
+ crossbar->published_count != crossbar->config.num_timesteps) {
return -1;
+ }
pthread_mutex_lock(&crossbar->mutex);
while (!crossbar->failed &&
- crossbar->result_count < crossbar->config.num_timesteps)
+ crossbar->result_count < crossbar->config.num_timesteps) {
pthread_cond_wait(&crossbar->progress, &crossbar->mutex);
+ }
if (crossbar->failed) {
pthread_mutex_unlock(&crossbar->mutex);
return -1;
@@ -386,28 +444,35 @@ int online_crossbar_finish(Online_Crossbar *crossbar, double *final_output)
void online_crossbar_destroy(Online_Crossbar *crossbar)
{
- if (!crossbar)
+ if (!crossbar) {
return;
+ }
if (crossbar->started && ngSpice_running()) {
ngSpice_Command("bg_halt");
if (crossbar->mutex_initialized) {
pthread_mutex_lock(&crossbar->mutex);
- while (!crossbar->simulation_done && ngSpice_running())
+ while (!crossbar->simulation_done &&
+ ngSpice_running()) {
pthread_cond_wait(&crossbar->progress,
&crossbar->mutex);
+ }
pthread_mutex_unlock(&crossbar->mutex);
}
}
- if (crossbar->started)
+ if (crossbar->started) {
ngSpice_Reset();
+ }
free(crossbar->resistances);
free(crossbar->state_ring);
free(crossbar->results);
- if (crossbar->state_condition_initialized)
+ if (crossbar->state_condition_initialized) {
pthread_cond_destroy(&crossbar->state_available);
- if (crossbar->progress_condition_initialized)
+ }
+ if (crossbar->progress_condition_initialized) {
pthread_cond_destroy(&crossbar->progress);
- if (crossbar->mutex_initialized)
+ }
+ if (crossbar->mutex_initialized) {
pthread_mutex_destroy(&crossbar->mutex);
+ }
free(crossbar);
}