model-net-lp.c 22.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*
 * Copyright (C) 2014 University of Chicago.
 * See COPYRIGHT notice in top-level directory.
 *
 */

#include <stddef.h>
#include <assert.h>
#include "codes/model-net.h"
#include "codes/model-net-method.h"
#include "codes/model-net-lp.h"
12
#include "codes/model-net-sched.h"
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "codes/codes_mapping.h"
#include "codes/jenkins-hash.h"

#define MN_NAME "model_net_base"

/**** BEGIN SIMULATION DATA STRUCTURES ****/

int model_net_base_magic;

// message-type specific offsets - don't want to get bitten later by alignment
// issues...
static int msg_offsets[MAX_NETS];

26
27
typedef struct model_net_base_params_s {
    model_net_sched_cfg_params sched_params;
28
    uint64_t packet_size;
29
    int use_recv_queue;
30
31
} model_net_base_params;

32
/* annotation-specific parameters (unannotated entry occurs at the
33
34
35
36
37
 * last index) */
static int                       num_params = 0;
static const char              * annos[CONFIGURATION_MAX_ANNOS];
static model_net_base_params     all_params[CONFIGURATION_MAX_ANNOS];

38
39
static tw_stime mn_sample_interval = 0.0;
static int mn_sample_enabled = 0;
40
static tw_stime mn_sample_end = 0.0;
41

42
43
typedef struct model_net_base_state {
    int net_id;
44
    // whether scheduler loop is running
45
    int in_sched_send_loop, in_sched_recv_loop;
46
47
48
    // unique message id counter. This doesn't get decremented on RC to prevent
    // optimistic orderings using "stale" ids
    uint64_t msg_id;
49
50
    // model-net schedulers
    model_net_sched *sched_send, *sched_recv;
51
52
    // parameters
    const model_net_base_params * params;
53
54
55
56
57
58
    // lp type and state of underlying model net method - cache here so we
    // don't have to constantly look up
    const tw_lptype *sub_type;
    void *sub_state;
} model_net_base_state;

59

60
61
62
63
/**** END SIMULATION DATA STRUCTURES ****/

/**** BEGIN LP, EVENT PROCESSING FUNCTION DECLS ****/

64
/* ROSS LP processing functions */
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
static void model_net_base_lp_init(
        model_net_base_state * ns,
        tw_lp * lp);
static void model_net_base_event(
        model_net_base_state * ns,
        tw_bf * b,
        model_net_wrap_msg * m,
        tw_lp * lp);
static void model_net_base_event_rc(
        model_net_base_state * ns,
        tw_bf * b,
        model_net_wrap_msg * m,
        tw_lp * lp);
static void model_net_base_finalize(
        model_net_base_state * ns,
        tw_lp * lp);

/* event type handlers */
static void handle_new_msg(
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp);
static void handle_sched_next(
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp);
static void handle_new_msg_rc(
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp);
static void handle_sched_next_rc(
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp);

/* ROSS function pointer table for this LP */
tw_lptype model_net_base_lp = {
106
107
108
109
    (init_f) model_net_base_lp_init,
    (pre_run_f) NULL,
    (event_f) model_net_base_event,
    (revent_f) model_net_base_event_rc,
110
111
    (commit_f) NULL,
    (final_f)  model_net_base_finalize,
112
113
    (map_f) codes_mapping,
    sizeof(model_net_base_state),
114
115
};

116
117
118
119
/* setup for the ROSS event tracing
 * can have a different function for  rbev_trace_f and ev_trace_f
 * but right now it is set to the same function for both
 */
120
121
122
123
124
125
void mn_event_collect(model_net_wrap_msg *m, tw_lp *lp, char *buffer)
{
    int type = (int) m->h.event_type;
    memcpy(buffer, &type, sizeof(type));
}

126
127
st_trace_type mn_trace_types = {
    (rbev_trace_f) mn_event_collect,
128
     sizeof(int),
129
     (ev_trace_f) mn_event_collect,
130
131
132
     sizeof(int),
};

133
134
135
136
/**** END LP, EVENT PROCESSING FUNCTION DECLS ****/

/**** BEGIN IMPLEMENTATIONS ****/

137
void model_net_enable_sampling(tw_stime interval, tw_stime end)
138
139
{
    mn_sample_interval = interval;
140
    mn_sample_end = end;
141
142
143
144
145
146
147
148
149
150
151
    mn_sample_enabled = 1;
}

