Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ a3be1d55

History | View | Annotate | Download (10.5 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
    //
57
    // If we retrieve a valid msg from the queue, we return it:
58
    //
59
    cMessage *msg = sim->msgQueue.removeFirst();
60
    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
    msg = sim->msgQueue.removeFirst();
78

    
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

    
90
    else
91
    throw cTerminationException(eENDEDOK);
92

    
93
#else
94
    cMessage *msg = NULL;
95
    cBarrierMessage* barrier = NULL;
96

    
97
    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

    
115
    cSimpleModule* mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
116
    if (mod->isAsyncModule())
117
    {
118
        cAsyncModule* aMod = (cAsyncModule*) mod;
119
        simtime_t now = msg->getArrivalTime();
120
        simtime_t duration = aMod->getProcessingDelay(msg);
121

    
122
        if (aMod->mayParallelize(msg, duration))
123
        {
124
            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
    return msg;
134
#endif
135
}
136

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

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

    
148
cMessage *cEEFScheduler::getNextEvent()
149
{
150
#ifdef NOBARRIER
151
    assert(false); //Not yet implemented
152
    //
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

    
191
    //TODO: Optimize to save state when the IES has to be emptied
192

    
193
    cMessage *msg;
194
    cBarrierMessage* barrier;
195
    cSimpleModule* mod;
196
    cAsyncModule* aMod;
197
    /*
198
     * Fill up independent event heap
199
     */
200
    while (!(sim->msgQueue.empty()))
201
    {
202
        msg = sim->msgQueue.removeFirst();
203
        barrier = dynamic_cast<cBarrierMessage*> (msg);
204
        if (barrier != NULL)
205
        {
206
            /*
207
             * if we hit a barrier, we are done and return the first independent msg
208
             * or we have wait at the barrier if no independent event exists
209
             */
210
            if (independentEventsHeap.empty())
211
            {
212
                barrier->wait();
213
                delete barrier;
214
                continue;
215
            }
216
            else
217
            {
218
                sim->msgQueue.insert(msg);
219
                return independentEventsHeap.getFirst();
220
            }
221
        }
222

    
223
        mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
224
        aMod = NULL;
225
        if (mod->isAsyncModule())
226
        {
227
            aMod = (cAsyncModule*) mod;
228
            simtime_t now = msg->getArrivalTime();
229
            simtime_t duration = aMod->getProcessingDelay(msg);
230
            msg->setEventDuration(duration);
231

    
232
            if (!aMod->mayParallelize(msg, duration))
233
            {
234
                if (independentEventsHeap.empty())
235
                {
236
                    return msg;
237
                }
238
                else
239
                {
240
                    sim->msgQueue.insert(msg);
241
                    return independentEventsHeap.getFirst();
242
                }
243
            }
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

    
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
            independentEventsHeap.insert(msg);
257

    
258
            printf(
259
                    "%s, length=%i\n",
260
                    ((cSimpleModule*) sim->getModule(
261
                            independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName(),
262
                    independentEventsHeap.length());
263

    
264
        }
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

    
278
    } // 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
#endif
289
}
290

    
291

    
292

    
293

    
294
//-----
295
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

    
407