00001 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 00002 /* 00003 * Copyright (c) 2008 University of Washington 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation; 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 */ 00018 00019 #include <time.h> 00020 #include <sys/time.h> 00021 00022 #include "ns3/log.h" 00023 #include "ns3/system-condition.h" 00024 00025 #include "wall-clock-synchronizer.h" 00026 00027 NS_LOG_COMPONENT_DEFINE ("WallClockSynchronizer"); 00028 00029 namespace ns3 { 00030 00031 WallClockSynchronizer::WallClockSynchronizer () 00032 { 00033 NS_LOG_FUNCTION_NOARGS (); 00034 // 00035 // In Linux, the basic timekeeping unit is derived from a variable called HZ 00036 // HZ is the frequency in hertz of the system timer. The system timer fires 00037 // every 1/HZ seconds and a counter, called the jiffies counter is incremented 00038 // at each tick. The time between ticks is called a jiffy (American slang for 00039 // a short period of time). The ticking of the jiffies counter is how the 00040 // the kernel tells time. 00041 // 00042 // Now, the shortest time the kernel can sleep is one jiffy since a timer 00043 // has to be set to expire and trigger the process to be made ready. The 00044 // Posix clock CLOCK_REALTIME is defined as a 1/HZ clock, so by doing a 00045 // clock_getres () on the realtime clock we can infer the scheduler quantum 00046 // and the minimimum sleep time for the system. This is most certainly NOT 00047 // going to be one nanosecond even though clock_nanosleep () pretends it is. 00048 // 00049 // The reason this number is important is that we are going to schedule lots 00050 // of waits for less time than a jiffy. The clock_nanosleep function is 00051 // going to guarantee that it will sleep for AT LEAST the time specified. 00052 // The least time that it will sleep is a jiffy. 00053 // 00054 // In order to deal with this, we are going to do a spin-wait if the simulator 00055 // requires a delay less than a jiffy. This is on the order of one millisecond 00056 // (999848 ns) on the ns-regression machine. 00057 // 00058 // If the underlying OS does not support posix clocks, we'll just assume a 00059 // one millisecond quantum and deal with this as best we can 00060 00061 #ifdef CLOCK_REALTIME 00062 struct timespec ts; 00063 clock_getres (CLOCK_REALTIME, &ts); 00064 m_jiffy = ts.tv_sec * NS_PER_SEC + ts.tv_nsec; 00065 NS_LOG_INFO ("Jiffy is " << m_jiffy << " ns"); 00066 #else 00067 m_jiffy = 1000000; 00068 #endif 00069 } 00070 00071 WallClockSynchronizer::~WallClockSynchronizer () 00072 { 00073 NS_LOG_FUNCTION_NOARGS (); 00074 } 00075 00076 bool 00077 WallClockSynchronizer::DoRealtime (void) 00078 { 00079 NS_LOG_FUNCTION_NOARGS (); 00080 return true; 00081 } 00082 00083 uint64_t 00084 WallClockSynchronizer::DoGetCurrentRealtime (void) 00085 { 00086 NS_LOG_FUNCTION_NOARGS (); 00087 return GetNormalizedRealtime (); 00088 } 00089 00090 void 00091 WallClockSynchronizer::DoSetOrigin (uint64_t ns) 00092 { 00093 NS_LOG_FUNCTION_NOARGS (); 00094 // 00095 // In order to make sure we're really locking the simulation time to some 00096 // wall-clock time, we need to be able to compare that simulation time to 00097 // that wall-clock time. The wall clock will have been running for some 00098 // long time and will probably have a huge count of nanoseconds in it. We 00099 // save the real time away so we can subtract it from "now" later and get 00100 // a count of nanoseconds in real time since the simulation started. 00101 // 00102 m_realtimeOriginNano = GetRealtime (); 00103 NS_LOG_INFO ("origin = " << m_realtimeOriginNano); 00104 } 00105 00106 int64_t 00107 WallClockSynchronizer::DoGetDrift (uint64_t ns) 00108 { 00109 NS_LOG_FUNCTION_NOARGS (); 00110 // 00111 // In order to make sure we're really locking the simulation time to some 00112 // wall-clock time, we need to be able to compare that simulation time to 00113 // that wall-clock time. In DoSetOrigin we saved the real time at the start 00114 // of the simulation away. This is the place where we subtract it from "now" 00115 // to a count of nanoseconds in real time since the simulation started. We 00116 // then subtract the current real time in normalized nanoseconds we just got 00117 // from the normalized simulation time in nanoseconds that is passed in as 00118 // the parameter ns. We return an integer difference, but in reality all of 00119 // the mechanisms that cause wall-clock to simuator time drift cause events 00120 // to be late. That means that the wall-clock will be higher than the 00121 // simulation time and drift will be positive. I would be astonished to 00122 // see a negative drift, but the possibility is admitted for other 00123 // implementations; and we'll use the ability to report an early result in 00124 // DoSynchronize below. 00125 // 00126 uint64_t nsNow = GetNormalizedRealtime (); 00127 00128 if (nsNow > ns) 00129 { 00130 // 00131 // Real time (nsNow) is larger/later than the simulator time (ns). We are 00132 // behind real time and the difference (drift) is positive. 00133 // 00134 return (int64_t)(nsNow - ns); 00135 } 00136 else 00137 { 00138 // 00139 // Real time (nsNow) is smaller/earlier than the simulator time (ns). We are 00140 // ahead of real time and the difference (drift) is negative. 00141 // 00142 return -(int64_t)(ns - nsNow); 00143 } 00144 } 00145 00146 bool 00147 WallClockSynchronizer::DoSynchronize (uint64_t nsCurrent, uint64_t nsDelay) 00148 { 00149 NS_LOG_FUNCTION_NOARGS (); 00150 // 00151 // This is the belly of the beast. We have received two parameters from the 00152 // simulator proper -- a current simulation time (nsCurrent) and a simulation 00153 // time to delay which identifies the time the next event is supposed to fire. 00154 // 00155 // The first thing we need to do is to (try and) correct for any realtime 00156 // drift that has happened in the system. In this implementation, we realize 00157 // that all mechanisms for drift will cause the drift to be such that the 00158 // realtime is greater than the simulation time. This typically happens when 00159 // our process is put to sleep for a given time, but actually sleeps for 00160 // longer. So, what we want to do is to "catch up" to realtime and delay for 00161 // less time than we are actually asked to delay. DriftCorrect will return a 00162 // number from 0 to nsDelay corresponding to the amount of catching-up we 00163 // need to do. If we are more than nsDelay behind, we do not wait at all. 00164 // 00165 // Note that it will be impossible to catch up if the amount of drift is 00166 // cumulatively greater than the amount of delay between events. The method 00167 // GetDrift () is available to clients of the syncrhonizer to keep track of 00168 // the cumulative drift. The client can assert if the drift gets out of 00169 // hand, print warning messages, or just ignore the situation and hope it will 00170 // go away. 00171 // 00172 uint64_t ns = DriftCorrect (nsCurrent, nsDelay); 00173 NS_LOG_INFO ("Synchronize ns = " << ns); 00174 // 00175 // Once we've decided on how long we need to delay, we need to split this 00176 // time into sleep waits and busy waits. The reason for this is described 00177 // in the comments for the constructor where jiffies and jiffy resolution is 00178 // explained. 00179 // 00180 // Here, I'll just say that we need that the jiffy is the minimum resolution 00181 // of the system clock. It can only sleep in blocks of time equal to a jiffy. 00182 // If we want to be more accurate than a jiffy (we do) then we need to sleep 00183 // for some number of jiffies and then busy wait for any leftover time. 00184 // 00185 uint64_t numberJiffies = ns / m_jiffy; 00186 NS_LOG_INFO ("Synchronize numberJiffies = " << numberJiffies); 00187 // 00188 // This is where the real world interjects its very ugly head. The code 00189 // immediately below reflects the fact that a sleep is actually quite probably 00190 // going to end up sleeping for some number of jiffies longer than you wanted. 00191 // This is because your system is going to be off doing other unimportant 00192 // stuff during that extra time like running file systems and networks. What 00193 // we want to do is to ask the system to sleep enough less than the requested 00194 // delay so that it comes back early most of the time (coming back early is 00195 // fine, coming back late is bad). If we can convince the system to come back 00196 // early (most of the time), then we can busy-wait until the requested 00197 // completion time actually comes around (most of the time). 00198 // 00199 // The tradeoff here is, of course, that the less time we spend sleeping, the 00200 // more accurately we will sync up; but the more CPU time we will spend busy 00201 // waiting (doing nothing). 00202 // 00203 // I'm not really sure about this number -- a boss of mine once said, "pick 00204 // a number and it'll be wrong." But this works for now. 00205 // 00206 // XXX BUGBUG Hardcoded tunable parameter below. 00207 // 00208 if (numberJiffies > 3) 00209 { 00210 NS_LOG_INFO ("SleepWait for " << numberJiffies * m_jiffy << " ns"); 00211 NS_LOG_INFO ("SleepWait until " << nsCurrent + numberJiffies * m_jiffy 00212 << " ns"); 00213 // 00214 // SleepWait is interruptible. If it returns true it meant that the sleep 00215 // went until the end. If it returns false, it means that the sleep was 00216 // interrupted by a Signal. In this case, we need to return and let the 00217 // simulator re-evaluate what to do. 00218 // 00219 if (SleepWait ((numberJiffies - 3) * m_jiffy) == false) 00220 { 00221 NS_LOG_INFO ("SleepWait interrupted"); 00222 return false; 00223 } 00224 } 00225 NS_LOG_INFO ("Done with SleepWait"); 00226 // 00227 // We asked the system to sleep for some number of jiffies, but that doesn't 00228 // mean we actually did. Let's re-evaluate what we need to do here. Maybe 00229 // we're already late. Probably the "real" delay time left has little to do 00230 // with what we would calculate it to be naively. 00231 // 00232 // We are now at some Realtime. The important question now is not, "what 00233 // would we calculate in a mathematicians paradise," it is, "how many 00234 // nanoseconds do we need to busy-wait until we get to the Realtime that 00235 // corresponds to nsCurrent + nsDelay (in simulation time). We have a handy 00236 // function to do just that -- we ask for the time the realtime clock has 00237 // drifted away from the simulation clock. That's our answer. If the drift 00238 // is negative, we're early and we need to busy wait for that number of 00239 // nanoseconds. The place were we want to be is described by the parameters 00240 // we were passed by the simulator. 00241 // 00242 int64_t nsDrift = DoGetDrift (nsCurrent + nsDelay); 00243 // 00244 // If the drift is positive, we are already late and we need to just bail out 00245 // of here as fast as we can. Return true to indicate that the requested time 00246 // has, in fact, passed. 00247 // 00248 if (nsDrift >= 0) 00249 { 00250 NS_LOG_INFO ("Back from SleepWait: IML8 " << nsDrift); 00251 return true; 00252 } 00253 // 00254 // There are some number of nanoseconds left over and we need to wait until 00255 // the time defined by nsDrift. We'll do a SpinWait since the usual case 00256 // will be that we are doing this Spinwait after we've gotten a rough delay 00257 // using the SleepWait above. If SpinWait completes to the end, it will 00258 // return true; if it is interrupted by a signal it will return false. 00259 // 00260 NS_LOG_INFO ("SpinWait until " << nsCurrent + nsDelay); 00261 return SpinWait (nsCurrent + nsDelay); 00262 } 00263 00264 void 00265 WallClockSynchronizer::DoSignal (void) 00266 { 00267 NS_LOG_FUNCTION_NOARGS (); 00268 00269 m_condition.SetCondition (true); 00270 m_condition.Signal (); 00271 } 00272 00273 void 00274 WallClockSynchronizer::DoSetCondition (bool cond) 00275 { 00276 NS_LOG_FUNCTION_NOARGS (); 00277 m_condition.SetCondition (cond); 00278 } 00279 00280 void 00281 WallClockSynchronizer::DoEventStart (void) 00282 { 00283 NS_LOG_FUNCTION_NOARGS (); 00284 m_nsEventStart = GetNormalizedRealtime (); 00285 } 00286 00287 uint64_t 00288 WallClockSynchronizer::DoEventEnd (void) 00289 { 00290 NS_LOG_FUNCTION_NOARGS (); 00291 return GetNormalizedRealtime () - m_nsEventStart; 00292 } 00293 00294 bool 00295 WallClockSynchronizer::SpinWait (uint64_t ns) 00296 { 00297 NS_LOG_FUNCTION_NOARGS (); 00298 // 00299 // Do a busy-wait until the normalized realtime equals the value passed in 00300 // or the condition variable becomes true. The condition becomes true if 00301 // an outside entity (a network device receives a packet, sets the condition 00302 // and signals the scheduler it needs to re-evaluate). 00303 // 00304 // We just sit here and spin, wasting CPU cycles until we get to the right 00305 // time or are told to leave. 00306 // 00307 for (;;) 00308 { 00309 if (GetNormalizedRealtime () >= ns) 00310 { 00311 return true; 00312 } 00313 if (m_condition.GetCondition ()) 00314 { 00315 return false; 00316 } 00317 } 00318 // Quiet compiler 00319 return true; 00320 } 00321 00322 bool 00323 WallClockSynchronizer::SleepWait (uint64_t ns) 00324 { 00325 NS_LOG_FUNCTION_NOARGS (); 00326 // 00327 // Put our process to sleep for some number of nanoseconds. Typically this 00328 // will be some time equal to an integral number of jiffies. We will usually 00329 // follow a call to SleepWait with a call to SpinWait to get the kind of 00330 // accuracy we want. 00331 // 00332 // We have to have some mechanism to wake up this sleep in case an external 00333 // event happens that causes a schedule event in the simulator. This newly 00334 // scheduled event might be before the time we are waiting until, so we have 00335 // to break out of both the SleepWait and the following SpinWait to go back 00336 // and reschedule/resynchronize taking the new event into account. The 00337 // SystemCondition we have saved in m_condition takes care of this for us. 00338 // 00339 // This call will return if the timeout expires OR if the condition is 00340 // set true by a call to WallClockSynchronizer::SetCondition (true) followed 00341 // by a call to WallClockSynchronizer::Signal(). In either case, we are done 00342 // waiting. If the timeout happened, we TimedWait returns true; if a Signal 00343 // happened, false. 00344 // 00345 return m_condition.TimedWait (ns); 00346 } 00347 00348 uint64_t 00349 WallClockSynchronizer::DriftCorrect (uint64_t nsNow, uint64_t nsDelay) 00350 { 00351 int64_t drift = DoGetDrift (nsNow); 00352 // 00353 // If we're running late, drift will be positive and we need to correct by 00354 // delaying for less time. If we're early for some bizarre reason, we don't 00355 // do anything since we'll almost instantly self-correct. 00356 // 00357 if (drift < 0) 00358 { 00359 return nsDelay; 00360 } 00361 // 00362 // If we've drifted out of sync by less than the requested delay, then just 00363 // subtract the drift from the delay and fix up the drift in one go. If we 00364 // have more drift than delay, then we just play catch up as fast as possible 00365 // by not delaying at all. 00366 // 00367 uint64_t correction = (uint64_t)drift; 00368 if (correction <= nsDelay) 00369 { 00370 return nsDelay - correction; 00371 } 00372 else 00373 { 00374 return 0; 00375 } 00376 } 00377 00378 uint64_t 00379 WallClockSynchronizer::GetRealtime (void) 00380 { 00381 struct timeval tvNow; 00382 gettimeofday (&tvNow, NULL); 00383 return TimevalToNs (&tvNow); 00384 } 00385 00386 uint64_t 00387 WallClockSynchronizer::GetNormalizedRealtime (void) 00388 { 00389 return GetRealtime () - m_realtimeOriginNano; 00390 } 00391 00392 void 00393 WallClockSynchronizer::NsToTimeval (int64_t ns, struct timeval *tv) 00394 { 00395 NS_ASSERT ((ns % US_PER_NS) == 0); 00396 tv->tv_sec = ns / NS_PER_SEC; 00397 tv->tv_usec = (ns % NS_PER_SEC) / US_PER_NS; 00398 } 00399 00400 uint64_t 00401 WallClockSynchronizer::TimevalToNs (struct timeval *tv) 00402 { 00403 uint64_t nsResult = tv->tv_sec * NS_PER_SEC + tv->tv_usec * US_PER_NS; 00404 NS_ASSERT ((nsResult % US_PER_NS) == 0); 00405 return nsResult; 00406 } 00407 00408 void 00409 WallClockSynchronizer::TimevalAdd ( 00410 struct timeval *tv1, 00411 struct timeval *tv2, 00412 struct timeval *result) 00413 { 00414 result->tv_sec = tv1->tv_sec + tv2->tv_sec; 00415 result->tv_usec = tv1->tv_usec + tv2->tv_usec; 00416 if (result->tv_usec > (int64_t)US_PER_SEC) 00417 { 00418 ++result->tv_sec; 00419 result->tv_usec %= US_PER_SEC; 00420 } 00421 } 00422 00423 }; // namespace ns3