int model_net_sampling_enabled(void)
{
    return mn_sample_enabled;
}

// schedule sample event - want to be precise, so no noise here
static void issue_sample_event(tw_lp *lp)
{
152
153
154
155
156
157
    if (tw_now(lp) + mn_sample_interval < mn_sample_end + 0.0001) {
        tw_event *e = tw_event_new(lp->gid, mn_sample_interval, lp);
        model_net_wrap_msg *m = tw_event_data(e);
        msg_set_header(model_net_base_magic, MN_BASE_SAMPLE, lp->gid, &m->h);
        tw_event_send(e);
    }
158
159
}

160
161
162
163
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]){
164
165
166
167
168
169
170
            // some model-net lps need custom registration hooks (dragonfly).
            // Those that don't NULL out the reg. function
            if (method_array[i]->mn_register == NULL)
                lp_type_register(model_net_lp_config_names[i],
                        &model_net_base_lp);
            else
                method_array[i]->mn_register(&model_net_base_lp);
171
            if (g_st_ev_trace) // for ROSS event tracing
172
            {
173
174
                if (method_array[i]->mn_trace_register == NULL)
                    trace_type_register(model_net_lp_config_names[i], &mn_trace_types);
175
                else
176
                    method_array[i]->mn_trace_register(&mn_trace_types);
177
            }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
        }
    }
}

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;

    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){
198
                p->sched_params.type = i;
199
200
201
202
203
                break;
            }
        }
        if (i == MAX_SCHEDS){
            tw_error(TW_LOC,"Unknown value for PARAMS:modelnet-scheduler : "
204
                    "%s", sched);
205
206
207
208
        }
    }
    else{
        // default: FCFS
209
        p->sched_params.type = MN_SCHED_FCFS;
210
211
    }

212
213
    // get scheduler-specific parameters
    if (p->sched_params.type == MN_SCHED_PRIO){
214
        // prio scheduler uses default parameters
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
        int             * num_prios = &p->sched_params.u.prio.num_prios;
        enum sched_type * sub_stype = &p->sched_params.u.prio.sub_stype;
        // number of priorities to allocate
        ret = configuration_get_value_int(&config, "PARAMS",
                "prio-sched-num-prios", anno, num_prios);
        if (ret != 0)
            *num_prios = 10;

        ret = configuration_get_value(&config, "PARAMS",
                "prio-sched-sub-sched", anno, sched, MAX_NAME_LENGTH);
        if (ret == 0)
            *sub_stype = MN_SCHED_FCFS;
        else{
            int i;
            for (i = 0; i < MAX_SCHEDS; i++){
                if (strcmp(sched_names[i], sched) == 0){
                    *sub_stype = i;
                    break;
                }
            }
            if (i == MAX_SCHEDS){
                tw_error(TW_LOC, "Unknown value for "
                        "PARAMS:prio-sched-sub-sched %s", sched);
            }
            else if (i == MN_SCHED_PRIO){
                tw_error(TW_LOC, "priority scheduler cannot be used as a "
                        "priority scheduler's sub sched "
                        "(PARAMS:prio-sched-sub-sched)");
            }
        }
245
246
    }

247
248
249
250
251
252
253
254
255
256
257
258
259
    if (p->sched_params.type == MN_SCHED_FCFS_FULL ||
            (p->sched_params.type == MN_SCHED_PRIO &&
             p->sched_params.u.prio.sub_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->sched_params.type != MN_SCHED_FCFS_FULL ||
             (p->sched_params.type == MN_SCHED_PRIO &&
              p->sched_params.u.prio.sub_stype != MN_SCHED_FCFS_FULL))){
        packet_size = 512;
        fprintf(stderr, "WARNING, no packet size specified, setting packet "
Jonathan Jenkins's avatar
Jonathan Jenkins committed
260
                "size to %llu\n", LLU(packet_size));
261
262
263
    }


264
265
266
267
    p->packet_size = packet_size;
}

