model-net.c 20.3 KB
Newer Older
1
/*
Philip Carns's avatar
Philip Carns committed
2
 * Copyright (C) 2013 University of Chicago.
3
 * See COPYRIGHT notice in top-level directory.
Philip Carns's avatar
Philip Carns committed
4
 *
5
 */
Philip Carns's avatar
Philip Carns committed
6

7
8
9
#include <string.h>
#include <assert.h>

10
#include "codes/model-net.h"
11
#include "codes/model-net-method.h"
12
#include "codes/model-net-lp.h"
13
#include "codes/model-net-sched.h"
14
#include "codes/codes.h"
15

16
17
18
19
#define STR_SIZE 16
#define PROC_TIME 10.0

extern struct model_net_method simplenet_method;
20
extern struct model_net_method simplewan_method;
21
extern struct model_net_method torus_method;
22
extern struct model_net_method dragonfly_method;
Philip Carns's avatar
Philip Carns committed
23
extern struct model_net_method loggp_method;
24

25
26
27
28
29
30
31
32
33
34
35
36
#define X(a,b,c,d) b,
char * model_net_lp_config_names[] = {
    NETWORK_DEF
};
#undef X

#define X(a,b,c,d) c,
char * model_net_method_names[] = {
    NETWORK_DEF
};
#undef X

37
/* Global array initialization, terminated with a NULL entry */
38
39
40
41
42
#define X(a,b,c,d) d,
struct model_net_method* method_array[] = { 
    NETWORK_DEF
};
#undef X
43

44
45
46
int in_sequence = 0;
tw_stime mn_msg_offset = 0.0;

47
int model_net_setup(char* name,
48
		    uint64_t packet_size,
49
50
		    const void* net_params)
{
51
     int i;
52
53
54
    /* find struct for underlying method (according to configuration file) */
     for(i=0; method_array[i] != NULL; i++)
     {
55
     	if(strcmp(model_net_method_names[i], name) == 0)
56
57
58
59
60
61
	{
	   method_array[i]->mn_setup(net_params);
	   method_array[i]->packet_size = packet_size;
	   return(i);
	}
     }
62
     fprintf(stderr, "Error: undefined network name %s (Available options simplenet, torus, dragonfly) \n", name);
63
64
65
     return -1; // indicating error
}

66
67
68
int model_net_get_id(char *name){
    int i;
    for(i=0; method_array[i] != NULL; i++) {
69
        if(strcmp(model_net_method_names[i], name) == 0) {
70
71
72
73
74
75
            return i;
        }
    }
    return -1;
}

76
77
78
void model_net_write_stats(tw_lpid lpid, struct mn_stats* stat)
{
    int ret;
79
    char id[19+CATEGORY_NAME_MAX+1];
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    char data[1024];

    sprintf(id, "model-net-category-%s", stat->category);
    sprintf(data, "lp:%ld\tsend_count:%ld\tsend_bytes:%ld\tsend_time:%f\t" 
        "recv_count:%ld\trecv_bytes:%ld\trecv_time:%f\tmax_event_size:%ld\n",
        (long)lpid,
        stat->send_count,
        stat->send_bytes,
        stat->send_time,
        stat->recv_count,
        stat->recv_bytes,
        stat->recv_time,
        stat->max_event_size);

    ret = lp_io_write(lpid, id, strlen(data), data);
    assert(ret == 0);

    return;
}

void model_net_print_stats(tw_lpid lpid, mn_stats mn_stats_array[])
{

    int i;
    struct mn_stats all;

    memset(&all, 0, sizeof(all));
    sprintf(all.category, "all");

    for(i=0; i<CATEGORY_MAX; i++)
    {
        if(strlen(mn_stats_array[i].category) > 0)
        {
            all.send_count += mn_stats_array[i].send_count;
            all.send_bytes += mn_stats_array[i].send_bytes;
            all.send_time += mn_stats_array[i].send_time;
            all.recv_count += mn_stats_array[i].recv_count;
            all.recv_bytes += mn_stats_array[i].recv_bytes;
            all.recv_time += mn_stats_array[i].recv_time;
            if(mn_stats_array[i].max_event_size > all.max_event_size)
                all.max_event_size = mn_stats_array[i].max_event_size;

            model_net_write_stats(lpid, &mn_stats_array[i]);
        }
    }
    model_net_write_stats(lpid, &all);
}

