Bringing the virtual clock up to real time

105 views
Skip to first unread message

Stefan Jevtic

unread,
Apr 12, 2017, 2:56:10 PM4/12/17
to ns-3-users
Hello All,

My simulation is interacting with a real world controller, and I'd like to bring the sim (virtual ) clock up as close to real time as I can get it. I won't go into those details here, as I think they'd just distract from the problem at hand.

I'm running 3.26 on an Ubuntu 16.04 machine, and haven't had any trouble getting realtime behavior to operate as intended. However, as we know, the virtual clock (RealtimeSimulatorImpl.m_currentTs) starts at 0, and discretely jumps upward as events are processed from the event queue. I'd like these discrete jumps to start at a realtime stamp to give the illusion of a real clock.

I see two broad strategies.

1.) Initialize m_currentTs to the value returned by WallClockSynchronizer.GetCurrentRealtime().

Benefit: Setting m_currentTs early like this takes advantage of the relative nature of the scheduler timing, ie i don't have to touch the behind the scenes scheduling, which I like since I don't fully understand what's being scheduled, how, when, etc.

Drawback: The time difference between m_currentTs and WallClockSynchronizer's m_realtimeOriginNano will be (based on my simulation code), a few hundred ms, with the origin time being ~200ms or so after m_currentTs. This is causing problems in synchronization, specifically in DoGetDrift, where I'm returning a monster negative, and thus spinwait forever.

Solution? I think my solution here would need to start with RealtimeSimulatorImpl's ProcessOneEvent function, specifically in setting tsNow. Since tsNow assumes the virtual clock was initialized to 0, I'm setting to GetCurrentRealtime() - the synchronizer's m_realtimeOriginNano (once I made that member variable public). This gets me past where I was, but eventually leads to an ASSERT when somebody tries to schedule an event that would occur in the past (after m_currentTs). So that's where I'm stuck. I'm not sure if the root of my issue that the origin timestamp is after the virtual clock's timestamp, if the sync module inherently assumes a virtual clock counting up from zero, or both. Probably both.

2.) Allow m_currentTs to be initialized to zero, but force it up to the sync's origin time right as the WallClockSynchronizer calls DoSetOrigin().

Benefit: This method would rid us of the ~200ms disparity between the origin timestamp ("timestamp", i know it's a 64bit int) and the m_currentTs virtual clock.

Drawback: Everything else. All of the scheduling done by the program would have to be redone, as it would have been done relative to a 0 containing clock. I can manually calculate when to schedule my application events, but there are something like 40 or 50 events in the event queue when the sim first begins running, and fewer than 10 of those are mine (application, end of simulation, etc). Further, I'll have a new problem with the origin time, described below.

Solution? If (A) I manually get the real time, set m_currentTs to it, reschedule everything, and then set the origin time, I'll have the same problem as method 1: an origin time that's further along the timeline than the virtual clock. This would effectively just decrease that ~200ms down to say 5ms and I'll have the same forever spinlock wait as above.
If (B) I set the origin time, then manually get the real time, set m_currentTs, reschedule everything, then begin processing the event queue, I'm increasing the disparity between the origin timestamp and the event queue checks.

So, I'd like to ask if anyone has been through this before and can point me in the right direction. Or if any of the devs/ those with a deeper understanding of NS3 would be willing to brainstorm a solution with me.

Thanks for your attention, I hope your own work is going well.

Stefan

pdbarnes

unread,
Apr 13, 2017, 12:44:48 AM4/13/17
to ns-3-users
I'm confused by your question. AFAIK the RealtimeScheduler already handles the offset between real time at simulation time, more or less your approach A.

If you're seeing 200 ms between real time and simulation time I'd look in a few places. Are you running in a virtual machine? Is your kernel configured with a small tick quantum? Does it match what's claimed for clock rate in the appropriate header?

Peter

Stefan Jevtic

unread,
Apr 13, 2017, 12:02:59 PM4/13/17
to ns-3-users
Thanks for your response, and I'm sorry I was unclear/ incorrect in my original post.

My goal is for the virtual clock to contain the same value as the wall clock.

IE- if I begin running my simulation at 11:45 AM EST on April 13, 2017, I'd like to see

10.018948 ARP, Request who-has 10.1.1.5 (ff:ff:ff:ff:ff:ff) tell 10.1.1.1, length 50
10.018948 ARP, Reply 10.1.1.5 is-at 00:00:00:00:00:09, length 50
10.039821 IP 10.1.1.1.49153 > 10.1.1.5.9: UDP, length 1024
11.006256 IP 10.1.1.1.49153 > 10.1.1.5.9: UDP, length 1024

become something like

1492098185.862711 ARP, Request who-has 10.1.1.5 (ff:ff:ff:ff:ff:ff) tell 10.1.1.1, length 50
1492098185.863821 ARP, Reply 10.1.1.5 is-at 00:00:00:00:00:09, length 50
1492098185.872711 IP 10.1.1.1.49153 > 10.1.1.5.9: UDP, length 1024
1492098186.862711 IP 10.1.1.1.49153 > 10.1.1.5.9: UDP, length 1024

I'd like to preserve the perfect pacing I'm observing (I'm not having synchronization issues caused by inordinately small quanta or incorrectly reported clock rates). The 200ms I spoke about is the time difference between the RealtimeImpl being initialized and the SetOrigin timestamp, and only becomes a factor when the RealtimeImpl initializes its m_currentTs to WallClockSynchronizer.GetCurrentRealtime(). I think perhaps your other questions have been cleared up with this clarification of my question.

pdbarnes

unread,
Apr 21, 2017, 3:44:52 PM4/21/17
to ns-3-users


On Thursday, April 13, 2017 at 9:02:59 AM UTC-7, Stefan Jevtic wrote:
Thanks for your response, and I'm sorry I was unclear/ incorrect in my original post.

My goal is for the virtual clock to contain the same value as the wall clock.

Since the RealtimeScheduler is best effort (it can't really be anything else), you can't guarantee that the simulation can keep up with wall time.  If the simulator takes too long, it will fall behind.  As a consequence you can't count on the internal simulation time matching wall clock time, even if they start synchronized.  The current behavior is to record the offset at the start of the simulation, then use that to relate wall clock time to simulation time, in order to execute simulation events at the appropriate wall clock time.  There isn't a perfect solution to this problem.  The consequences of falling behind depend on the reason you're trying to run in real time. Take a look at how the enum SynchronizationMode is used to indicate two policies:  continue no matter how far behind we get, or fatal error if we fall too far behind. 

The 200 ms persistent offset you see is puzzling; I suspect it's either a bug (not obvious how, though) or an artifact of the details of your system, which might be correctable, or at least reduced.

As you say, trying to keep the virtual time value equal to wall clock time isn't going to be easy.  As you note the simulator (and model code) implicitly assumes that simulator time starts at 0, with the result that models schedule initialization events for delay 0, when really they should be scheduled for an epoch "before simulation time," just as ScheduleDestroy() runs events at an epoch "after simulation time."  The general fix, which would help you as well, is to add ScheduleAtStart(const PtrEventImpl > &event) [and perhaps add the parallel ScheduleAtEnd() which would run after Simulator::Stop, before returning to the main script].  With that done, one could then add Simulator::SetStartTime() which will explicitly set the initial value of m_currentTs. (Setting the start time might require rescheduling any events currently in the Scheduler; see SetScheduler for something very similar).  Events scheduled with Schedule(Time delay...) will be scheduled relative to the current time, which would now have the wall clock offset built in.

Peter
Reply all
Reply to author
Forward
0 new messages