A Discrete-Event Network Simulator
API
null-message-simulator-impl.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright 2013. Lawrence Livermore National Security, LLC.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Steven Smith <smith84@llnl.gov>
19  *
20  */
21 
23 
26 #include "remote-channel-bundle.h"
27 #include "mpi-interface.h"
28 
29 #include <ns3/simulator.h>
30 #include <ns3/scheduler.h>
31 #include <ns3/event-impl.h>
32 #include <ns3/channel.h>
33 #include <ns3/node-container.h>
34 #include <ns3/double.h>
35 #include <ns3/ptr.h>
36 #include <ns3/pointer.h>
37 #include <ns3/assert.h>
38 #include <ns3/log.h>
39 
40 #include <cmath>
41 #include <iostream>
42 #include <fstream>
43 #include <iomanip>
44 
45 namespace ns3 {
46 
47 NS_LOG_COMPONENT_DEFINE ("NullMessageSimulatorImpl");
48 
49 NS_OBJECT_ENSURE_REGISTERED (NullMessageSimulatorImpl);
50 
51 NullMessageSimulatorImpl* NullMessageSimulatorImpl::g_instance = 0;
52 
53 TypeId
55 {
56  static TypeId tid = TypeId ("ns3::NullMessageSimulatorImpl")
58  .SetGroupName ("Mpi")
59  .AddConstructor<NullMessageSimulatorImpl> ()
60  .AddAttribute ("SchedulerTune", "Null Message scheduler tuning parameter",
61  DoubleValue (1.0),
63  MakeDoubleChecker<double> (0.01,1.0))
64  ;
65  return tid;
66 }
67 
69 {
70 #ifdef NS3_MPI
71  NS_LOG_FUNCTION (this);
72 
75 
76  m_stop = false;
77  // uids are allocated from 4.
78  // uid 0 is "invalid" events
79  // uid 1 is "now" events
80  // uid 2 is "destroy" events
81  m_uid = 4;
82  // before ::Run is entered, the m_currentUid will be zero
83  m_currentUid = 0;
84  m_currentTs = 0;
87  m_eventCount = 0;
88  m_events = 0;
89 
90  m_safeTime = Seconds (0);
91 
92  NS_ASSERT (g_instance == 0);
93  g_instance = this;
94 
95 #else
96  NS_FATAL_ERROR ("Can't use Null Message simulator without MPI compiled in");
97 #endif
98 }
99 
101 {
102  NS_LOG_FUNCTION (this);
103 }
104 
105 void
107 {
108  NS_LOG_FUNCTION (this);
109 
110  while (!m_events->IsEmpty ())
111  {
112  Scheduler::Event next = m_events->RemoveNext ();
113  next.impl->Unref ();
114  }
115  m_events = 0;
117 }
118 
119 void
121 {
122  NS_LOG_FUNCTION (this);
123 
124  while (!m_destroyEvents.empty ())
125  {
126  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
127  m_destroyEvents.pop_front ();
128  NS_LOG_LOGIC ("handle destroy " << ev);
129  if (!ev->IsCancelled ())
130  {
131  ev->Invoke ();
132  }
133  }
134 
137 }
138 
139 void
141 {
142  NS_LOG_FUNCTION (this);
143 
144  int num_local_nodes = 0;
145 
146  if (MpiInterface::GetSize () > 1)
147  {
149  for (NodeContainer::Iterator iter = c.Begin (); iter != c.End (); ++iter)
150  {
151  if ((*iter)->GetSystemId () != MpiInterface::GetSystemId ())
152  {
153  continue;
154  }
155 
156  num_local_nodes++;
157 
158  for (uint32_t i = 0; i < (*iter)->GetNDevices (); ++i)
159  {
160  Ptr<NetDevice> localNetDevice = (*iter)->GetDevice (i);
161  // only works for p2p links currently
162  if (!localNetDevice->IsPointToPoint ())
163  {
164  continue;
165  }
166  Ptr<Channel> channel = localNetDevice->GetChannel ();
167  if (channel == 0)
168  {
169  continue;
170  }
171 
172  // grab the adjacent node
173  Ptr<Node> remoteNode;
174  if (channel->GetDevice (0) == localNetDevice)
175  {
176  remoteNode = (channel->GetDevice (1))->GetNode ();
177  }
178  else
179  {
180  remoteNode = (channel->GetDevice (0))->GetNode ();
181  }
182 
183  // if it's not remote, don't consider it
184  if (remoteNode->GetSystemId () == MpiInterface::GetSystemId ())
185  {
186  continue;
187  }
188 
192  Ptr<RemoteChannelBundle> remoteChannelBundle = RemoteChannelBundleManager::Find (remoteNode->GetSystemId ());
193  if (!remoteChannelBundle)
194  {
195  remoteChannelBundle = RemoteChannelBundleManager::Add (remoteNode->GetSystemId ());
196  }
197 
198  TimeValue delay;
199  channel->GetAttribute ("Delay", delay);
200  remoteChannelBundle->AddChannel (channel, delay.Get () );
201  }
202  }
203  }
204 
205  // Completed setup of remote channel bundles. Setup send and receive buffers.
207 
208  // Initialized to 0 as we don't have a simulation start time.
209  m_safeTime = Time (0);
210 }
211 
212 void
214 {
215  NS_LOG_FUNCTION (this << schedulerFactory);
216 
217  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
218 
219  if (m_events != 0)
220  {
221  while (!m_events->IsEmpty ())
222  {
223  Scheduler::Event next = m_events->RemoveNext ();
224  scheduler->Insert (next);
225  }
226  }
227  m_events = scheduler;
228 }
229 
230 void
232 {
233  NS_LOG_FUNCTION (this);
234 
235  Scheduler::Event next = m_events->RemoveNext ();
236 
237  NS_ASSERT (next.key.m_ts >= m_currentTs);
239  m_eventCount++;
240 
241  NS_LOG_LOGIC ("handle " << next.key.m_ts);
242  m_currentTs = next.key.m_ts;
244  m_currentUid = next.key.m_uid;
245  next.impl->Invoke ();
246  next.impl->Unref ();
247 }
248 
249 bool
251 {
252  return m_events->IsEmpty () || m_stop;
253 }
254 
255 Time
257 {
258  NS_LOG_FUNCTION (this);
259 
260  NS_ASSERT (!m_events->IsEmpty ());
261 
262  Scheduler::Event ev = m_events->PeekNext ();
263  return TimeStep (ev.key.m_ts);
264 }
265 
266 void
268 {
269  NS_LOG_FUNCTION (this << bundle);
270 
271  Time delay (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
272 
274  this, PeekPointer(bundle)));
275 }
276 
277 void
279 {
280  NS_LOG_FUNCTION (this << bundle);
281 
282  Simulator::Cancel (bundle->GetEventId ());
283 
284  Time delay (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
285 
287  this, PeekPointer(bundle)));
288 }
289 
290 void
292 {
293  NS_LOG_FUNCTION (this << nodeSysId);
294 
296  NS_ASSERT (bundle);
297 
299 }
300 
301 void
303 {
304  NS_LOG_FUNCTION (this);
305 
307 
309 
310  // Stop will be set if stop is called by simulation.
311  m_stop = false;
312  while (!IsFinished ())
313  {
314  Time nextTime = Next ();
315 
316  if ( nextTime <= GetSafeTime () )
317  {
318  ProcessOneEvent ();
320  }
321  else
322  {
323  // Block until packet or Null Message has been received.
325  }
326  }
327 }
328 
329 void
331 {
332  NS_LOG_FUNCTION (this);
333 
335 
337 
338  // Check for send completes
340 }
341 
342 void
344 {
345  NS_LOG_FUNCTION (this);
346 
348 
350 
351  // Check for send completes
353 }
354 
355 void
357 {
358  NS_LOG_FUNCTION (this);
359 
362 }
363 
364 Time
366 {
367  return m_safeTime;
368 }
369 
370 
371 uint32_t
373 {
374  return m_myId;
375 }
376 
377 void
379 {
380  NS_LOG_FUNCTION (this);
381 
382  ProcessOneEvent ();
383 }
384 
385 void
387 {
388  NS_LOG_FUNCTION (this);
389 
390  m_stop = true;
391 }
392 
393 void
395 {
396  NS_LOG_FUNCTION (this << delay.GetTimeStep ());
397 
399 }
400 
401 //
402 // Schedule an event for a _relative_ time in the future.
403 //
404 EventId
406 {
407  NS_LOG_FUNCTION (this << delay.GetTimeStep () << event);
408 
409  Time tAbsolute = delay + TimeStep (m_currentTs);
410 
411  NS_ASSERT (tAbsolute.IsPositive ());
412  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
413  Scheduler::Event ev;
414  ev.impl = event;
415  ev.key.m_ts = static_cast<uint64_t> (tAbsolute.GetTimeStep ());
416  ev.key.m_context = GetContext ();
417  ev.key.m_uid = m_uid;
418  m_uid++;
420  m_events->Insert (ev);
421  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
422 }
423 
424 void
425 NullMessageSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *event)
426 {
427  NS_LOG_FUNCTION (this << context << delay.GetTimeStep () << m_currentTs << event);
428 
429  Time tAbsolute(m_currentTs + delay.GetTimeStep ());
430 
431  NS_ASSERT (tAbsolute.IsPositive ());
432  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
433 
434  Scheduler::Event ev;
435  ev.impl = event;
436  ev.key.m_ts = tAbsolute.GetTimeStep ();
437  ev.key.m_context = context;
438  ev.key.m_uid = m_uid;
439  m_uid++;
441  m_events->Insert (ev);
442 }
443 
444 EventId
446 {
447  NS_LOG_FUNCTION (this << event);
448 
449  Scheduler::Event ev;
450  ev.impl = event;
451  ev.key.m_ts = m_currentTs;
452  ev.key.m_context = GetContext ();
453  ev.key.m_uid = m_uid;
454  m_uid++;
456  m_events->Insert (ev);
457  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
458 }
459 
460 EventId
462 {
463  NS_LOG_FUNCTION (this << event);
464 
465  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
466  m_destroyEvents.push_back (id);
467  m_uid++;
468  return id;
469 }
470 
471 Time
473 {
474  return TimeStep (m_currentTs);
475 }
476 
477 Time
479 {
480  if (IsExpired (id))
481  {
482  return TimeStep (0);
483  }
484  else
485  {
486  return TimeStep (id.GetTs () - m_currentTs);
487  }
488 }
489 
490 void
492 {
493  if (id.GetUid () == 2)
494  {
495  // destroy events.
496  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
497  {
498  if (*i == id)
499  {
500  m_destroyEvents.erase (i);
501  break;
502  }
503  }
504  return;
505  }
506  if (IsExpired (id))
507  {
508  return;
509  }
510  Scheduler::Event event;
511  event.impl = id.PeekEventImpl ();
512  event.key.m_ts = id.GetTs ();
513  event.key.m_context = id.GetContext ();
514  event.key.m_uid = id.GetUid ();
515  m_events->Remove (event);
516  event.impl->Cancel ();
517  // whenever we remove an event from the event list, we have to unref it.
518  event.impl->Unref ();
519 
521 }
522 
523 void
525 {
526  if (!IsExpired (id))
527  {
528  id.PeekEventImpl ()->Cancel ();
529  }
530 }
531 
532 bool
534 {
535  if (id.GetUid () == 2)
536  {
537  if (id.PeekEventImpl () == 0
538  || id.PeekEventImpl ()->IsCancelled ())
539  {
540  return true;
541  }
542  // destroy events.
543  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
544  {
545  if (*i == id)
546  {
547  return false;
548  }
549  }
550  return true;
551  }
552  if (id.PeekEventImpl () == 0
553  || id.GetTs () < m_currentTs
554  || (id.GetTs () == m_currentTs
555  && id.GetUid () <= m_currentUid)
556  || id.PeekEventImpl ()->IsCancelled ())
557  {
558  return true;
559  }
560  else
561  {
562  return false;
563  }
564 }
565 
566 Time
568 {
569  // XXX: I am fairly certain other compilers use other non-standard
570  // post-fixes to indicate 64 bit constants.
571  return TimeStep (0x7fffffffffffffffLL);
572 }
573 
574 uint32_t
576 {
577  return m_currentContext;
578 }
579 
580 uint64_t
582 {
583  return m_eventCount;
584 }
585 
587 {
589  NS_ASSERT (bundle);
590 
591  return Min (NullMessageSimulatorImpl::GetInstance ()->Next (), GetSafeTime ()) + bundle->GetDelay ();
592 }
593 
595 {
596  NS_LOG_FUNCTION (this << bundle);
597 
598  Time time = Min (Next (), GetSafeTime ()) + bundle->GetDelay ();
600 
601  ScheduleNullMessageEvent (bundle);
602 }
603 
604 
607 {
608  NS_ASSERT (g_instance != 0);
609  return g_instance;
610 }
611 } // namespace ns3
612 
Time CalculateGuaranteeTime(uint32_t systemId)
virtual void Remove(const EventId &id)
Remove an event from the event list.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void Unref(void) const
Decrement the reference count.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
std::vector< Ptr< Node > >::const_iterator Iterator
Node container iterator.
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:81
void HandleArrivingMessagesNonBlocking(void)
Non blocking receive of pending messages.
virtual EventId ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:94
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:564
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:204
virtual bool IsFinished(void) const
Check if the simulation should finish.
static void ReceiveMessagesNonBlocking()
Non-blocking check for received messages complete.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event&#39;s associated function will not be invoked when it expires...
Definition: simulator.cc:290
void ProcessOneEvent(void)
Process the next event on the queue.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:743
void RescheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
Collection of NS3 channels between local and remote nodes.
Iterator End(void) const
Get an iterator which indicates past-the-last Node in the container.
virtual EventId ScheduleDestroy(EventImpl *event)
Schedule an event to run at the end of the simulation, after the Stop() time or condition has been re...
virtual uint32_t GetContext(void) const
Get the current simulation context.
channel
Definition: third.py:85
void CalculateSafeTime(void)
Calculate the SafeTime.
void Invoke(void)
Called by the simulation engine to notify the event that it is time to execute.
Definition: event-impl.cc:46
static NullMessageSimulatorImpl * GetInstance(void)
static void TestSendComplete()
Check for completed sends.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:197
static EventId Schedule(Time const &delay, MEM mem_ptr, OBJ obj)
Schedule an event to expire after delay.
Definition: simulator.h:1389
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:95
static void Destroy()
Deletes storage used by the parallel environment.
AttributeValue implementation for Time.
Definition: nstime.h:1124
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
uint32_t m_uid
Event unique id.
Definition: scheduler.h:82
static void SendNullMessage(const Time &guaranteeUpdate, Ptr< RemoteChannelBundle > bundle)
Send a Null Message to across the specified bundle.
static void InitializeNullMessageEvents(void)
Setup initial Null Message events for every RemoteChannelBundle.
Time GetSafeTime(void)
Get the current SafeTime; the maximum time that events can be processed based on information received...
Maintain the event list.
Definition: scheduler.h:66
virtual uint64_t GetEventCount(void) const
Get the number of events executed.
static void Destroy(void)
Destroy the singleton.
virtual void Run(void)
Run the simulation.
static NullMessageSimulatorImpl * g_instance
virtual bool IsExpired(const EventId &id) const
Check if an event has already run or been cancelled.
Scheduler event.
Definition: scheduler.h:92
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void CalculateLookAhead(void)
Calculate the look ahead allowable for this MPI task.
keep track of a set of node pointers.
static void ReceiveMessagesBlocking()
Blocking message receive.
virtual void ScheduleWithContext(uint32_t context, Time const &delay, EventImpl *event)
Schedule a future event execution (in a different context).
uint32_t GetSystemId(void) const
Definition: node.cc:121
static Ptr< RemoteChannelBundle > Find(uint32_t systemId)
void HandleArrivingMessagesBlocking(void)
Blocking receive of arriving messages.
virtual Time Now(void) const
Return the current simulation virtual time.
Time TimeStep(uint64_t ts)
Definition: nstime.h:1119
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
static Ptr< RemoteChannelBundle > Add(uint32_t systemId)
Add RemoteChannelBundle from this task to MPI task on other side of the link.
Simulator implementation using MPI and a Null Message algorithm.
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: double.h:42
static NodeContainer GetGlobal(void)
Create a NodeContainer that contains a list of all nodes created through NodeContainer::Create() and ...
Instantiate subclasses of ns3::Object.
A simulation event.
Definition: event-impl.h:44
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
An identifier for simulation events.
Definition: event-id.h:53
static uint32_t GetSystemId()
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:178
Time Get(void) const
Definition: time.cc:443
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1062
virtual void Cancel(const EventId &id)
Set the cancel bit on this event: the event&#39;s associated function will not be invoked when it expires...
void ScheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
Flag for events not associated with any particular context.
Definition: simulator.h:198
void NullMessageEventHandler(RemoteChannelBundle *bundle)
virtual EventId Schedule(Time const &delay, EventImpl *event)
Schedule a future event execution (in the same context).
virtual void DoDispose(void)
Destructor implementation.
static void InitializeSendReceiveBuffers(void)
Initialize send and receive buffers.
This class can be used to hold variables of floating point type such as &#39;double&#39; or &#39;float&#39;...
Definition: double.h:41
a unique identifier for an interface.
Definition: type-id.h:58
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:915
static uint32_t GetSize()
uint32_t m_context
Event context.
Definition: scheduler.h:83
Iterator Begin(void) const
Get an iterator which refers to the first Node in the container.
The SimulatorImpl base class.
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:391