Commit 4e19d940 authored by Jonathan Jenkins's avatar Jonathan Jenkins

config overhaul + annotation-aware mapping

All configuration now proceeds on a per-LP level, and requires separate
registration and configuration calls, as seen in the test programs.
model_net_set_params is no longer used, and is replaced by model_net_register
and model_net_configure. The dragonfly network, having two LP types bundled in
the same code-path, is special-cased in the registration code.

LP-mapping in model-net now has the following defaults:
- counts via codes_mapping_get_lp_count are now with respect to the calling
  network LP's annotation.
- when looking up network LPs via
  codes_mapping_get_lp_info/codes_mapping_get_lp_id, the annotation of the
  calling network LP is used. Hence, routing now occurs only between LPs of the
  same annotation. If the destination LP's group specified by model_net_*event
  does not contain a modelnet LP with the same annotation as the modelnet LP in
  the sender's group, then an error will occur (in codes_mapping).

Known Issues:
- modelnet users currently cannot specify which modelnet LP to use in the case
  of multiple modelnet LPs in the sender's group. This will be fixed in future
  commits after a consensus is reached on the best way to expose this
  information.
parent c65c84a1
...@@ -24,6 +24,12 @@ ...@@ -24,6 +24,12 @@
extern int model_net_base_magic; extern int model_net_base_magic;
// register the networks with ROSS, given the array of flags, one for each
// network type
void model_net_base_register(int *do_config_nets);
// configure the base LP type, setting up general parameters
void model_net_base_configure();
// Construct a model-net-specific event, analagous to a tw_event_new and // Construct a model-net-specific event, analagous to a tw_event_new and
// codes_event_new. The difference here is that we return pointers to // codes_event_new. The difference here is that we return pointers to
// both the message data (to be cast into the appropriate type) and the // both the message data (to be cast into the appropriate type) and the
...@@ -49,7 +55,7 @@ void * model_net_method_get_edata(int net_id, void * msg); ...@@ -49,7 +55,7 @@ void * model_net_method_get_edata(int net_id, void * msg);
/// use them /// use them
// init method // init method
void model_net_base_init(int id_count, int *ids); void model_net_base_init(int *do_config_nets);
enum model_net_base_event_type { enum model_net_base_event_type {
MN_BASE_NEW_MSG, MN_BASE_NEW_MSG,
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
struct model_net_method struct model_net_method
{ {
uint64_t packet_size; /* packet size */ uint64_t packet_size; /* packet size */
void (*mn_setup)(const void* net_params); /* For initializing the network */ void (*mn_configure)(); /* For initializing the network */
tw_stime (*model_net_method_packet_event)( tw_stime (*model_net_method_packet_event)(
char* category, char* category,
tw_lpid final_dest_lp, tw_lpid final_dest_lp,
......
...@@ -30,10 +30,6 @@ enum sched_type { ...@@ -30,10 +30,6 @@ enum sched_type {
extern char * sched_names[]; extern char * sched_names[];
/// global for scheduler
/// TODO: move away from using the global for when we have multiple networks
extern enum sched_type mn_sched_type;
/// scheduler decls /// scheduler decls
typedef struct model_net_sched_s model_net_sched; typedef struct model_net_sched_s model_net_sched;
......
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
* messages as part of an event and expects FCFS ordering. A proper fix which * messages as part of an event and expects FCFS ordering. A proper fix which
* involves model-net LP-level scheduling of requests is ideal, but not * involves model-net LP-level scheduling of requests is ideal, but not
* feasible for now (would basically have to redesign model-net), so expose * feasible for now (would basically have to redesign model-net), so expose
* explicit start-sequence and stop-sequence markers as a workaround */ * explicit start-sequence and stop-sequence markers as a workaround
*/
extern int in_sequence; extern int in_sequence;
extern tw_stime mn_msg_offset; extern tw_stime mn_msg_offset;
#define MN_START_SEQ() do {\ #define MN_START_SEQ() do {\
...@@ -36,11 +37,6 @@ extern tw_stime mn_msg_offset; ...@@ -36,11 +37,6 @@ extern tw_stime mn_msg_offset;
} while (0) } while (0)
typedef struct simplenet_param simplenet_param;
typedef struct simplewan_param simplewan_param;
typedef struct dragonfly_param dragonfly_param;
typedef struct torus_param torus_param;
typedef struct loggp_param loggp_param;
typedef struct mn_stats mn_stats; typedef struct mn_stats mn_stats;
// use the X-macro to get types and names rolled up into one structure // use the X-macro to get types and names rolled up into one structure
...@@ -93,53 +89,18 @@ struct mn_stats ...@@ -93,53 +89,18 @@ struct mn_stats
long max_event_size; long max_event_size;
}; };
/* structs for initializing a network/ specifying network parameters */ /* Registers all model-net LPs in ROSS. Should be called after
struct loggp_param * configuration_load, but before codes_mapping_setup */
{ void model_net_register();
char* net_config_file; /* file with loggp parameter table */
};
/* structs for initializing a network/ specifying network parameters */
struct simplenet_param
{
double net_startup_ns; /*simplenet startup cost*/
double net_bw_mbps; /*Link bandwidth per byte*/
int num_nics;
};
struct simplewan_param
{
char bw_filename[MAX_NAME_LENGTH];
char startup_filename[MAX_NAME_LENGTH];
};
struct dragonfly_param /* Configures all model-net LPs based on the CODES configuration, and returns
{ * ids to address the different types by.
int num_routers; /*Number of routers in a group*/ *
double local_bandwidth;/* bandwidth of the router-router channels within a group */ * id_count - the output number of networks
double global_bandwidth;/* bandwidth of the inter-group router connections */ *
double cn_bandwidth;/* bandwidth of the compute node channels connected to routers */ * return - the set of network IDs, indexed in the order given by the
int num_vcs; /* number of virtual channels */ * modelnet_order configuration parameter */
int local_vc_size; /* buffer size of the router-router channels */ int* model_net_configure(int *id_count);
int global_vc_size; /* buffer size of the global channels */
int cn_vc_size; /* buffer size of the compute node channels */
short routing; /* minimal or non-minimal routing */
short chunk_size; /* full-sized packets are broken into smaller chunks.*/
};
struct torus_param
{
int n_dims; /*Dimension of the torus network, 5-D, 7-D or any other*/
int* dim_length; /*Length of each torus dimension*/
double link_bandwidth;/* bandwidth for each torus link */
int buffer_size; /* number of buffer slots for each vc in flits*/
int num_vc; /* number of virtual channels for each torus link */
float mean_process;/* mean process time for each flit */
int chunk_size; /* chunk is the smallest unit--default set to 32 */
};
/* In general we need to figure out how to pass configuration information to
* the methods and we need to be able to calculate ross event message size.
*/
/* Initialize/configure the network(s) based on the CODES configuration. /* Initialize/configure the network(s) based on the CODES configuration.
* returns an array of the network ids, indexed in the order given by the * returns an array of the network ids, indexed in the order given by the
......
This diff is collapsed.
...@@ -26,15 +26,6 @@ ...@@ -26,15 +26,6 @@
/*Define loggp data types and structs*/ /*Define loggp data types and structs*/
typedef struct loggp_state loggp_state; typedef struct loggp_state loggp_state;
struct loggp_state
{
/* next idle times for network card, both inbound and outbound */
tw_stime net_send_next_idle;
tw_stime net_recv_next_idle;
struct mn_stats loggp_stats_array[CATEGORY_MAX];
};
/* loggp parameters for a given msg size, as reported by netgauge */ /* loggp parameters for a given msg size, as reported by netgauge */
struct param_table_entry struct param_table_entry
{ {
...@@ -50,8 +41,32 @@ struct param_table_entry ...@@ -50,8 +41,32 @@ struct param_table_entry
double G; double G;
double lsqu_gG; double lsqu_gG;
}; };
struct param_table_entry param_table[100]; typedef struct param_table_entry param_table_entry;
static int param_table_size = 0;
typedef struct loggp_param loggp_param;
// loggp parameters
struct loggp_param
{
int table_size;
param_table_entry table[100];
};
struct loggp_state
{
/* next idle times for network card, both inbound and outbound */
tw_stime net_send_next_idle;
tw_stime net_recv_next_idle;
const char * anno;
const loggp_param *params;
struct mn_stats loggp_stats_array[CATEGORY_MAX];
};
/* annotation-specific parameters (unannotated entry occurs at the
* last index) */
static uint64_t num_params = 0;
static loggp_param * all_params = NULL;
static const config_anno_map_t * anno_map = NULL;
static int loggp_magic = 0; static int loggp_magic = 0;
...@@ -73,21 +88,11 @@ static void loggp_collective(); ...@@ -73,21 +88,11 @@ static void loggp_collective();
/* collective network calls-- rc */ /* collective network calls-- rc */
static void loggp_collective_rc(); static void loggp_collective_rc();
/* allocate a new event that will pass through loggp to arriave at its
* destination:
*
* - category: category name to associate with this communication
* - final_dest_gid: the LP that the message should be delivered to.
* - event_size_bytes: size of event msg that will be delivered to
* final_dest_gid.
* - local_event_size_byte: size of event message that will delivered to
* local LP upon local send comletion (set to 0 if not used)
* - net_msg_size_bytes: size of simulated network message in bytes.
* - sender: LP calling this function.
*/
/* Modelnet interface events */ /* Modelnet interface events */
/* sets up the loggp parameters through modelnet interface */ /* sets up the loggp parameters through modelnet interface */
static void loggp_setup(const void* net_params); static void loggp_configure();
static void loggp_set_params(const char * config_file, loggp_param * params);
/* Issues a loggp packet event call */ /* Issues a loggp packet event call */
static tw_stime loggp_packet_event( static tw_stime loggp_packet_event(
...@@ -112,12 +117,14 @@ static void loggp_report_stats(); ...@@ -112,12 +117,14 @@ static void loggp_report_stats();
static tw_lpid loggp_find_local_device(tw_lp *sender); static tw_lpid loggp_find_local_device(tw_lp *sender);
static struct param_table_entry* find_params(uint64_t msg_size); static const struct param_table_entry* find_params(
uint64_t msg_size,
const loggp_param *params);
/* data structure for model-net statistics */ /* data structure for model-net statistics */
struct model_net_method loggp_method = struct model_net_method loggp_method =
{ {
.mn_setup = loggp_setup, .mn_configure = loggp_configure,
.model_net_method_packet_event = loggp_packet_event, .model_net_method_packet_event = loggp_packet_event,
.model_net_method_packet_event_rc = loggp_packet_event_rc, .model_net_method_packet_event_rc = loggp_packet_event_rc,
.mn_get_lp_type = loggp_get_lp_type, .mn_get_lp_type = loggp_get_lp_type,
...@@ -220,6 +227,14 @@ static void loggp_init( ...@@ -220,6 +227,14 @@ static void loggp_init(
ns->net_send_next_idle = tw_now(lp); ns->net_send_next_idle = tw_now(lp);
ns->net_recv_next_idle = tw_now(lp); ns->net_recv_next_idle = tw_now(lp);
ns->anno = codes_mapping_get_annotation_by_lpid(lp->gid);
if (ns->anno == NULL)
ns->params = &all_params[num_params-1];
else{
int id = configuration_get_annotation_index(ns->anno, anno_map);
ns->params = &all_params[id];
}
bj_hashlittle2(LP_METHOD_NM, strlen(LP_METHOD_NM), &h1, &h2); bj_hashlittle2(LP_METHOD_NM, strlen(LP_METHOD_NM), &h1, &h2);
loggp_magic = h1+h2; loggp_magic = h1+h2;
/* printf("\n loggp_magic %d ", loggp_magic); */ /* printf("\n loggp_magic %d ", loggp_magic); */
...@@ -324,9 +339,9 @@ static void handle_msg_ready_event( ...@@ -324,9 +339,9 @@ static void handle_msg_ready_event(
loggp_message *m_new; loggp_message *m_new;
struct mn_stats* stat; struct mn_stats* stat;
double recv_time; double recv_time;
struct param_table_entry *param; const struct param_table_entry *param;
param = find_params(m->net_msg_size_bytes); param = find_params(m->net_msg_size_bytes, ns->params);
recv_time = ((double)(m->net_msg_size_bytes-1)*param->G); recv_time = ((double)(m->net_msg_size_bytes-1)*param->G);
/* scale to nanoseconds */ /* scale to nanoseconds */
...@@ -420,9 +435,9 @@ static void handle_msg_start_event( ...@@ -420,9 +435,9 @@ static void handle_msg_start_event(
char lp_group_name[MAX_NAME_LENGTH]; char lp_group_name[MAX_NAME_LENGTH];
int total_event_size; int total_event_size;
double xmit_time; double xmit_time;
struct param_table_entry *param; const struct param_table_entry *param;
param = find_params(m->net_msg_size_bytes); param = find_params(m->net_msg_size_bytes, ns->params);
total_event_size = model_net_get_msg_sz(LOGGP) + m->event_size_bytes + total_event_size = model_net_get_msg_sz(LOGGP) + m->event_size_bytes +
m->local_event_size_bytes; m->local_event_size_bytes;
...@@ -465,7 +480,7 @@ static void handle_msg_start_event( ...@@ -465,7 +480,7 @@ static void handle_msg_start_event(
// TODO: make annotation-aware // TODO: make annotation-aware
codes_mapping_get_lp_info(m->final_dest_gid, lp_group_name, &mapping_grp_id, codes_mapping_get_lp_info(m->final_dest_gid, lp_group_name, &mapping_grp_id,
NULL, &mapping_type_id, NULL, &mapping_rep_id, &mapping_offset); NULL, &mapping_type_id, NULL, &mapping_rep_id, &mapping_offset);
codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM, NULL, 1, codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM, ns->anno, 0,
mapping_rep_id, mapping_offset, &dest_id); mapping_rep_id, mapping_offset, &dest_id);
void *m_data; void *m_data;
...@@ -574,52 +589,76 @@ static tw_stime loggp_packet_event( ...@@ -574,52 +589,76 @@ static tw_stime loggp_packet_event(
return xfer_to_nic_time; return xfer_to_nic_time;
} }
static void loggp_setup(const void* net_params) static void loggp_configure(){
{ char config_file[MAX_NAME_LENGTH];
loggp_param* loggp_params = (loggp_param*)net_params;
anno_map = codes_mapping_get_lp_anno_map(LP_CONFIG_NM);
assert(anno_map);
num_params = anno_map->num_annos + (anno_map->has_unanno_lp > 0);
all_params = malloc(num_params * sizeof(*all_params));
for (uint64_t i = 0; i < anno_map->num_annos; i++){
const char * anno = anno_map->annotations[i];
int rc = configuration_get_value_relpath(&config, "PARAMS",
"net_config_file", anno, config_file, MAX_NAME_LENGTH);
if (rc == 0){
tw_error(TW_LOC, "unable to read PARAMS:net_config_file@%s",
anno);
}
loggp_set_params(config_file, &all_params[i]);
}
if (anno_map->has_unanno_lp > 0){
int rc = configuration_get_value_relpath(&config, "PARAMS",
"net_config_file", NULL, config_file, MAX_NAME_LENGTH);
if (rc == 0){
tw_error(TW_LOC, "unable to read PARAMS:net_config_file");
}
loggp_set_params(config_file, &all_params[anno_map->num_annos]);
}
}
void loggp_set_params(const char * config_file, loggp_param * params){
FILE *conf; FILE *conf;
int ret; int ret;
char buffer[512]; char buffer[512];
int line_nr = 0; int line_nr = 0;
printf("Loggp configured to use parameters from file %s\n", config_file);
/* TODO: update this to read on one proc and then broadcast */ conf = fopen(config_file, "r");
printf("Loggp configured to use parameters from file %s\n", loggp_params->net_config_file);
conf = fopen(loggp_params->net_config_file, "r");
if(!conf) if(!conf)
{ {
perror("fopen"); perror("fopen");
assert(0); assert(0);
} }
params->table_size = 0;
while(fgets(buffer, 512, conf)) while(fgets(buffer, 512, conf))
{ {
line_nr++; line_nr++;
if(buffer[0] == '#') if(buffer[0] == '#')
continue; continue;
ret = sscanf(buffer, "%llu %d %lf %lf %lf %lf %lf %lf %lf %lf %lf", ret = sscanf(buffer, "%llu %d %lf %lf %lf %lf %lf %lf %lf %lf %lf",
&param_table[param_table_size].size, &params->table[params->table_size].size,
&param_table[param_table_size].n, &params->table[params->table_size].n,
&param_table[param_table_size].PRTT_10s, &params->table[params->table_size].PRTT_10s,
&param_table[param_table_size].PRTT_n0s, &params->table[params->table_size].PRTT_n0s,
&param_table[param_table_size].PRTT_nPRTT_10ss, &params->table[params->table_size].PRTT_nPRTT_10ss,
&param_table[param_table_size].L, &params->table[params->table_size].L,
&param_table[param_table_size].o_s, &params->table[params->table_size].o_s,
&param_table[param_table_size].o_r, &params->table[params->table_size].o_r,
&param_table[param_table_size].g, &params->table[params->table_size].g,
&param_table[param_table_size].G, &params->table[params->table_size].G,
&param_table[param_table_size].lsqu_gG); &params->table[params->table_size].lsqu_gG);
if(ret != 11) if(ret != 11)
{ {
fprintf(stderr, "Error: malformed line %d in %s\n", line_nr, fprintf(stderr, "Error: malformed line %d in %s\n", line_nr,
loggp_params->net_config_file); config_file);
assert(0); assert(0);
} }
param_table_size++; params->table_size++;
} }
printf("Parsed %d loggp table entries.\n", param_table_size); printf("Parsed %d loggp table entries.\n", params->table_size);
fclose(conf); fclose(conf);
...@@ -634,25 +673,26 @@ static void loggp_packet_event_rc(tw_lp *sender) ...@@ -634,25 +673,26 @@ static void loggp_packet_event_rc(tw_lp *sender)
/* find the parameters corresponding to the message size we are transmitting /* find the parameters corresponding to the message size we are transmitting
*/ */
static struct param_table_entry* find_params(uint64_t msg_size) static const struct param_table_entry* find_params(
{ uint64_t msg_size,
const loggp_param *params) {
int i; int i;
/* pick parameters based on the next smallest size in the table, but /* pick parameters based on the next smallest size in the table, but
* default to beginning or end of table if we are out of range * default to beginning or end of table if we are out of range
*/ */
for(i=0; i<param_table_size; i++) for(i=0; i < params->table_size; i++)
{ {
if(param_table[i].size > msg_size) if(params->table[i].size > msg_size)
{ {
break; break;
} }
} }
if(i>=param_table_size) if(i>=params->table_size)
i = param_table_size-1; i = params->table_size-1;
return(&param_table[i]); return(&params->table[i]);
} }
static tw_lpid loggp_find_local_device(tw_lp *sender) static tw_lpid loggp_find_local_device(tw_lp *sender)
......
...@@ -23,18 +23,32 @@ int model_net_base_magic; ...@@ -23,18 +23,32 @@ int model_net_base_magic;
// issues... // issues...
static int msg_offsets[MAX_NETS]; static int msg_offsets[MAX_NETS];
typedef struct model_net_base_params {
enum sched_type stype;
uint64_t packet_size;
} model_net_base_params;
/* annotation-specific parameters (unannotated entry occurs at the
* last index) */
static int num_params = 0;
static const char * annos[CONFIGURATION_MAX_ANNOS];
static model_net_base_params all_params[CONFIGURATION_MAX_ANNOS];
typedef struct model_net_base_state { typedef struct model_net_base_state {
int net_id; int net_id;
// whether scheduler loop is running // whether scheduler loop is running
int in_sched_loop; int in_sched_loop;
// model-net scheduler // model-net scheduler
model_net_sched *sched; model_net_sched *sched;
// parameters
const model_net_base_params * params;
// lp type and state of underlying model net method - cache here so we // lp type and state of underlying model net method - cache here so we
// don't have to constantly look up // don't have to constantly look up
const tw_lptype *sub_type; const tw_lptype *sub_type;
void *sub_state; void *sub_state;
} model_net_base_state; } model_net_base_state;
/**** END SIMULATION DATA STRUCTURES ****/ /**** END SIMULATION DATA STRUCTURES ****/
/**** BEGIN LP, EVENT PROCESSING FUNCTION DECLS ****/ /**** BEGIN LP, EVENT PROCESSING FUNCTION DECLS ****/
...@@ -93,44 +107,132 @@ tw_lptype model_net_base_lp = { ...@@ -93,44 +107,132 @@ tw_lptype model_net_base_lp = {
/**** BEGIN IMPLEMENTATIONS ****/ /**** BEGIN IMPLEMENTATIONS ****/
void model_net_base_init(int id_count, int *ids){ void model_net_base_register(int *do_config_nets){
// here, we initialize ALL lp types to use the base type
for (int i = 0; i < MAX_NETS; i++){
if (do_config_nets[i]){
lp_type_register(model_net_lp_config_names[i], &model_net_base_lp);
// HACK: unfortunately, we need to special-case dragonfly
// registration at the moment - there are two LPs, and
// previously the LP matched on configuration initialized
// the "router" LP. Now that the base LP is in charge of
// registration, we need to take care of it
// TODO: fix the interface to have underlying networks do
// the registration
if (i==DRAGONFLY){
lp_type_register("dragonfly_router",
&method_array[DRAGONFLY]->mn_get_lp_type()[1]);
}
}
}
}
static void base_read_config(const char * anno, model_net_base_params *p){
char sched[MAX_NAME_LENGTH];
long int packet_size_l = 0;
uint64_t packet_size;
int ret;
// TODO: make this annotation-specific - put in the config loop, make part
// of model-net base
ret = configuration_get_value(&config, "PARAMS", "modelnet_scheduler",
anno, sched, MAX_NAME_LENGTH);
configuration_get_value_longint(&config, "PARAMS", "packet_size", anno,
&packet_size_l);
packet_size = packet_size_l;
if (ret > 0){
int i;
for (i = 0; i < MAX_SCHEDS; i++){
if (strcmp(sched_names[i], sched) == 0){
p->stype = i;
break;
}
}
if (i == MAX_SCHEDS){
tw_error(TW_LOC,"Unknown value for PARAMS:modelnet-scheduler : "
"%s\n", sched);
}
}
else{
// default: FCFS
p->stype = MN_SCHED_FCFS;
}
if (p->stype == MN_SCHED_FCFS_FULL){
// override packet size to something huge (leave a bit in the unlikely
// case that an op using packet size causes overflow)
packet_size = 1ull << 62;
}
else if (!packet_size && p->stype != MN_SCHED_FCFS_FULL)
{
packet_size = 512;
fprintf(stderr, "Warning, no packet size specified, setting packet size to %llu\n", packet_size);
}
p->packet_size = packet_size;
}
void model_net_base_configure(){
uint32_t h1=0, h2=0; uint32_t h1=0, h2=0;
bj_hashlittle2(MN_NAME, strlen(MN_NAME), &h1, &h2); bj_hashlittle2(MN_NAME, strlen(MN_NAME), &h1, &h2);
model_net_base_magic = h1+h2; model_net_base_magic = h1+h2;
// here, we initialize ALL lp types to use the base type // set up offsets - doesn't matter if they are actually used or not
// TODO: only initialize ones that are actually used msg_offsets[SIMPLENET] =
for (int i = 0; i < id_count; i++){ offsetof(model_net_wrap_msg, msg.m_snet);
lp_type_register(model_net_lp_config_names[ids[i]], &model_net_base_lp); msg_offsets[SIMPLEWAN] =
offsetof(model_net_wrap_msg, msg.m_swan);
msg_offsets[TORUS] =
offsetof(model_net_wrap_msg, msg.m_torus);
msg_offsets[DRAGONFLY] =
offsetof(model_net_wrap_msg, msg.m_dfly);
msg_offsets[LOGGP] =
offsetof(model_net_wrap_msg, msg.m_loggp);
// perform the configuration(s)
// This part is tricky, as we basically have to look up all annotations that
// have LP names of the form modelnet_*. For each of those, we need to read
// the base parameters
// - the init is a little easier as we can use the LP-id to look up the
// annotation
// first grab all of the annotations and store locally
for (int c = 0; c < lpconf.lpannos_count; c++){
const config_anno_map_t *amap = &lpconf.lpannos[c];
if (strncmp("modelnet_", amap->lp_name, 9) == 0){
for (int n = 0; n < amap->num_annos; n++){
int a;
for (a = 0; a < num_params; a++){
if (annos[a] != NULL &&
strcmp(amap->annotations[n], annos[a]) == 0){
break;
}
}
if (a == num_params){
// found a new annotation
annos[num_params++] = amap->annotations[n];
}
}
if (amap->has_unanno_lp){
int a;
for (a = 0; a < num_params; a++){
if (annos[a] == NULL)
break;
}
if (a == num_params){
// found a new (empty) annotation
annos[num_params++] = NULL;
}
}
}
} }
// initialize the msg-specific offsets // now that we have all of the annos for all of the networks, loop through
for (int i = 0; i < id_count; i++){ // and read the configs
switch(ids[i]){ for (int i = 0; i < num_params; i++){
case SIMPLENET: base_read_config(annos[i], &all_params[i]);
msg_offsets[SIMPLENET] =
offsetof(model_net_wrap_msg, msg.m_snet);
break;
case SIMPLEWAN:
msg_offsets[SIMPLEWAN] =
offsetof(model_net_wrap_msg, msg.m_swan);
break;
case TORUS:
msg_offsets[TORUS] =
offsetof(model_net_wrap_msg, msg.m_torus);
break;