Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ 96e929a8

History | View | Annotate | Download (12.3 KB)

1
//=========================================================================
2
//  CSCHEDULER.CC - part of
3
//
4
//                  OMNeT++/OMNEST
5
//           Discrete System Simulation in C++
6
//
7
//  Author: Andras Varga, 2003
8
//
9
//=========================================================================
10

    
11
/*--------------------------------------------------------------*
12
  Copyright (C) 2003-2008 Andras Varga
13
  Copyright (C) 2006-2008 OpenSim Ltd.
14
  Monash University, Dept. of Electrical and Computer Systems Eng.
15
  Melbourne, Australia
16

17
  This file is distributed WITHOUT ANY WARRANTY. See the file
18
  `license' for details on this and other legal matters.
19
*--------------------------------------------------------------*/
20

    
21
#include "cscheduler.h"
22
#include "cmessage.h"
23
#include "csimulation.h"
24
#include "cmessageheap.h"
25
#include "globals.h"
26
#include "cenvir.h"
27
#include "cconfiguration.h"
28
#include "cconfigoption.h"
29
#include "platmisc.h" // usleep
30
#include "cbarriermessage.h"
31

    
32
USING_NAMESPACE
33

    
34
Register_GlobalConfigOption(CFGID_REALTIMESCHEDULER_SCALING, "realtimescheduler-scaling", CFG_DOUBLE, NULL, "When cRealTimeScheduler is selected as scheduler class: ratio of simulation time to real time. For example, scaling=2 will cause simulation time to progress twice as fast as runtime.");
35

    
36
cScheduler::cScheduler()
37
{
38
    sim = NULL;
39
}
40

    
41
cScheduler::~cScheduler()
42
{
43
}
44

    
45
void cScheduler::setSimulation(cSimulation *_sim)
46
{
47
    sim = _sim;
48
}
49
//-----
50

    
51
Register_Class(cSequentialScheduler);
52

    
53
cMessage *cSequentialScheduler::getNextEvent()
54
{
55
#ifdef NOBARRIER
56
    // Do we have to wait for a barrier?
57
    if (sim->threadPool) sim->threadPool->waitAtBarrier(&(sim->msgQueue));
58

    
59
    //
60
    // If we retrieve a valid msg from the queue, we return it:
61
    //
62
    cMessage *msg = sim->msgQueue.removeFirst();
63

    
64
    if (msg) return msg;
65

    
66

    
67
    //
68
    // if there is no event left and we don't use the threadpool, end the sim
69
    //
70
    if (!sim->threadPool)
71
        throw cTerminationException(eENDEDOK);
72

    
73
    //
74
    // If we did not get a valid msg from the queue, but there are still
75
    // barrier messages left, we wait:
76
    //
77
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
78
    {
79
        __asm__ ("pause");
80
    }
81
    msg = sim->msgQueue.removeFirst();
82

    
83
    //
84
    // If there is a msg now, we return it:
85
    //
86
    if (msg) return msg;
87

    
88
    //
89
    // If there is still no message in the queue, there are
90
    // also no barriers left (else we would have waited), and we quit:
91
    //
92

    
93
    else
94
    throw cTerminationException(eENDEDOK);
95

    
96
#else
97
    cMessage *msg = NULL;
98
    cBarrierMessage* barrier = NULL;
99

    
100
    while (!msg)
101
    {
102
        msg = sim->msgQueue.removeFirst();
103
        if (!msg)
104
            throw cTerminationException(eENDEDOK);
105
        /*
106
         * If we have a Barriermsg, we wait
107
         */
108
        barrier = dynamic_cast<cBarrierMessage*> (msg);
109
        if (barrier != NULL)
110
        {
111
            // wait for the task to complete
112
            barrier->wait();
113
            delete barrier;
114
            msg = NULL;
115
        }
116
    }
117

    
118
    cSimpleModule* mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
119
    if (mod->isAsyncModule())
120
    {
121
        cAsyncModule* aMod = (cAsyncModule*) mod;
122
        simtime_t now = msg->getArrivalTime();
123
        simtime_t duration = msg->getEventDuration();
124

    
125
        if (aMod->mayParallelize(msg, duration))
126
        {
127
            // create a new barrier and schedule it
128
            cBarrierMessage* barrier = new cBarrierMessage();
129
            barrier->setArrival(aMod, -1, now + duration);
130
            msg->setBarrier(barrier);
131
            sim->msgQueue.insert(barrier);
132
        }
133
    }
134
    return msg;
135
#endif
136
}
137

    
138
//-----
139
Register_Class(cEEFScheduler)
140
;
141

    
142
cEEFScheduler::cEEFScheduler()
143
{
144
}
145
cEEFScheduler::~cEEFScheduler()
146
{
147
}
148

    
149
cMessage *cEEFScheduler::getNextEvent()
150
{
151

    
152
    //TODO: check if barriermessage is still vaild before waiting (may speed up things, as IES may not run empty)
153

    
154
    cMessage *msg = NULL;
155
    cSimpleModule* mod = NULL;
156
    cAsyncModule* aMod = NULL;
157

    
158
#ifdef NOBARRIER
159

    
160
    while (!(sim->msgQueue.empty()))
161
       {
162
        msg = sim->msgQueue.removeFirst();
163

    
164
        mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
165

    
166
        if (!(mod->isAsyncModule())) {
167
            break;
168
        }
169

    
170
        aMod = (cAsyncModule*) mod;
171
        simtime_t duration = msg->getEventDuration();
172

    
173
        if (!aMod->mayParallelize(msg, duration)) {
174
            break;
175
        }
176
        /*
177
         * If there is an active barrier in the threadpool before msg, break
178
         */
179
        if (sim->threadPool->isBeforeBarrier(msg)) {
180
            break;
181
        }
182
        /*
183
         * If an event in the IES would cause a barrier before msg, break
184
         */
185
        if (!independentEventsHeap.empty() && msg->getArrivalTime() >= independentEventsHeap.peekFirst()->getTend()) {
186
            break;
187
        }
188
        printf(
189
                "adding to IEH: %s, tstart=%f, tend= %f, now First in IEH: ",
190
                ((cSimpleModule*) sim->getModule(msg->getArrivalModuleId()))->getName(),SIMTIME_DBL(msg->getArrivalTime()),
191
                SIMTIME_DBL(msg->getTend()));
192

    
193
        independentEventsHeap.insert(msg);
194

    
195
        printf(
196
                "%s, length=%i\n",
197
                ((cSimpleModule*) sim->getModule(
198
                        independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName(),
199
                independentEventsHeap.length());
200
        msg = NULL;
201
    }
202

    
203
    if (msg) sim->msgQueue.insert(msg);
204

    
205
    if(independentEventsHeap.empty()) {
206
        if (!sim->msgQueue.empty()) {
207
            // Do we have to wait for a barrier?
208
            if (sim->threadPool) sim->threadPool->waitAtBarrier(&(sim->msgQueue));
209
            return sim->msgQueue.removeFirst();
210
        }
211
    } else {
212
        return independentEventsHeap.getFirst();
213
    }
214
    // At this point, both IES and FES are empty
215
    //
216
    // if there is no event left and we don't use the threadpool, end the sim
217
    //
218
    if (!sim->threadPool)
219
    throw cTerminationException(eENDEDOK);
220

    
221
    //
222
    // If we did not get a valid msg from the queue, but there are still
223
    // barrier messages left, we wait:
224
    //
225
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
226
    {
227
        __asm__ ("pause");
228
    }
229
    msg = sim->msgQueue.removeFirst();
230

    
231
    if (msg) return msg;
232

    
233
    //
234
    // If there is still no message in the queue, there are
235
    // also no barriers left (else we would have waited), and we quit:
236
    //
237

    
238
    else
239
    throw cTerminationException(eENDEDOK);
240

    
241
#else
242
    cBarrierMessage* barrier = NULL;
243
    /*
244
     * Fill up independent event heap
245
     */
246
    while (!(sim->msgQueue.empty()))
247
    {
248
        msg = sim->msgQueue.removeFirst();
249
        barrier = dynamic_cast<cBarrierMessage*> (msg);
250
        if (barrier != NULL)
251
        {
252
            /*
253
             * If the barrier has already been signaled, we can just delete it, as we would not have to wait here
254
            */
255
            if(!barrier->isValid()) {
256
                delete barrier;
257
                continue;
258
            }
259
            /*
260
             * if we hit a barrier, we are done and return the first independent msg
261
             * or we have wait at the barrier if no independent event exists
262
             */
263
            if (independentEventsHeap.empty())
264
            {
265
                barrier->wait();
266
                delete barrier;
267
                continue;
268
            }
269
            else
270
            {
271
                sim->msgQueue.insert(msg);
272
                return independentEventsHeap.getFirst();
273
            }
274
        }
275

    
276
        mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
277
        aMod = NULL;
278
        if (mod->isAsyncModule())
279
        {
280
            aMod = (cAsyncModule*) mod;
281
            simtime_t now = msg->getArrivalTime();
282
            simtime_t duration = msg->getEventDuration();
283

    
284
            if (!aMod->mayParallelize(msg, duration))
285
            {
286
                if (independentEventsHeap.empty())
287
                {
288
                    return msg;
289
                }
290
                else
291
                {
292
                    sim->msgQueue.insert(msg);
293
                    return independentEventsHeap.getFirst();
294
                }
295
            }
296
            // create a new barrier and schedule it
297
            cBarrierMessage* barrier = new cBarrierMessage();
298
            barrier->setArrival(aMod, -1, now + duration);
299
            msg->setBarrier(barrier);
300
            sim->msgQueue.insert(barrier);
301

    
302
            printf(
303
                    "adding to IEH: %s, tstart=%f, tend= %f, now First in IEH: ",
304
                    ((cSimpleModule*) sim->getModule(msg->getArrivalModuleId()))->getName(),SIMTIME_DBL(msg->getArrivalTime()),
305
                    SIMTIME_DBL(msg->getTend()));
306

    
307
            independentEventsHeap.insert(msg);
308

    
309
            printf(
310
                    "%s, length=%i\n",
311
                    ((cSimpleModule*) sim->getModule(
312
                            independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName(),
313
                    independentEventsHeap.length());
314

    
315
        }
316
        else //Not a AsyncModule
317
        {
318
            if (independentEventsHeap.empty())
319
            {
320
                return msg;
321
            }
322
            else
323
            {
324
                sim->msgQueue.insert(msg);
325
                return independentEventsHeap.getFirst();
326
            }
327
        }
328

    
329
    } // while (!(sim->msgQueue.empty()))
330
/*
331
 * the FES is empty
332
 * check if the independent event set is also empty
333
 */
334
if (independentEventsHeap.empty())
335
{
336
    throw cTerminationException(eENDEDOK);
337
}
338
return independentEventsHeap.getFirst();
339
#endif
340
}
341

    
342

    
343

    
344

    
345
//-----
346
Register_Class(cRealTimeScheduler);
347

    
348
void cRealTimeScheduler::startRun()
349
{
350
    factor = ev.getConfig()->getAsDouble(CFGID_REALTIMESCHEDULER_SCALING);
351
    if (factor!=0)
352
        factor = 1/factor;
353
    doScaling = (factor!=0);
354

    
355
    gettimeofday(&baseTime, NULL);
356
}
357

    
358
void cRealTimeScheduler::endRun()
359
{
360
}
361

    
362
void cRealTimeScheduler::executionResumed()
363
{
364
    gettimeofday(&baseTime, NULL);
365
    baseTime = timeval_substract(baseTime, SIMTIME_DBL(doScaling ? factor*sim->getSimTime() : sim->getSimTime()));
366
}
367

    
368
bool cRealTimeScheduler::waitUntil(const timeval& targetTime)
369
{
370
    // if there's more than 200ms to wait, wait in 100ms chunks
371
    // in order to keep UI responsiveness by invoking ev.idle()
372
    timeval curTime;
373
    gettimeofday(&curTime, NULL);
374
    while (targetTime.tv_sec-curTime.tv_sec >=2 ||
375
           timeval_diff_usec(targetTime, curTime) >= 200000)
376
    {
377
        usleep(100000); // 100ms
378
        if (ev.idle())
379
            return false;
380
        gettimeofday(&curTime, NULL);
381
    }
382

    
383
    // difference is now at most 100ms, do it at once
384
    long usec = timeval_diff_usec(targetTime, curTime);
385
    if (usec>0)
386
        usleep(usec);
387
    return true;
388
}
389

    
390
cMessage *cRealTimeScheduler::getNextEvent()
391
{
392
#ifdef NOBARRIER
393
    //
394
    // If we retrieve a valid msg from the queue, we return it:
395
    //
396
    cMessage *msg = sim->msgQueue.peekFirst();
397
    if (msg)
398
        return msg;
399

    
400
    //
401
    // if there is no event left and we don't use the threadpool, end the sim
402
    //
403
    if (!sim->threadPool)
404
        throw cTerminationException(eENDEDOK);
405

    
406
    //
407
    // If we did not get a valid msg from the queue, but there are still
408
    // barrier messages left, we wait:
409
    //
410
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
411
    {
412
        __asm__ ("pause");
413
    }
414
    msg = sim->msgQueue.peekFirst();
415

    
416
    //
417
    // If there is a msg now, we return it:
418
    //
419
    if (msg)
420
        return msg;
421

    
422
    //
423
    // If there is still no message in the queue, there are
424
    // also no barriers left (else we would have waited), and we quit:
425
    //
426
    else
427
        throw cTerminationException(eENDEDOK);
428

    
429
#else
430
    cMessage *msg = sim->msgQueue.peekFirst();
431
    if (!msg)
432
        throw cTerminationException(eENDEDOK);
433

    
434
    // calculate target time
435
    simtime_t eventSimtime = msg->getArrivalTime();
436
    timeval targetTime = timeval_add(baseTime, SIMTIME_DBL(doScaling ? factor*eventSimtime : eventSimtime));
437

    
438
    // if needed, wait until that time arrives
439
    timeval curTime;
440
    gettimeofday(&curTime, NULL);
441
    if (timeval_greater(targetTime, curTime))
442
    {
443
        if (!waitUntil(targetTime))
444
            return NULL; // user break
445
    }
446
    else
447
    {
448
        // we're behind -- customized versions of this class may alert
449
        // if we're too much behind, or modify basetime to accept the skew
450
    }
451

    
452
    // ok, return the message
453
    return msg;
454
#endif
455
}
456

    
457

    
458