struct mn_stats* model_net_find_stats(const char* category, mn_stats mn_stats_array[])
{
    int i;
    int new_flag = 0;
    int found_flag = 0;

    for(i=0; i<CATEGORY_MAX; i++)
    {
        if(strlen(mn_stats_array[i].category) == 0)
        {
            found_flag = 1;
            new_flag = 1;
            break;
        }
        if(strcmp(category, mn_stats_array[i].category) == 0)
        {
            found_flag = 1;
            new_flag = 0;
            break;
        }
    }
    assert(found_flag);

    if(new_flag)
    {
        strcpy(mn_stats_array[i].category, category);
    }
    return(&mn_stats_array[i]);
}

158
static void model_net_event_impl_base(
159
160
161
162
163
164
165
166
167
168
169
        int net_id,
        char* category, 
        tw_lpid final_dest_lp, 
        uint64_t message_size, 
        int is_pull,
        tw_stime offset,
        int remote_event_size,
        const void* remote_event,
        int self_event_size,
        const void* self_event,
        tw_lp *sender) {
170

171
172
173
174
175
176
177
178
    if (remote_event_size + self_event_size + sizeof(model_net_wrap_msg) 
            > g_tw_msg_sz){
        tw_error(TW_LOC, "Error: model_net trying to transmit an event of size "
                         "%d but ROSS is configured for events of size %zd\n",
                         remote_event_size+self_event_size+sizeof(model_net_wrap_msg),
                         g_tw_msg_sz);
        return;
    }
179

180
    tw_lpid mn_lp = model_net_find_local_device(net_id, sender);
181
    tw_stime poffset = codes_local_latency(sender);
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    if (in_sequence){
        tw_stime tmp = mn_msg_offset;
        mn_msg_offset += poffset;
        poffset += tmp;
    }
    tw_event *e = codes_event_new(mn_lp, poffset+offset, sender);

    model_net_wrap_msg *m = tw_event_data(e);
    m->event_type = MN_BASE_NEW_MSG;
    m->magic = model_net_base_magic;

    // set the request struct 
    model_net_request *r = &m->msg.m_base.u.req;
    r->net_id = net_id;
196
    r->packet_size = model_net_get_packet_size(net_id);
197
    r->final_dest_lp = final_dest_lp;
198
    r->src_lp = sender->gid;
199
200
201
    r->msg_size = message_size;
    r->remote_event_size = remote_event_size;
    r->self_event_size = self_event_size;
202
    r->is_pull = is_pull;
203
204
205
206
207
208
209
210
211
212
213
    strncpy(r->category, category, CATEGORY_NAME_MAX-1);
    r->category[CATEGORY_NAME_MAX-1]='\0';
    
    void *e_msg = (m+1);
    if (remote_event_size > 0){
        memcpy(e_msg, remote_event, remote_event_size);
        e_msg = (char*)e_msg + remote_event_size; 
    }
    if (self_event_size > 0){
        memcpy(e_msg, self_event, self_event_size);
    }
214

215
216
217
218
219
    //print_base(m);
    tw_event_send(e);
}
static void model_net_event_impl_base_rc(tw_lp *sender){
    codes_local_latency_reverse(sender);
220
}
221
222
223
224
225
226
227
228
229
230
231
232
233

void model_net_event(
    int net_id,
    char* category, 
    tw_lpid final_dest_lp, 
    uint64_t message_size, 
    tw_stime offset,
    int remote_event_size,
    const void* remote_event,
    int self_event_size,
    const void* self_event,
    tw_lp *sender)
{
234
235
236
    model_net_event_impl_base(net_id, category, final_dest_lp, message_size,
            0, offset, remote_event_size, remote_event, self_event_size,
            self_event, sender);
237
238
239
240
241
242
243
244
245
246
247
248
249
}

void model_net_pull_event(
        int net_id,
        char *category,
        tw_lpid final_dest_lp,
        uint64_t message_size,
        tw_stime offset,
        int self_event_size,
        const void *self_event,
        tw_lp *sender){
    /* NOTE: for a pull, we are filling the *remote* event - it will be remote
     * from the destination's POV */
250
251
    model_net_event_impl_base(net_id, category, final_dest_lp, message_size,
            1, offset, self_event_size, self_event, 0, NULL, sender);
252
253
}

