Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ 3e29b8a0

History | View | Annotate | Download (12.5 KB)

1 01873262 Georg Kunz
//=========================================================================
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 a3d116e3 Simon Tenbusch
#include "cbarriermessage.h"
31 01873262 Georg Kunz
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 6b81f4fa Simon Tenbusch
    // Do we have to wait for a barrier?
57 fd9e238e Georg Kunz
    if (sim->threadPool)
58
        sim->threadPool->waitAtBarrier(&(sim->msgQueue));
59 6b81f4fa Simon Tenbusch
60 01873262 Georg Kunz
    //
61
    // If we retrieve a valid msg from the queue, we return it:
62
    //
63 aeae20a1 Simon Tenbusch
    cMessage *msg = sim->msgQueue.removeFirst();
64 6b81f4fa Simon Tenbusch
65 fd9e238e Georg Kunz
    if (msg)
66
        return msg;
67 6b81f4fa Simon Tenbusch
68 01873262 Georg Kunz
69
    //
70
    // if there is no event left and we don't use the threadpool, end the sim
71
    //
72
    if (!sim->threadPool)
73
        throw cTerminationException(eENDEDOK);
74
75
    //
76
    // If we did not get a valid msg from the queue, but there are still
77
    // barrier messages left, we wait:
78
    //
79
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
80
    {
81
        __asm__ ("pause");
82
    }
83 aeae20a1 Simon Tenbusch
    msg = sim->msgQueue.removeFirst();
84 01873262 Georg Kunz
85
    //
86
    // If there is a msg now, we return it:
87
    //
88 fd9e238e Georg Kunz
    if (msg)
89
        return msg;
90 01873262 Georg Kunz
91
    //
92
    // If there is still no message in the queue, there are
93
    // also no barriers left (else we would have waited), and we quit:
94
    //
95
    else
96 fd9e238e Georg Kunz
        throw cTerminationException(eENDEDOK);
97 01873262 Georg Kunz
98
#else
99 a3be1d55 Simon Tenbusch
    cMessage *msg = NULL;
100
    cBarrierMessage* barrier = NULL;
101 2501f650 Simon Tenbusch
102 6b81f4fa Simon Tenbusch
    while (!msg)
103 a3be1d55 Simon Tenbusch
    {
104
        msg = sim->msgQueue.removeFirst();
105
        if (!msg)
106
            throw cTerminationException(eENDEDOK);
107 fd9e238e Georg Kunz
108
        //
109
        // If we have a Barriermsg, we wait
110
        //
111 a3be1d55 Simon Tenbusch
        barrier = dynamic_cast<cBarrierMessage*> (msg);
112
        if (barrier != NULL)
113
        {
114 fd9e238e Georg Kunz
            //
115 a3be1d55 Simon Tenbusch
            // wait for the task to complete
116 fd9e238e Georg Kunz
            //
117 a3be1d55 Simon Tenbusch
            barrier->wait();
118
            delete barrier;
119
            msg = NULL;
120
        }
121
    }
122 2501f650 Simon Tenbusch
123
    cSimpleModule* mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
124
    if (mod->isAsyncModule())
125
    {
126 a3be1d55 Simon Tenbusch
        cAsyncModule* aMod = (cAsyncModule*) mod;
127 96e929a8 Simon Tenbusch
        simtime_t duration = msg->getEventDuration();
128 0e7ff5c8 Simon Tenbusch
        if (duration != SimTime::simTimeSequentialExecution && aMod->mayParallelize(msg, duration) && sim->threadPool)
129 a3be1d55 Simon Tenbusch
        {
130 fd9e238e Georg Kunz
            //
131 2501f650 Simon Tenbusch
            // create a new barrier and schedule it
132 fd9e238e Georg Kunz
            //
133 2501f650 Simon Tenbusch
            cBarrierMessage* barrier = new cBarrierMessage();
134 46ea5b3d Simon Tenbusch
            barrier->setArrival(aMod, -1, msg->getArrivalTime() + duration);
135 2501f650 Simon Tenbusch
            msg->setBarrier(barrier);
136 b9e9c37a Simon Tenbusch
137
            // If the event is a null duration event,
138
            // we have to set additional data in the barrier
139
            // to make sure the barrier gets placed correctly
140 64aa7fee Simon Tenbusch
            barrier->setSchedulingPriority(msg->getSchedulingPriority());
141 e1d5f2c9 Simon Tenbusch
            barrier->setParentStartTime(msg->getArrivalTime());
142
            barrier->setParentExecutionOrderId(sim->getNextExecutionOrderId(msg));
143 77cb9420 Simon Tenbusch
            // Set scheduling order to 0 (in front of all children)
144
            barrier->setSchedulingOrderId(0);
145 b9e9c37a Simon Tenbusch
146 2501f650 Simon Tenbusch
            sim->msgQueue.insert(barrier);
147
        }
148
    }
