/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2008 University of Washington
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef WALL_CLOCK_CLOCK_SYNCHRONIZER_H
#define WALL_CLOCK_CLOCK_SYNCHRONIZER_H
#include "ns3/system-condition.h"
#include "synchronizer.h"
namespace ns3 {
/**
* @brief Class used for synchronizing the simulation events to a real-time
* "wall clock" using Posix Clock functions.
*
* Enable this synchronizer using:
*
* DefaultValue::Bind ("Synchronizer", "WallClockSynchronizer");
*
* before calling any simulator functions.
*
* The simulation clock is maintained as a 64-bit integer in a unit specified
* by the user through the TimeStepPrecision::Set function. This means that
* it is not possible to specify event expiration times with anything better
* than this user-specified accuracy.
*
* There are a couple of more issues at this level. Posix clocks provide
* access to several clocks we could use as a wall clock. We don't care about
* time in the sense of 0430 CEST, we care about some piece of hardware that
* ticks at some regular period. The most accurate posix clock in this
* respect is the CLOCK_PROCESS_CPUTIME_ID clock. This is a high-resolution
* register in the CPU. For example, on Intel machines this corresponds to
* the timestamp counter (TSC) register. The resolution of this counter will
* be on the order of nanoseconds.
*
* Now, just because we can measure time in nanoseconds doesn't mean we can
* put our process to sleep to nanosecond resolution. We are eventually going
* to use the function clock_nanosleep () to sleep until a simulation Time
* specified by the caller.
*
* MORE ON JIFFIES, SLEEP, PROCESSES, etc., as required
*
* Nanosleep takes a struct timespec as an input so we have to deal with
* conversion between Time and struct timespec here. They are both
* interpreted as elapsed times.
*/
class WallClockSynchronizer : public Synchronizer
{
public:
WallClockSynchronizer ();
virtual ~WallClockSynchronizer ();
static const uint64_t US_PER_NS = (uint64_t)1000;
static const uint64_t US_PER_SEC = (uint64_t)1000000;
static const uint64_t NS_PER_SEC = (uint64_t)1000000000;
protected:
/**
* @brief Return true if this synchronizer is actually synchronizing to a
* realtime clock. The simulator sometimes needs to know this.
*
* @internal
*
* Subclasses are expected to implement this method to tell the outside world
* whether or not they are synchronizing to a realtime clock.
*
* @returns True if locked with realtime, false if not.
*/
virtual bool DoRealtime (void);
/**
* @brief Retrieve the value of the origin of the underlying normalized wall
* clock time in nanosecond units.
*
* @internal
*
* Subclasses are expected to implement this method to do the actual
* real-time-clock-specific work of getting the current time.
*
* @returns The normalized wall clock time (in nanosecond units).
* @see TimeStepPrecision::Get
* @see Synchronizer::SetOrigin
*/
virtual uint64_t DoGetCurrentRealtime (void);
/**
* @brief Establish a correspondence between a simulation time and a
* wall-clock (real) time.
*
* @internal
*
* There are three timelines involved here: the simulation time, the
* (absolute) wall-clock time and the (relative) synchronizer real time.
* Calling this method makes a correspondence between the origin of the
* synchronizer time and the current wall-clock time.
*
* This method is expected to be called at the "instant" before simulation
* begins. At this point, simulation time = 0, and synchronizer time is
* set = 0 in this method. We then associate this time with the current
* value of the real time clock that will be used to actually perform the
* synchronization.
*
* Subclasses are expected to implement this method to do the actual
* real-time-clock-specific work of making the correspondence mentioned above.
* for example, this is where the differences between Time parameters and
* parameters to clock_nanosleep would be dealt with.
*
* @param ns The simulation time we need to use as the origin (normalized to
* nanosecond units).
*/
virtual void DoSetOrigin (uint64_t ns);
/**
* @brief Declaration of method used to retrieve drift between the real time
* clock used to synchronize the simulation and the current simulation time.
*
* @internal
*
* @param ns Simulation timestep from the simulator normalized to nanosecond
* steps.
* @returns Drift in nanosecond units.
* @see TimeStepPrecision::Get
* @see Synchronizer::SetOrigin
* @see Synchronizer::GetDrift
*/
virtual int64_t DoGetDrift (uint64_t ns);
/**
* @brief Wait until the real time is in sync with the specified simulation
* time.
*
* @internal
*
* This is where the real work of synchronization is done. The Time passed
* in as a parameter is the simulation time. The job of Synchronize is to
* translate from simulation time to synchronizer time (in a perfect world
* this is the same time) and then figure out how long in real-time it needs
* to wait until that synchronizer / simulation time comes around.
*
* Subclasses are expected to implement this method to do the actual
* real-time-clock-specific work of waiting (either busy-waiting or sleeping,
* or some combination) until the requested simulation time.
*
* @param ns The simulation time we need to wait for (normalized to nanosecond
* units).
* @see TimeStepPrecision::Get
*/
virtual bool DoSynchronize (uint64_t nsCurrent, uint64_t nsDelay);
virtual void DoSignal (void);
virtual void DoSetCondition (bool cond);
virtual void DoEventStart (void);
virtual uint64_t DoEventEnd (void);
bool SpinWait (uint64_t);
bool SleepWait (uint64_t);
uint64_t DriftCorrect (uint64_t nsNow, uint64_t nsDelay);
uint64_t GetRealtime (void);
uint64_t GetNormalizedRealtime (void);
void NsToTimeval (int64_t ns, struct timeval *tv);
uint64_t TimevalToNs (struct timeval *tv);
void TimevalAdd (
struct timeval *tv1,
struct timeval *tv2,
struct timeval *result);
uint64_t m_cpuTick;
uint64_t m_realtimeTick;
uint64_t m_jiffy;
uint64_t m_nsEventStart;
SystemCondition m_condition;
};
}; // namespace ns3
#endif /* WALL_CLOCK_SYNCHRONIZER_H */