254
int* model_net_set_params(int *id_count)
255
{
256
  char sched[MAX_NAME_LENGTH];
257
258
  long int packet_size_l = 0;
  uint64_t packet_size;
259
  int ret;
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  config_lpgroups_t lpconf;

  // TODO: currently just hard-coding the name determination, should probably
  // refactor to do this elsewhere (in codes-base?)
  int do_config_nets[MAX_NETS];
  memset(do_config_nets, 0, MAX_NETS*sizeof(*do_config_nets));
  // TODO: inefficient (codes_mapping opens up the same section), but at least
  // this avoids the need to call codes_mapping_setup first
  configuration_get_lpgroups(&config, "LPGROUPS", &lpconf);
  for (int grp = 0; grp < lpconf.lpgroups_count; grp++){
      config_lpgroup_t *lpgroup = &lpconf.lpgroups[grp];
      for (int lpt = 0; lpt < lpgroup->lptypes_count; lpt++){
          char *nm = lpgroup->lptypes[lpt].name;
          for (int n = 0; n < MAX_NETS; n++){
              if (strcmp(model_net_lp_config_names[n], nm) == 0){
                  do_config_nets[n] = 1;
                  break;
              }
          }
      }
  }
281

282
283
  ret = configuration_get_value(&config, "PARAMS", "modelnet_scheduler", NULL,
          sched, MAX_NAME_LENGTH);
284

285
286
  configuration_get_value_longint(&config, "PARAMS", "packet_size", NULL,
          &packet_size_l);
287
  packet_size = packet_size_l;
288

289
    if (ret > 0){
290
291
292
293
294
295
        int i;
        for (i = 0; i < MAX_SCHEDS; i++){
            if (strcmp(sched_names[i], sched) == 0){
                mn_sched_type = i;
                break;
            }
296
        }
297
298
299
        if (i == MAX_SCHEDS){
            fprintf(stderr, 
                    "Unknown value for PARAMS:modelnet-scheduler : %s\n", 
300
301
302
303
304
305
306
307
308
                    sched);
            abort();
        }
    }
    else{
        // default: FCFS
        mn_sched_type = MN_SCHED_FCFS;
    }

309
310
311
312
313
314
315
316
    if (mn_sched_type == 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 && mn_sched_type != MN_SCHED_FCFS_FULL)
    {
        packet_size = 512;
317
        fprintf(stderr, "\n Warning, no packet size specified, setting packet size to %llu\n", packet_size);
318
319
    }

320
  if(do_config_nets[SIMPLENET])
321
322
323
324
   {
     double net_startup_ns, net_bw_mbps;
     simplenet_param net_params;
     
325
326
327
328
     configuration_get_value_double(&config, "PARAMS", "net_startup_ns", NULL,
             &net_startup_ns);
     configuration_get_value_double(&config, "PARAMS", "net_bw_mbps", NULL,
             &net_bw_mbps);
329
330
     net_params.net_startup_ns = net_startup_ns;
     net_params.net_bw_mbps =  net_bw_mbps;
331
     model_net_setup(model_net_method_names[SIMPLENET], packet_size, (const void*)&net_params); /* Sets the network as simplenet and packet size 512 */
332
   }
333
  if (do_config_nets[SIMPLEWAN]){
334
    simplewan_param net_params;
335
336
    configuration_get_value_relpath(&config, "PARAMS", "net_startup_ns_file", NULL, net_params.startup_filename, MAX_NAME_LENGTH);
    configuration_get_value_relpath(&config, "PARAMS", "net_bw_mbps_file", NULL, net_params.bw_filename, MAX_NAME_LENGTH);
337
    model_net_setup(model_net_method_names[SIMPLEWAN], packet_size, (const void*)&net_params);
338
  }
339
   if(do_config_nets[LOGGP])
Philip Carns's avatar
Philip Carns committed
340
341
342
343
   {
     char net_config_file[256];
     loggp_param net_params;
     
344
     configuration_get_value_relpath(&config, "PARAMS", "net_config_file", NULL, net_config_file, 256);
Philip Carns's avatar
Philip Carns committed
345
     net_params.net_config_file = net_config_file;
346
     model_net_setup(model_net_method_names[LOGGP], packet_size, (const void*)&net_params); /* Sets the network as loggp and packet size 512 */
Philip Carns's avatar
Philip Carns committed
347
348
   }

349
  if(do_config_nets[DRAGONFLY])	  
350
    {
351
       dragonfly_param net_params;
352
       int num_routers=0, num_vcs=0, local_vc_size=0, global_vc_size=0, cn_vc_size=0, chunk_size=0;
353
354
       double local_bandwidth=0.0, cn_bandwidth=0.0, global_bandwidth=0.0;
       
355
       configuration_get_value_int(&config, "PARAMS", "num_routers", NULL, &num_routers);
356
357
358
359
360
361
362
       if(!num_routers)
	{
	   num_routers = 4; 
	   printf("\n Number of dimensions not specified, setting to %d ", num_routers);
        } 
       net_params.num_routers = num_routers; 

363
       configuration_get_value_int(&config, "PARAMS", "num_vcs", NULL, &num_vcs);
364
365
366
367
368
369
370
       if(!num_vcs)
       {
          num_vcs = 1;
	  printf("\n Number of virtual channels not specified, setting to %d ", num_vcs);
       }
       net_params.num_vcs = num_vcs;

371
       configuration_get_value_int(&config, "PARAMS", "local_vc_size", NULL, &local_vc_size);
372
373
374
375
376
377
378
       if(!local_vc_size)
	{
	   local_vc_size = 1024;
	   printf("\n Buffer size of local channels not specified, setting to %d ", local_vc_size);
	}
       net_params.local_vc_size = local_vc_size;

379
       configuration_get_value_int(&config, "PARAMS", "global_vc_size", NULL, &global_vc_size);
380
381
382
383
384
385
386
       if(!global_vc_size)
	{
	  global_vc_size = 2048;
	  printf("\n Buffer size of global channels not specified, setting to %d ", global_vc_size);
	}
       net_params.global_vc_size = global_vc_size;

387
       configuration_get_value_int(&config, "PARAMS", "cn_vc_size", NULL, &cn_vc_size);
388
389
390
391
392
393
394
       if(!cn_vc_size)
	 {
	    cn_vc_size = 1024;
	    printf("\n Buffer size of compute node channels not specified, setting to %d ", cn_vc_size);
	 }
       net_params.cn_vc_size = cn_vc_size;

395
	configuration_get_value_int(&config, "PARAMS", "chunk_size", NULL, &chunk_size);
396
397
398
399
400
401
402
	if(!chunk_size)
	  {
		chunk_size = 64;
		printf("\n Chunk size for packets is specified, setting to %d ", chunk_size);
	  }
	net_params.chunk_size = chunk_size;

403
	configuration_get_value_double(&config, "PARAMS", "local_bandwidth", NULL, &local_bandwidth);
404
405
406
407
408
409
410
        if(!local_bandwidth)
	  {
	    local_bandwidth = 5.25;
	    printf("\n Bandwidth of local channels not specified, setting to %lf ", local_bandwidth);
	 }
       net_params.local_bandwidth = local_bandwidth;

411
       configuration_get_value_double(&config, "PARAMS", "global_bandwidth", NULL, &global_bandwidth);
412
413
414
415
416
417
418
        if(!global_bandwidth)
	{
	     global_bandwidth = 4.7;
	     printf("\n Bandwidth of global channels not specified, setting to %lf ", global_bandwidth);
	}
	net_params.global_bandwidth = global_bandwidth;

419
	configuration_get_value_double(&config, "PARAMS", "cn_bandwidth", NULL, &cn_bandwidth);
420
421
422
423
424
425
426
	if(!cn_bandwidth)
	 {
	     cn_bandwidth = 5.25;
	     printf("\n Bandwidth of compute node channels not specified, setting to %lf ", cn_bandwidth);
	}
	net_params.cn_bandwidth = cn_bandwidth;

427
	
428
       char routing[MAX_NAME_LENGTH];
429
       configuration_get_value(&config, "PARAMS", "routing", NULL, routing, MAX_NAME_LENGTH);
430
431
432
433
       if(strcmp(routing, "minimal") == 0)
	   net_params.routing = 0;
       else if(strcmp(routing, "nonminimal")==0 || strcmp(routing,"non-minimal")==0)
	       net_params.routing = 1;
434
435
	else if (strcmp(routing, "adaptive") == 0)
		net_params.routing = 2;
436
437
438
439
440
       else
       {
       	   printf("\n No routing protocol specified, setting to minimal routing");
   	   net_params.routing = 0;	   
       }
441
    model_net_setup(model_net_method_names[DRAGONFLY], packet_size, (const void*)&net_params);   
442
    }
443
   if(do_config_nets[TORUS])
444
     {
445
446
	torus_param net_params;
	char dim_length[MAX_NAME_LENGTH];
447
	int n_dims=0, buffer_size=0, num_vc=0, i=0, chunk_size = 0;
448
449
	double link_bandwidth=0;

450
	configuration_get_value_int(&config, "PARAMS", "n_dims", NULL, &n_dims);
451
452
453
454
455
456
	if(!n_dims)
	{
	   n_dims = 4; /* a 4-D torus */
	   printf("\n Number of dimensions not specified, setting to %d ", n_dims);
	}
	
457
	configuration_get_value_double(&config, "PARAMS", "link_bandwidth", NULL, &link_bandwidth);	
458
459
460
461
462
463
	if(!link_bandwidth)
	{
		link_bandwidth = 2.0; /*default bg/q configuration */
		printf("\n Link bandwidth not specified, setting to %lf ", link_bandwidth);
	}

464
	configuration_get_value_int(&config, "PARAMS", "buffer_size", NULL, &buffer_size);
465
466
467
468
469
470
	if(!buffer_size)
	{
		buffer_size = 2048;
		printf("\n Buffer size not specified, setting to %d ",buffer_size);
	}

471
	configuration_get_value_int(&config, "PARAMS", "chunk_size", NULL, &chunk_size);
472
473
474
475
476
	if(!chunk_size)
	{
	       chunk_size = 32;
	       printf("\n Chunk size not specified, setting to %d ", chunk_size);
	}
477
	configuration_get_value_int(&config, "PARAMS", "num_vc", NULL, &num_vc);
478
479
480
481
482
483
	if(!num_vc)
	{
		num_vc = 1; /*by default, we have one for taking packets, another for taking credit*/
		printf("\n num_vc not specified, setting to %d ", num_vc);
	}

484
        configuration_get_value(&config, "PARAMS", "dim_length", NULL, dim_length, MAX_NAME_LENGTH);
485
486
487
488
        char* token;
	net_params.n_dims=n_dims;
	net_params.num_vc=num_vc;
	net_params.buffer_size=buffer_size;
489
	net_params.chunk_size = chunk_size;
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
	net_params.link_bandwidth=link_bandwidth;
	net_params.dim_length=malloc(n_dims*sizeof(int));
        token = strtok(dim_length, ",");	
	while(token != NULL)
	{
	   sscanf(token, "%d", &net_params.dim_length[i]);
	   if(!net_params.dim_length[i])
	   {
	      printf("\n Invalid torus dimension specified %d, exitting... ", net_params.dim_length[i]);
	      MPI_Finalize();
	      exit(-1);
	   }
	   i++;
	   token = strtok(NULL,",");
	}
505
	model_net_setup(model_net_method_names[TORUS], packet_size, (const void*)&net_params);
506
     }
507
508
509
510
511
512
513
514
515
516
517
518
519
520

  // now that the LP-specific nets are set up...
  // - get the number of nets used
  *id_count = 0;
  for (int i = 0; i < MAX_NETS; i++){
      if (do_config_nets[i]){
          (*id_count)++;
      }
  }
  // - allocate the output
  int *ids = malloc(*id_count * sizeof(int));
  // - read the ordering provided by modelnet_order
  char **values;
  size_t length;
521
  ret = configuration_get_multivalue(&config, "PARAMS", "modelnet_order", NULL, &values, &length);
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
  if (ret != 1){
      fprintf(stderr, "unable to read PARAMS:modelnet_order variable\n");
      abort();
  }
  if (length != (size_t) *id_count){
      fprintf(stderr, "number of networks in PARAMS:modelnet_order "
              "do not match number in LPGROUPS\n");
      abort();
  }
  // - set the index
  for (int i = 0; i < *id_count; i++){
      ids[i] = -1;
      for (int n = 0; n < MAX_NETS; n++){
          if (strcmp(values[i], model_net_method_names[n]) == 0){
              if (!do_config_nets[n]){
                  fprintf(stderr, "network in PARAMS:modelnet_order not "
                          "present in LPGROUPS: %s\n", values[i]);
                  abort();
              }
              ids[i] = n;
              break;
          }
      }
      if (ids[i] == -1){
          fprintf(stderr, "unknown network in PARAMS:modelnet_order: %s\n",
                  values[i]);
          abort();
      }
      free(values[i]);
  }
  free(values);
  // - pass along to model_net_base_init
  model_net_base_init(*id_count, ids);
  // - done
  return ids;
557
}
558