149 01873262 Georg Kunz
    return msg;
150
#endif
151
}
152
153
//-----
154 a3d116e3 Simon Tenbusch
Register_Class(cEEFScheduler)
155
;
156 01873262 Georg Kunz
157 a3d116e3 Simon Tenbusch
cEEFScheduler::cEEFScheduler()
158
{
159
}
160 fd9e238e Georg Kunz
161 a3d116e3 Simon Tenbusch
cEEFScheduler::~cEEFScheduler()
162
{
163
}
164
165
cMessage *cEEFScheduler::getNextEvent()
166
{
167 af9583d7 Simon Tenbusch
    if(!(sim->threadPool)) {
168
        throw cRuntimeError("EEFScheduler is not supported in sequential mode. Activate Threadpool or use cSequentialScheduler.");
169
    }
170 6b81f4fa Simon Tenbusch
171 c87b95b0 Simon Tenbusch
    updateIES();
172
    return getFirstEvent();
173
}
174 6b81f4fa Simon Tenbusch
175 c87b95b0 Simon Tenbusch
void cEEFScheduler::updateIES() {
176 6b81f4fa Simon Tenbusch
    cMessage *msg = NULL;
177
    cSimpleModule* mod = NULL;
178
    cAsyncModule* aMod = NULL;
179 a3d116e3 Simon Tenbusch
#ifdef NOBARRIER
180
181 6b81f4fa Simon Tenbusch
    while (!(sim->msgQueue.empty()))
182 fd9e238e Georg Kunz
    {
183 6b81f4fa Simon Tenbusch
        msg = sim->msgQueue.removeFirst();
184
185
        mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
186
187
        if (!(mod->isAsyncModule())) {
188
            break;
189
        }
190 96e929a8 Simon Tenbusch
191 6b81f4fa Simon Tenbusch
        aMod = (cAsyncModule*) mod;
192 96e929a8 Simon Tenbusch
        simtime_t duration = msg->getEventDuration();
193 6b81f4fa Simon Tenbusch
194 96e929a8 Simon Tenbusch
        if (!aMod->mayParallelize(msg, duration)) {
195 6b81f4fa Simon Tenbusch
            break;
196
        }
197 fd9e238e Georg Kunz
198
        //
199
        // If there is an active barrier in the threadpool before msg, break
200
        //
201 6b81f4fa Simon Tenbusch
        if (sim->threadPool->isBeforeBarrier(msg)) {
202
            break;
203
        }
204 fd9e238e Georg Kunz
205
        //
206
        // If an event in the IES would cause a barrier before msg, break
207
        //
208 6b81f4fa Simon Tenbusch
        if (!independentEventsHeap.empty() && msg->getArrivalTime() >= independentEventsHeap.peekFirst()->getTend()) {
209
            break;
210
        }
211 46ea5b3d Simon Tenbusch
/*        printf(
212 6b81f4fa Simon Tenbusch
                "adding to IEH: %s, tstart=%f, tend= %f, now First in IEH: ",
213
                ((cSimpleModule*) sim->getModule(msg->getArrivalModuleId()))->getName(),SIMTIME_DBL(msg->getArrivalTime()),
214 46ea5b3d Simon Tenbusch
                SIMTIME_DBL(msg->getTend()));*/
215 6b81f4fa Simon Tenbusch
216
        independentEventsHeap.insert(msg);
217
218 46ea5b3d Simon Tenbusch
/*        printf(
219 6b81f4fa Simon Tenbusch
                "%s, length=%i\n",
220
                ((cSimpleModule*) sim->getModule(
221
                        independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName(),
222 46ea5b3d Simon Tenbusch
                independentEventsHeap.length());*/
223 6b81f4fa Simon Tenbusch
        msg = NULL;
224
    }
225
226 fd9e238e Georg Kunz
    if (msg)
227
        sim->msgQueue.insert(msg);
228 a3d116e3 Simon Tenbusch
#else
229 6b81f4fa Simon Tenbusch
    cBarrierMessage* barrier = NULL;
230 52072b74 Simon Tenbusch
    /*
231
     * Fill up independent event heap
232
     */
233
    while (!(sim->msgQueue.empty()))
234 a3d116e3 Simon Tenbusch
    {
235 83ba5375 Simon Tenbusch
        msg = sim->msgQueue.removeFirst();
236 a3d116e3 Simon Tenbusch
        barrier = dynamic_cast<cBarrierMessage*> (msg);
237
        if (barrier != NULL)
238
        {
239 52072b74 Simon Tenbusch
            /*
240 c87b95b0 Simon Tenbusch
             * If the barrier has already been signaled, we can just delete it,
241
             * as we would not have to wait here
242 94cf1056 Simon Tenbusch
            */
243
            if(!barrier->isValid()) {
244
                delete barrier;
245
                continue;
246
            }
247
            /*
248 52072b74 Simon Tenbusch
             * if we hit a barrier, we are done and return the first independent msg
249 a3be1d55 Simon Tenbusch
             * or we have wait at the barrier if no independent event exists
250 52072b74 Simon Tenbusch
             */
251 a3be1d55 Simon Tenbusch
            if (independentEventsHeap.empty())
252
            {
253
                barrier->wait();
254
                delete barrier;
255
                continue;
256
            }
257
            else
258
            {
259 83ba5375 Simon Tenbusch
                sim->msgQueue.insert(msg);
260 c87b95b0 Simon Tenbusch
                return;
261 83ba5375 Simon Tenbusch
            }
262
        }
263 a3be1d55 Simon Tenbusch
264
        mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
265
        aMod = NULL;
266 83ba5375 Simon Tenbusch
        if (mod->isAsyncModule())
267
        {
268
            aMod = (cAsyncModule*) mod;
269 96e929a8 Simon Tenbusch
            simtime_t duration = msg->getEventDuration();
270 d617def6 Simon Tenbusch
271 a3be1d55 Simon Tenbusch
            if (!aMod->mayParallelize(msg, duration))
272
            {
273 c87b95b0 Simon Tenbusch
                sim->msgQueue.insert(msg);
274
                return;
275 83ba5375 Simon Tenbusch
            }
276
            // create a new barrier and schedule it
277
            cBarrierMessage* barrier = new cBarrierMessage();
278 46ea5b3d Simon Tenbusch
            barrier->setArrival(aMod, -1, msg->getArrivalTime() + duration);
279 83ba5375 Simon Tenbusch
            msg->setBarrier(barrier);
280
            sim->msgQueue.insert(barrier);
281 a3be1d55 Simon Tenbusch
282 46ea5b3d Simon Tenbusch
/*            printf(
283 96e929a8 Simon Tenbusch
                    "adding to IEH: %s, tstart=%f, tend= %f, now First in IEH: ",
284
                    ((cSimpleModule*) sim->getModule(msg->getArrivalModuleId()))->getName(),SIMTIME_DBL(msg->getArrivalTime()),
285 46ea5b3d Simon Tenbusch
                    SIMTIME_DBL(msg->getTend()));*/
286 a3be1d55 Simon Tenbusch
287 83ba5375 Simon Tenbusch
            independentEventsHeap.insert(msg);
288 9194dd48 Simon Tenbusch
289 46ea5b3d Simon Tenbusch
/*            printf(
290 a3be1d55 Simon Tenbusch
                    "%s, length=%i\n",
291
                    ((cSimpleModule*) sim->getModule(
292
                            independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName(),
293 46ea5b3d Simon Tenbusch
                    independentEventsHeap.length());*/
294 83ba5375 Simon Tenbusch
295 a3be1d55 Simon Tenbusch
        }
296
        else //Not a AsyncModule
297
        {
298 c87b95b0 Simon Tenbusch
            sim->msgQueue.insert(msg);
299
            return;
300 a3be1d55 Simon Tenbusch
        }
301 52072b74 Simon Tenbusch
302 a3be1d55 Simon Tenbusch
    } // while (!(sim->msgQueue.empty()))
303 a3d116e3 Simon Tenbusch
#endif
304
}
305
306 c87b95b0 Simon Tenbusch
cMessage* cEEFScheduler::getFirstEvent() {
307
#ifdef NOBARRIER
308
    cMessage *msg = NULL;
309
    if(independentEventsHeap.empty()) {
310
            if (!sim->msgQueue.empty()) {
311
                // Do we have to wait for a barrier?
312
                if (sim->threadPool) sim->threadPool->waitAtBarrier(&(sim->msgQueue));
313
                return sim->msgQueue.removeFirst();
314
            }
315
        } else {
316
            return independentEventsHeap.getFirst();
317
        }
318
        // At this point, both IES and FES are empty
319
        //
320
        // if there is no event left and we don't use the threadpool, end the sim
321
        //
322
        if (!sim->threadPool)
323 fd9e238e Georg Kunz
            throw cTerminationException(eENDEDOK);
324 c87b95b0 Simon Tenbusch
325
        //
326
        // If we did not get a valid msg from the queue, but there are still
327
        // barrier messages left, we wait:
328
        //
329
        while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
330
        {
331
            __asm__ ("pause");
332
        }
333
        msg = sim->msgQueue.removeFirst();
334 a3d116e3 Simon Tenbusch
335 c87b95b0 Simon Tenbusch
        if (msg) return msg;
336 aeae20a1 Simon Tenbusch
337 c87b95b0 Simon Tenbusch
        //
338
        // If there is still no message in the queue, there are
339
        // also no barriers left (else we would have waited), and we quit:
340
        //
341
342
        else
343 fd9e238e Georg Kunz
            throw cTerminationException(eENDEDOK);
344 c87b95b0 Simon Tenbusch
#else
345
        if (independentEventsHeap.empty())
346
        {
347
            if (sim->msgQueue.empty()) {
348
                /*
349
                 * Both Queues are empty, we are done
350
                 */
351
                throw cTerminationException(eENDEDOK);
352
            } else {
353
                /*
354
                 * In this case, we have sequential execution
355
                 */
356
                return sim->msgQueue.removeFirst();
357
            }
358
        }
359
        return independentEventsHeap.getFirst();
360
#endif
361
}
362 aeae20a1 Simon Tenbusch
363 a3d116e3 Simon Tenbusch
//-----
364 01873262 Georg Kunz
Register_Class(cRealTimeScheduler);
365
366
void cRealTimeScheduler::startRun()
367
{
368
    factor = ev.getConfig()->getAsDouble(CFGID_REALTIMESCHEDULER_SCALING);
369
    if (factor!=0)
370
        factor = 1/factor;
371
    doScaling = (factor!=0);
372
373
    gettimeofday(&baseTime, NULL);
374
}
375
376
void cRealTimeScheduler::endRun()
377
{
378
}
379
380
void cRealTimeScheduler::executionResumed()
381
{
382
    gettimeofday(&baseTime, NULL);
383
    baseTime = timeval_substract(baseTime, SIMTIME_DBL(doScaling ? factor*sim->getSimTime() : sim->getSimTime()));
384
}
385
386
bool cRealTimeScheduler::waitUntil(const timeval& targetTime)
387
{
388
    // if there's more than 200ms to wait, wait in 100ms chunks
389
    // in order to keep UI responsiveness by invoking ev.idle()
390
    timeval curTime;
391
    gettimeofday(&curTime, NULL);
392
    while (targetTime.tv_sec-curTime.tv_sec >=2 ||
393
           timeval_diff_usec(targetTime, curTime) >= 200000)
394
    {
395
        usleep(100000); // 100ms
396
        if (ev.idle())
397
            return false;
398
        gettimeofday(&curTime, NULL);
399
    }
400
401
    // difference is now at most 100ms, do it at once
402
    long usec = timeval_diff_usec(targetTime, curTime);
403
    if (usec>0)
404
        usleep(usec);
405
    return true;
406
}
407
408
cMessage *cRealTimeScheduler::getNextEvent()
409
{
410
#ifdef NOBARRIER
411 bfb08604 Simon Tenbusch
    throw cRuntimeError("RealTimeScheduler is not supported with NOBARRIER.");
412
#endif
413
    if(sim->threadPool) {
414
        //TODO: Handle barriermsg
415
        throw cRuntimeError("RealTimeScheduler is not supported with Threadpool.");
416 01873262 Georg Kunz
    }
417 bfb08604 Simon Tenbusch
    cMessage *msg = sim->msgQueue.removeFirst();
418 01873262 Georg Kunz
    if (!msg)
419
        throw cTerminationException(eENDEDOK);
420
421
    // calculate target time
422
    simtime_t eventSimtime = msg->getArrivalTime();
423
    timeval targetTime = timeval_add(baseTime, SIMTIME_DBL(doScaling ? factor*eventSimtime : eventSimtime));
424
425
    // if needed, wait until that time arrives
426
    timeval curTime;
427
    gettimeofday(&curTime, NULL);
428
    if (timeval_greater(targetTime, curTime))
429
    {
430
        if (!waitUntil(targetTime))
431
            return NULL; // user break
432
    }
433
    else
434
    {
435
        // we're behind -- customized versions of this class may alert
436
        // if we're too much behind, or modify basetime to accept the skew
437
    }
438
439
    // ok, return the message
440
    return msg;
441
}