Bug 376

Summary: Mixing use of realtime simulator Schedule and Schedule now problematic
Product: ns-3 Reporter: Craig Dowell <craigdo>
Component: coreAssignee: Craig Dowell <craigdo>
Status: RESOLVED FIXED    
Severity: normal    
Priority: P3    
Version: ns-3-dev   
Hardware: All   
OS: All   
Attachments: Separate out simulator methods that can change time based on realtime clock.

Description Craig Dowell 2008-10-08 15:29:29 UTC
Consider the following scenario (not using underlying real time clocks):

  Event A starts running at tA
  Schedule Event B for tA + tEpsilon
  long processing step tP consumes real-time tP
  ScheduleNow Event C

This would result in the following sequence of events:

  Event A, Event C, Event B

If you use ScheduleNow with an underlying realtime clock, and the time consumed by the the procesing step is small (tP < tEpsilon), the order of execution is unchanged.  However, if tP > tEpsilon the executed event order changes to

  Event A, Event B, Event C

In the real world tP may vary around tEpsilon and the event ordering may change unpredictably and incorrectly as system loads vary.

There are cases where doing a ScheduleNow using the actual underlying realtime clock is required (to cause simulation time to advance in the presence of external events such as network packet reception).

There are cases where using the underlying realtime clock can cause errors in situations where dependent events can change order.

The current realtime simulator makes no distinction between scheduling operations that involve the realtime clock and those that don't.  This leads to slippery situations.

There need to be two kinds of scheduling methods:  one set that respects time as models may assume using m_currentTs as a basis, and one set that works with the current realtime as a basis.  How this works is tricky.  The time to process event A can no longer affect the order of the events A, B and C.  

If we implement a separate {Schedule, ScheduleNow} and {ScheduleReal, ScheduleRealNow} the situation changes.  The related events {A,B,C} use Schedule and ScheduleNow and are therefore using m_currentTs as a basis.  The external device uses ScheduleRealNow and uses the current realtime as a basis.

What we have then is an unrelated external event being scheduled for some time during the actual execution of the related events:

  Event A starts running at m_currentTs = tA, realtime ~ tA 
  Schedule() Event B for absolute time tA + tEpsilon (based on m_currentTs)
  long processing step consumes real-time during event A execution
  Packet Reception queues event D for realtime tA < tR < tEpsilon
  ScheduleNow Event C (based on m_currentTs) = tA

Here's what happens:

  1. Event A is run at about realtime = tA.
  2. Event B is inserted at the head of the queue for tA + tEpsilon
     at about realtime tA
  3. Event A continues running for some time tP.  Somewhere during the 
     event, an external thread schedules an event for 
     tA + tR (at the current realtime then) which is less than 
     tA + tEpsilon, so this goes at the head of the event queue.
  4. Event C is scheduled for m_currentTs = tA and so this goes
     to the head of the event queue.

  Event execution is as follows,

  Event A @ tA executes at realtime ~ tA
  Event C @ tA executes at realtime ~ tA plus tP (after event A)
  Event D @ tA + tR executes at realtime tA + tR
  Event B @ tA + tEpsilon

The order of the events A, B, C is preserved.  Event D is an unrelated "asynchronous" event that happens at some realtime before tA + tEpsilon

You can see that if tA + tR > tA + tEpsilon (the reception event happens during the execution time of tA (where m_currentTs = tA) but at a realtime > tA + tEpsilon, the execution order of all events changes, but the ordering of the events scheduled by Schedule() and ScheduleNow() is preserved.

  Event A @ tA executes at realtime ~ tA
  Event C @ tA executes at realtime ~ tA plus tP (after event A)
  Event B @ tA + tEpsilon
  Event D @ tA + tR executes at realtime tA + tR

This seems to me to be the right thing to do.
Comment 1 Mathieu Lacage 2008-10-10 04:02:51 UTC
I would like to see a single ScheduleReal instead of ScheduleReal+ScheduleRealNow: ScheduleRealNow is purely syntactical sugar for ScheduleReal(Seconds (0.0)) and I can't imagine that we will have enough users of this piece of code to make this syntactical sugar very useful.
Comment 2 Craig Dowell 2008-10-10 15:16:07 UTC
Not that it is a terribly big deal, but I think the two models, real and non-real, should be symmetric.

I think the main use for the real-time call will be in the form of ScheduleRealNow(); and I think forcing the user (probably mostly me) to always call ScheduleReal(0) is just unnecessary obfuscation.

I like syntactic sugar, since its purpose is to make my life easier.  I like symmetrical interfaces since it means fewer exceptions to remember.
Comment 3 Craig Dowell 2008-10-11 00:12:48 UTC
Created attachment 264 [details]
Separate out simulator methods that can change time based on realtime clock.