559
560
561
562
void model_net_event_rc(
        int net_id,
        tw_lp *sender,
        uint64_t message_size){
563
    model_net_event_impl_base_rc(sender);
564
565
566
567
568
}

void model_net_pull_event_rc(
        int net_id,
        tw_lp *sender) {
569
    model_net_event_impl_base_rc(sender);
570
571
}

572
/* returns the message size, can be either simplenet, dragonfly or torus message size*/
573
int model_net_get_msg_sz(int net_id)
574
575
576
{
   // TODO: Add checks on network name
   // TODO: Add dragonfly and torus network models
577
578
   return sizeof(model_net_wrap_msg);
#if 0
579
   if(net_id < 0 || net_id >= MAX_NETS)
580
581
582
583
584
585
     {
      printf("%s Error: Uninitializied modelnet network, call modelnet_init first\n", __FUNCTION__);
      exit(-1);
     }

       return method_array[net_id]->mn_get_msg_sz();
586
#endif
587
588
589
}

/* returns the packet size in the modelnet struct */
590
uint64_t model_net_get_packet_size(int net_id)
591
{
592
  if(net_id < 0 || net_id >= MAX_NETS)
593
594
595
596
597
598
599
     {
       fprintf(stderr, "%s Error: Uninitializied modelnet network, call modelnet_init first\n", __FUNCTION__);
       exit(-1);
     }
  return method_array[net_id]->packet_size; // TODO: where to set the packet size?
}

