Project

General

Profile

Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ 6b036b78

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