void model_net_base_configure(){
268
269
270
271
272
    uint32_t h1=0, h2=0;

    bj_hashlittle2(MN_NAME, strlen(MN_NAME), &h1, &h2);
    model_net_base_magic = h1+h2;

273
274
275
    // set up offsets - doesn't matter if they are actually used or not
    msg_offsets[SIMPLENET] =
        offsetof(model_net_wrap_msg, msg.m_snet);
Jonathan Jenkins's avatar
Jonathan Jenkins committed
276
277
    msg_offsets[SIMPLEP2P] =
        offsetof(model_net_wrap_msg, msg.m_sp2p);
278
279
280
281
    msg_offsets[TORUS] =
        offsetof(model_net_wrap_msg, msg.m_torus);
    msg_offsets[DRAGONFLY] =
        offsetof(model_net_wrap_msg, msg.m_dfly);
282
283
284
    // note: dragonfly router uses the same event struct
    msg_offsets[DRAGONFLY_ROUTER] =
        offsetof(model_net_wrap_msg, msg.m_dfly);
285
286
287
288
    msg_offsets[DRAGONFLY_CUSTOM] =
        offsetof(model_net_wrap_msg, msg.m_dfly);
    msg_offsets[DRAGONFLY_CUSTOM_ROUTER] =
        offsetof(model_net_wrap_msg, msg.m_dfly);
289
290
    msg_offsets[SLIMFLY] =
        offsetof(model_net_wrap_msg, msg.m_slim);
291
292
    msg_offsets[FATTREE] =
	offsetof(model_net_wrap_msg, msg.m_fat);
293
294
    msg_offsets[LOGGP] =
        offsetof(model_net_wrap_msg, msg.m_loggp);
295

296
297
298
299
300
301
302
303
304
305
    // 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];
306
        if (strncmp("modelnet_", amap->lp_name.ptr, 9) == 0){
307
308
309
            for (int n = 0; n < amap->num_annos; n++){
                int a;
                for (a = 0; a < num_params; a++){
310
311
                    if (annos[a] != NULL && amap->annotations[n].ptr != NULL &&
                            strcmp(amap->annotations[n].ptr, annos[a]) == 0){
312
313
314
315
316
                        break;
                    }
                }
                if (a == num_params){
                    // found a new annotation
317
                    annos[num_params++] = amap->annotations[n].ptr;
318
319
320
321
322
323
324
325
326
327
328
329
330
                }
            }
            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;
                }
            }
331
332
        }
    }
333
334
335
336
337
338

    // now that we have all of the annos for all of the networks, loop through
    // and read the configs
    for (int i = 0; i < num_params; i++){
        base_read_config(annos[i], &all_params[i]);
    }
339
340
341
342
343
344
}

void model_net_base_lp_init(
        model_net_base_state * ns,
        tw_lp * lp){
    // obtain the underlying lp type through codes-mapping
345
    char lp_type_name[MAX_NAME_LENGTH], anno[MAX_NAME_LENGTH];
346
347
    int dummy;

348
    codes_mapping_get_lp_info(lp->gid, NULL, &dummy,
349
350
            lp_type_name, &dummy, anno, &dummy, &dummy);

351
352
    ns->msg_id = 0;

353
354
355
356
357
358
359
360
    // get annotation-specific parameters
    for (int i = 0; i < num_params; i++){
        if ((anno[0]=='\0' && annos[i] == NULL) ||
                strcmp(anno, annos[i]) == 0){
            ns->params = &all_params[i];
            break;
        }
    }
361
362
363
364
365
366
367
368
369

    // find the corresponding method name / index
    for (int i = 0; i < MAX_NETS; i++){
        if (strcmp(model_net_lp_config_names[i], lp_type_name) == 0){
            ns->net_id = i;
            break;
        }
    }

370
371
    ns->sched_send = malloc(sizeof(model_net_sched));
    ns->sched_recv = malloc(sizeof(model_net_sched));
372
    // init both the sender queue and the 'receiver' queue
373
374
375
376
    model_net_sched_init(&ns->params->sched_params, 0, method_array[ns->net_id],
            ns->sched_send);
    model_net_sched_init(&ns->params->sched_params, 1, method_array[ns->net_id],
            ns->sched_recv);
377

378
379
380
381
382
383
384
    ns->sub_type = model_net_get_lp_type(ns->net_id);
    // NOTE: some models actually expect LP state to be 0 initialized...
    // *cough anything that uses mn_stats_array cough*
    ns->sub_state = calloc(1, ns->sub_type->state_sz);

    // initialize the model-net method
    ns->sub_type->init(ns->sub_state, lp);
385
386
387
388
389
390

    // check validity of sampling function
    event_f  sample  = method_array[ns->net_id]->mn_sample_fn;
    revent_f rsample = method_array[ns->net_id]->mn_sample_rc_fn;
    if (model_net_sampling_enabled()) {
        if (sample == NULL) {
391
392
393
            /* MM: Commented out temporarily--- */
            //tw_error(TW_LOC,
            //        "Sampling requested for a model that doesn't provide it\n");
394
395
396
397
        }
        else if (rsample == NULL &&
                (g_tw_synchronization_protocol == OPTIMISTIC ||
                 g_tw_synchronization_protocol == OPTIMISTIC_DEBUG)) {
398
399
400
            /* MM: Commented out temporarily--- */
            //tw_error(TW_LOC,
            //        "Sampling requested for a model that doesn't provide it\n");
401
402
403
404
405
406
407
408
        }
        else {
            init_f sinit = method_array[ns->net_id]->mn_sample_init_fn;
            if (sinit != NULL)
                sinit(ns->sub_state, lp);
            issue_sample_event(lp);
        }
    }
409
410
411
412
413
414
415
}