600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
/* This event does a collective operation call for model-net */
void model_net_event_collective(int net_id, char* category, int message_size, int remote_event_size, const void* remote_event, tw_lp* sender)
{
  if(net_id < 0 || net_id > MAX_NETS)
     {
       fprintf(stderr, "%s Error: Uninitializied modelnet network, call modelnet_init first\n", __FUNCTION__);
       exit(-1);
     }
  return method_array[net_id]->mn_collective_call(category, message_size, remote_event_size, remote_event, sender);
}

/* reverse event of the collective operation call */
void model_net_event_collective_rc(int net_id, int message_size, tw_lp* sender)
{
  if(net_id < 0 || net_id > MAX_NETS)
     {
       fprintf(stderr, "%s Error: Uninitializied modelnet network, call modelnet_init first\n", __FUNCTION__);
       exit(-1);
     }
  return method_array[net_id]->mn_collective_call_rc(message_size, sender);
}

622
623
624
/* returns lp type for modelnet */
const tw_lptype* model_net_get_lp_type(int net_id)
{
625
    if(net_id < 0 || net_id >= MAX_NETS)
626
627
628
629
630
631
632
633
634
635
     {
       fprintf(stderr, "%s Error: Uninitializied modelnet network, call modelnet_init first\n", __FUNCTION__);
       exit(-1);
     }

   // TODO: ADd checks by network names
   // Add dragonfly and torus network models
   return method_array[net_id]->mn_get_lp_type();
}

636
637
void model_net_report_stats(int net_id)
{
638
  if(net_id < 0 || net_id >= MAX_NETS)
639
640
641
642
643
644
645
  {
    fprintf(stderr, "%s Error: Uninitializied modelnet network, call modelnet_init first\n", __FUNCTION__);
    exit(-1);
   }

     // TODO: ADd checks by network names
     //    // Add dragonfly and torus network models
646
647
   method_array[net_id]->mn_report_stats();
   return;
648
}
649
650
651
652
653
654

tw_lpid model_net_find_local_device(int net_id, tw_lp *sender)
{
    return(method_array[net_id]->model_net_method_find_local_device(sender));
}

655
656
657
658
659
660
661
662
/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 * End:
 *
 * vim: ft=c ts=8 sts=4 sw=4 expandtab
 */