Statistics
| Branch: | Revision:

root / src / sim / cscheduler.cc @ aeae20a1

History | View | Annotate | Download (9.85 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
    else
90
        throw cTerminationException(eENDEDOK);
91

    
92
#else
93

    
94
    cMessage *msg = sim->msgQueue.removeFirst();
95
    if (!msg)
96
        throw cTerminationException(eENDEDOK);
97

    
98
    cBarrierMessage* barrier = dynamic_cast<cBarrierMessage*> (msg);
99
            if (barrier != NULL)
100
            {
101
                return msg;
102
            }
103
    cSimpleModule* mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
104
    cAsyncModule* aMod = NULL;
105
    if (mod->isAsyncModule())
106
    {
107
        aMod = (cAsyncModule*) mod;
108
        simtime_t now = cThreadPool::getSimTime();
109
        simtime_t duration = aMod->getProcessingDelay(msg);
110
        if(aMod->mayParallelize(msg,duration)) {
111
            msg->setEventDuration(duration);
112
            // create a new barrier and schedule it
113
            cBarrierMessage* barrier = new cBarrierMessage();
114
            barrier->setArrival(aMod, -1, now + duration);
115
            msg->setBarrier(barrier);
116
            // insert user supplied message in task queue.
117
            sim->msgQueue.insert(barrier);
118
        }
119
    }
120

    
121
    return msg;
122
#endif
123
}
124

    
125
//-----
126
Register_Class(cEEFScheduler)
127
;
128

    
129
cEEFScheduler::cEEFScheduler()
130
{
131
}
132
cEEFScheduler::~cEEFScheduler()
133
{
134
}
135

    
136
cMessage *cEEFScheduler::getNextEvent()
137
{
138
#ifdef NOBARRIER
139
    assert(false); //Not yet implemented
140
    //
141
    // If we retrieve a valid msg from the queue, we return it:
142
    //
143
    cMessage *msg = sim->msgQueue.peekFirst();
144
    if (msg)
145
    return msg;
146

    
147
    //
148
    // if there is no event left and we don't use the threadpool, end the sim
149
    //
150
    if (!sim->threadPool)
151
    throw cTerminationException(eENDEDOK);
152

    
153
    //
154
    // If we did not get a valid msg from the queue, but there are still
155
    // barrier messages left, we wait:
156
    //
157
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
158
    {
159
        __asm__ ("pause");
160
    }
161
    msg = sim->msgQueue.peekFirst();
162

    
163
    //
164
    // If there is a msg now, we return it:
165
    //
166
    if (msg)
167
    return msg;
168

    
169
    //
170
    // If there is still no message in the queue, there are
171
    // also no barriers left (else we would have waited), and we quit:
172
    //
173

    
174
    else
175
    throw cTerminationException(eENDEDOK);
176

    
177
#else
178
    cMessage *msg;
179
    cBarrierMessage* barrier;
180
    /*
181
     * Fill up independent event heap
182
     */
183
    while (!(sim->msgQueue.empty()))
184
    {
185
        msg = sim->msgQueue.removeFirst();
186
        barrier = dynamic_cast<cBarrierMessage*> (msg);
187
        if (barrier != NULL)
188
        {
189
            /*
190
             * if we hit a barrier, we are done and return the first independent msg
191
             * or the barrier if no such event exists
192
             */
193
            if (independentEventsHeap.empty()) {
194
                return msg;
195
            } else {
196
                sim->msgQueue.insert(msg);
197
                return independentEventsHeap.getFirst();
198
            }
199

    
200
        }
201
        cSimpleModule* mod = (cSimpleModule*) sim->getModule(msg->getArrivalModuleId());
202
        cAsyncModule* aMod = NULL;
203
        if (mod->isAsyncModule())
204
        {
205
            aMod = (cAsyncModule*) mod;
206
        }
207
        if (aMod == NULL)
208
        {
209
            if (independentEventsHeap.empty()) {
210
                return msg;
211
            } else {
212
                sim->msgQueue.insert(msg);
213
                return independentEventsHeap.getFirst();
214
            }
215
        }
216
        else
217
        {
218
            simtime_t now = cThreadPool::getSimTime();
219
            simtime_t duration = aMod->getProcessingDelay(msg);
220
            msg->setEventDuration(duration);
221

    
222
            if(!aMod->mayParallelize(msg,duration)) {
223
                if (independentEventsHeap.empty()) {
224
                    return msg;
225
                } else {
226
                    sim->msgQueue.insert(msg);
227
                    return independentEventsHeap.getFirst();
228
                }
229
            }
230

    
231

    
232
            // create a new barrier and schedule it
233
            cBarrierMessage* barrier = new cBarrierMessage();
234
            barrier->setArrival(aMod, -1, now + duration);
235
            msg->setBarrier(barrier);
236
            // insert user supplied message in task queue.
237
            sim->msgQueue.insert(barrier);
238
            printf("adding to IEH: %s, tend= %f, now First in IEH: ",((cSimpleModule*)sim->getModule(msg->getArrivalModuleId()))->getName(),SIMTIME_DBL(msg->getTend()));
239
            independentEventsHeap.insert(msg);
240
            printf("%s, length=%i\n", ((cSimpleModule*)sim->getModule(independentEventsHeap.peekFirst()->getArrivalModuleId()))->getName(), independentEventsHeap.length());
241

    
242
        }
243

    
244
    }
245

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

    
257

    
258

    
259

    
260
//-----
261
Register_Class(cRealTimeScheduler);
262

    
263
void cRealTimeScheduler::startRun()
264
{
265
    factor = ev.getConfig()->getAsDouble(CFGID_REALTIMESCHEDULER_SCALING);
266
    if (factor!=0)
267
        factor = 1/factor;
268
    doScaling = (factor!=0);
269

    
270
    gettimeofday(&baseTime, NULL);
271
}
272

    
273
void cRealTimeScheduler::endRun()
274
{
275
}
276

    
277
void cRealTimeScheduler::executionResumed()
278
{
279
    gettimeofday(&baseTime, NULL);
280
    baseTime = timeval_substract(baseTime, SIMTIME_DBL(doScaling ? factor*sim->getSimTime() : sim->getSimTime()));
281
}
282

    
283
bool cRealTimeScheduler::waitUntil(const timeval& targetTime)
284
{
285
    // if there's more than 200ms to wait, wait in 100ms chunks
286
    // in order to keep UI responsiveness by invoking ev.idle()
287
    timeval curTime;
288
    gettimeofday(&curTime, NULL);
289
    while (targetTime.tv_sec-curTime.tv_sec >=2 ||
290
           timeval_diff_usec(targetTime, curTime) >= 200000)
291
    {
292
        usleep(100000); // 100ms
293
        if (ev.idle())
294
            return false;
295
        gettimeofday(&curTime, NULL);
296
    }
297

    
298
    // difference is now at most 100ms, do it at once
299
    long usec = timeval_diff_usec(targetTime, curTime);
300
    if (usec>0)
301
        usleep(usec);
302
    return true;
303
}
304

    
305
cMessage *cRealTimeScheduler::getNextEvent()
306
{
307
#ifdef NOBARRIER
308
    //
309
    // If we retrieve a valid msg from the queue, we return it:
310
    //
311
    cMessage *msg = sim->msgQueue.peekFirst();
312
    if (msg)
313
        return msg;
314

    
315
    //
316
    // if there is no event left and we don't use the threadpool, end the sim
317
    //
318
    if (!sim->threadPool)
319
        throw cTerminationException(eENDEDOK);
320

    
321
    //
322
    // If we did not get a valid msg from the queue, but there are still
323
    // barrier messages left, we wait:
324
    //
325
    while (sim->msgQueue.empty() && !sim->threadPool->barrierEmpty())
326
    {
327
        __asm__ ("pause");
328
    }
329
    msg = sim->msgQueue.peekFirst();
330

    
331
    //
332
    // If there is a msg now, we return it:
333
    //
334
    if (msg)
335
        return msg;
336

    
337
    //
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
    else
342
        throw cTerminationException(eENDEDOK);
343

    
344
#else
345
    cMessage *msg = sim->msgQueue.peekFirst();
346
    if (!msg)
347
        throw cTerminationException(eENDEDOK);
348

    
349
    // calculate target time
350
    simtime_t eventSimtime = msg->getArrivalTime();
351
    timeval targetTime = timeval_add(baseTime, SIMTIME_DBL(doScaling ? factor*eventSimtime : eventSimtime));
352

    
353
    // if needed, wait until that time arrives
354
    timeval curTime;
355
    gettimeofday(&curTime, NULL);
356
    if (timeval_greater(targetTime, curTime))
357
    {
358
        if (!waitUntil(targetTime))
359
            return NULL; // user break
360
    }
361
    else
362
    {
363
        // we're behind -- customized versions of this class may alert
364
        // if we're too much behind, or modify basetime to accept the skew
365
    }
366

    
367
    // ok, return the message
368
    return msg;
369
#endif
370
}
371

    
372

    
373