void model_net_base_event(
        model_net_base_state * ns,
        tw_bf * b,
        model_net_wrap_msg * m,
        tw_lp * lp){
416
417
418
419

    if(m->h.magic != model_net_base_magic)
        printf("\n LP ID mismatched %d ", lp->gid);

420
    assert(m->h.magic == model_net_base_magic);
421
422

    void * sub_msg;
423
    switch (m->h.event_type){
424
425
426
427
428
429
        case MN_BASE_NEW_MSG:
            handle_new_msg(ns, b, m, lp);
            break;
        case MN_BASE_SCHED_NEXT:
            handle_sched_next(ns, b, m, lp);
            break;
430
431
432
433
434
435
436
        case MN_BASE_SAMPLE: ;
            event_f sample = method_array[ns->net_id]->mn_sample_fn;
            assert(model_net_sampling_enabled() && sample != NULL);
            sub_msg = ((char*)m)+msg_offsets[ns->net_id];
            sample(ns->sub_state, b, sub_msg, lp);
            issue_sample_event(lp);
            break;
437
        case MN_BASE_PASS: ;
438
            sub_msg = ((char*)m)+msg_offsets[ns->net_id];
439
440
441
442
443
444
445
446
447
448
449
450
451
452
            ns->sub_type->event(ns->sub_state, b, sub_msg, lp);
            break;
        /* ... */
        default:
            assert(!"model_net_base event type not known");
            break;
    }
}

void model_net_base_event_rc(
        model_net_base_state * ns,
        tw_bf * b,
        model_net_wrap_msg * m,
        tw_lp * lp){
453
    assert(m->h.magic == model_net_base_magic);
454
455

    void * sub_msg;
456
    switch (m->h.event_type){
457
458
459
460
461
462
        case MN_BASE_NEW_MSG:
            handle_new_msg_rc(ns, b, m, lp);
            break;
        case MN_BASE_SCHED_NEXT:
            handle_sched_next_rc(ns, b, m, lp);
            break;
463
464
465
466
467
468
        case MN_BASE_SAMPLE: ;
            revent_f sample_rc = method_array[ns->net_id]->mn_sample_rc_fn;
            assert(model_net_sampling_enabled() && sample_rc != NULL);
            sub_msg = ((char*)m)+msg_offsets[ns->net_id];
            sample_rc(ns->sub_state, b, sub_msg, lp);
            break;
469
        case MN_BASE_PASS: ;
470
            sub_msg = ((char*)m)+msg_offsets[ns->net_id];
471
472
473
474
475
476
477
478
479
480
481
482
            ns->sub_type->revent(ns->sub_state, b, sub_msg, lp);
            break;
        /* ... */
        default:
            assert(!"model_net_base event type not known");
            break;
    }
}

void model_net_base_finalize(
        model_net_base_state * ns,
        tw_lp * lp){
483
484
485
    final_f sfini = method_array[ns->net_id]->mn_sample_fini_fn;
    if (sfini != NULL)
        sfini(ns->sub_state, lp);
486
487
488
489
    ns->sub_type->final(ns->sub_state, lp);
    free(ns->sub_state);
}

