Project

General

Profile

Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (9.88 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
cMessage* cScheduler::removeNextEvent()
50
{
51
    return sim->msgQueue.removeFirst();
52
}
53
//-----
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

    
98
    cMessage *msg = sim->msgQueue.removeFirst();
99
    if (!msg)
100
        throw cTerminationException(eENDEDOK);
101

    
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
    return msg;
126
#endif
127
}
128

    
129
//-----
130
Register_Class(cEEFScheduler)
131
;
132

    
133
cEEFScheduler::cEEFScheduler()
134
{
135
}
136
cEEFScheduler::~cEEFScheduler()
137
{
138
}
139

    
140
cMessage *cEEFScheduler::getNextEvent()
141
{
142
#ifdef NOBARRIER
143
    assert(false); //Not yet implemented
144
    //
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
    /*
185
     * Fill up independent event heap
186
     */
187
    while (!(sim->msgQueue.empty()))
188
    {
189
        msg = sim->msgQueue.removeFirst();
190
        barrier = dynamic_cast<cBarrierMessage*> (msg);
191
        if (barrier != NULL)
192
        {
193
            /*
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
            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
            msg->setEventDuration(duration);
225

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

    
235

    
236
            // 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
            printf("adding to IEH: %s, tend= %f, now First in IEH: ",((cSimpleModule*)sim->getModule(msg->getArrivalModuleId()))->getName(),SIMTIME_DBL(msg->getTend()));
243
            independentEventsHeap.insert(msg);
244
            printf("%s\n", ((cSimpleModule*)sim->getModule(independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName());
245

    
246
        }
247

    
248
    }
249

    
250
    /*
251
     * the big queue is empty
252
     * check if the independent event set is also empty
253
     */
254
    if (independentEventsHeap.empty()) {
255
        throw cTerminationException(eENDEDOK);
256
    }
257
    return independentEventsHeap.getFirst();
258
#endif
259
}
260

    
261

    
262
//-----
263
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

    
375