Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ a3be1d55

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