490
/// bitfields used:
491
/// c31 - we initiated a sched_next event
492
493
494
495
496
void handle_new_msg(
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp){
497
    // simply pass down to the scheduler
498
    model_net_request *r = &m->msg.m_base.req;
499
500
    // don't forget to set packet size, now that we're responsible for it!
    r->packet_size = ns->params->packet_size;
501
    r->msg_id = ns->msg_id++;
502
503
    void * m_data = m+1;
    void *remote = NULL, *local = NULL;
504
    if (r->remote_event_size > 0){
505
506
        remote = m_data;
        m_data = (char*)m_data + r->remote_event_size;
507
508
    }
    if (r->self_event_size > 0){
509
        local = m_data;
510
    }
511

512
    // set message-specific params
513
514
    int is_from_remote = m->msg.m_base.is_from_remote;
    model_net_sched *ss = is_from_remote ? ns->sched_recv : ns->sched_send;
515
    int *in_sched_loop = is_from_remote  ?
516
517
518
        &ns->in_sched_recv_loop : &ns->in_sched_send_loop;
    model_net_sched_add(r, &m->msg.m_base.sched_params, r->remote_event_size,
            remote, r->self_event_size, local, ss, &m->msg.m_base.rc, lp);
519

520
    if (*in_sched_loop == 0){
521
522
        b->c31 = 1;
        /* No need to issue an extra sched-next event if we're currently idle */
523
        *in_sched_loop = 1;
524
525
526
527
528
        /* NOTE: we can do this because the sched rc struct in the event is
         * *very* lightly used (there's harmless overlap in usage for the
         * priority scheduler) */
        handle_sched_next(ns, b, m, lp);
        assert(*in_sched_loop); // we shouldn't have fallen out of the loop
529
530
    }
}
531
532
533

void handle_new_msg_rc(
        model_net_base_state *ns,
534
        tw_bf *b,
535
536
        model_net_wrap_msg *m,
        tw_lp *lp){
537
538
    int is_from_remote = m->msg.m_base.is_from_remote;
    model_net_sched *ss = is_from_remote ? ns->sched_recv : ns->sched_send;
539
    int *in_sched_loop = is_from_remote  ?
540
541
        &ns->in_sched_recv_loop : &ns->in_sched_send_loop;

542
543
    if (b->c31) {
        handle_sched_next_rc(ns, b, m, lp);
544
        *in_sched_loop = 0;
545
    }
546
    model_net_sched_add_rc(ss, &m->msg.m_base.rc, lp);
547
}
548
549
550
551

/// bitfields used
/// c0 - scheduler loop is finished
void handle_sched_next(
552
553
554
555
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp){
556
    tw_stime poffset;
557
558
559
560
561
    int is_from_remote = m->msg.m_base.is_from_remote;
    model_net_sched * ss = is_from_remote ? ns->sched_recv : ns->sched_send;
    int *in_sched_loop = is_from_remote ?
        &ns->in_sched_recv_loop : &ns->in_sched_send_loop;
    int ret = model_net_sched_next(&poffset, ss, m+1, &m->msg.m_base.rc, lp);
562
563
564
565
    // we only need to know whether scheduling is finished or not - if not,
    // go to the 'next iteration' of the loop
    if (ret == -1){
        b->c0 = 1;
566
        *in_sched_loop = 0;
567
    }
568
569
570
    // Currently, only a subset of the network implementations use the
    // callback-based scheduling loop (model_net_method_idle_event).
    // For all others, we need to schedule the next packet
571
    // immediately
Jonathan Jenkins's avatar
Jonathan Jenkins committed
572
    else if (ns->net_id == SIMPLEP2P || ns->net_id == TORUS){
573
        tw_event *e = tw_event_new(lp->gid,
574
                poffset+codes_local_latency(lp), lp);
575
        model_net_wrap_msg *m_wrap = tw_event_data(e);
576
        msg_set_header(model_net_base_magic, MN_BASE_SCHED_NEXT, lp->gid,
577
578
                &m_wrap->h);
        m_wrap->msg.m_base.is_from_remote = is_from_remote;
579
580
        // no need to set m_base here
        tw_event_send(e);
581
582
    }
}
583

584
585
586
587
588
void handle_sched_next_rc(
        model_net_base_state * ns,
        tw_bf *b,
        model_net_wrap_msg * m,
        tw_lp * lp){
589
590
591
592
    int is_from_remote = m->msg.m_base.is_from_remote;
    model_net_sched * ss = is_from_remote ? ns->sched_recv : ns->sched_send;
    int *in_sched_loop = is_from_remote ?
        &ns->in_sched_recv_loop : &ns->in_sched_send_loop;
593

594
    model_net_sched_next_rc(ss, m+1, &m->msg.m_base.rc, lp);
595
    if (b->c0){
596
        *in_sched_loop = 1;
597
    }
Jonathan Jenkins's avatar
Jonathan Jenkins committed
598
    else if (ns->net_id == SIMPLEP2P || ns->net_id == TORUS){
599
600
        codes_local_latency_reverse(lp);
    }
601
602
603
604
605
606
607
608
609
610
611
612
613
}

/**** END IMPLEMENTATIONS ****/

tw_event * model_net_method_event_new(
        tw_lpid dest_gid,
        tw_stime offset_ts,
        tw_lp *sender,
        int net_id,
        void **msg_data,
        void **extra_data){
    tw_event *e = tw_event_new(dest_gid, offset_ts, sender);
    model_net_wrap_msg *m_wrap = tw_event_data(e);
614
615
    msg_set_header(model_net_base_magic, MN_BASE_PASS, sender->gid,
            &m_wrap->h);
616
617
618
619
620
621
622
623
    *msg_data = ((char*)m_wrap)+msg_offsets[net_id];
    // extra_data is optional
    if (extra_data != NULL){
        *extra_data = m_wrap + 1;
    }
    return e;
}

624
625
626
627
628
629
630
631
632
633
634
635
void model_net_method_send_msg_recv_event(
        tw_lpid final_dest_lp,
        tw_lpid dest_mn_lp,
        tw_lpid src_lp, // the "actual" source (as opposed to the model net lp)
        uint64_t msg_size,
        int is_pull,
        uint64_t pull_size,
        int remote_event_size,
        const mn_sched_params *sched_params,
        const char * category,
        int net_id,
        void * msg,
636
        tw_stime offset,
637
        tw_lp *sender){
638
    tw_event *e =
639
        tw_event_new(dest_mn_lp, offset+codes_local_latency(sender), sender);
640
641
642
643
644
645
646
647
    model_net_wrap_msg *m = tw_event_data(e);
    msg_set_header(model_net_base_magic, MN_BASE_NEW_MSG, sender->gid, &m->h);

    if (sched_params != NULL)
        m->msg.m_base.sched_params = *sched_params;
    else
        model_net_sched_set_default_params(&m->msg.m_base.sched_params);

648
649
650
    model_net_request *r = &m->msg.m_base.req;
    r->final_dest_lp = final_dest_lp;
    r->src_lp = src_lp;
651
    // for "recv" events, set the "dest" to this LP in the case of a pull event
652
653
654
655
656
657
658
659
660
    r->dest_mn_lp = sender->gid;
    r->pull_size = pull_size;
    r->msg_size = msg_size;
    // TODO: document why we're setting packet_size this way
    r->packet_size = msg_size;
    r->net_id = net_id;
    r->is_pull = is_pull;
    r->remote_event_size = remote_event_size;
    r->self_event_size = 0;
661
662
    m->msg.m_base.is_from_remote = 1;

663
664
    strncpy(r->category, category, CATEGORY_NAME_MAX-1);
    r->category[CATEGORY_NAME_MAX-1] = '\0';
665
666
667
668
669
670
671
672
673

    if (remote_event_size > 0){
        void * m_dat = model_net_method_get_edata(net_id, msg);
        memcpy(m+1, m_dat, remote_event_size);
    }

    tw_event_send(e);
}

Jonathan Jenkins's avatar
Jonathan Jenkins committed
674
675
676
677
void model_net_method_send_msg_recv_event_rc(tw_lp *sender){
    codes_local_latency_reverse(sender);
}

678
679
680

void model_net_method_idle_event(tw_stime offset_ts, int is_recv_queue,
        tw_lp * lp){
681
682
    tw_event *e = tw_event_new(lp->gid, offset_ts, lp);
    model_net_wrap_msg *m_wrap = tw_event_data(e);
683
684
    msg_set_header(model_net_base_magic, MN_BASE_SCHED_NEXT, lp->gid,
            &m_wrap->h);
685
    m_wrap->msg.m_base.is_from_remote = is_recv_queue;
686
687
688
    tw_event_send(e);
}

689
690
691
692
693
694
695
696
697
698
699
700
void * model_net_method_get_edata(int net_id, void *msg){
    return (char*)msg + sizeof(model_net_wrap_msg) - msg_offsets[net_id];
}

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 * End:
 *
 * vim: ft=c ts=8 sts=4 sw=4 expandtab
 */