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_events = 0;
88 
89  m_safeTime = Seconds (0);
90 
91  NS_ASSERT (g_instance == 0);
92  g_instance = this;
93 
94 #else
95  NS_FATAL_ERROR ("Can't use Null Message simulator without MPI compiled in");
96 #endif
97 }
98 
100 {
101  NS_LOG_FUNCTION (this);
102 }
103 
104 void
106 {
107  NS_LOG_FUNCTION (this);
108 
109  while (!m_events->IsEmpty ())
110  {
111  Scheduler::Event next = m_events->RemoveNext ();
112  next.impl->Unref ();
113  }
114  m_events = 0;
116 }
117 
118 void
120 {
121  NS_LOG_FUNCTION (this);
122 
123  while (!m_destroyEvents.empty ())
124  {
125  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
126  m_destroyEvents.pop_front ();
127  NS_LOG_LOGIC ("handle destroy " << ev);
128  if (!ev->IsCancelled ())
129  {
130  ev->Invoke ();
131  }
132  }
133 
136 }
137 
138 void
140 {
141  NS_LOG_FUNCTION (this);
142 
143  int num_local_nodes = 0;
144 
145  if (MpiInterface::GetSize () > 1)
146  {
148  for (NodeContainer::Iterator iter = c.Begin (); iter != c.End (); ++iter)
149  {
150  if ((*iter)->GetSystemId () != MpiInterface::GetSystemId ())
151  {
152  continue;
153  }
154 
155  num_local_nodes++;
156 
157  for (uint32_t i = 0; i < (*iter)->GetNDevices (); ++i)
158  {
159  Ptr<NetDevice> localNetDevice = (*iter)->GetDevice (i);
160  // only works for p2p links currently
161  if (!localNetDevice->IsPointToPoint ())
162  {
163  continue;
164  }
165  Ptr<Channel> channel = localNetDevice->GetChannel ();
166  if (channel == 0)
167  {
168  continue;
169  }
170 
171  // grab the adjacent node
172  Ptr<Node> remoteNode;
173  if (channel->GetDevice (0) == localNetDevice)
174  {
175  remoteNode = (channel->GetDevice (1))->GetNode ();
176  }
177  else
178  {
179  remoteNode = (channel->GetDevice (0))->GetNode ();
180  }
181 
182  // if it's not remote, don't consider it
183  if (remoteNode->GetSystemId () == MpiInterface::GetSystemId ())
184  {
185  continue;
186  }
187 
191  Ptr<RemoteChannelBundle> remoteChannelBundle = RemoteChannelBundleManager::Find (remoteNode->GetSystemId ());
192  if (!remoteChannelBundle)
193  {
194  remoteChannelBundle = RemoteChannelBundleManager::Add (remoteNode->GetSystemId ());
195  }
196 
197  TimeValue delay;
198  channel->GetAttribute ("Delay", delay);
199  remoteChannelBundle->AddChannel (channel, delay.Get () );
200  }
201  }
202  }
203 
204  // Completed setup of remote channel bundles. Setup send and receive buffers.
206 
207  // Initialized to 0 as we don't have a simulation start time.
208  m_safeTime = Time (0);
209 }
210 
211 void
213 {
214  NS_LOG_FUNCTION (this << schedulerFactory);
215 
216  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
217 
218  if (m_events != 0)
219  {
220  while (!m_events->IsEmpty ())
221  {
222  Scheduler::Event next = m_events->RemoveNext ();
223  scheduler->Insert (next);
224  }
225  }
226  m_events = scheduler;
227 }
228 
229 void
231 {
232  NS_LOG_FUNCTION (this);
233 
234  Scheduler::Event next = m_events->RemoveNext ();
235 
236  NS_ASSERT (next.key.m_ts >= m_currentTs);
238 
239  NS_LOG_LOGIC ("handle " << next.key.m_ts);
240  m_currentTs = next.key.m_ts;
242  m_currentUid = next.key.m_uid;
243  next.impl->Invoke ();
244  next.impl->Unref ();
245 }
246 
247 bool
249 {
250  return m_events->IsEmpty () || m_stop;
251 }
252 
253 Time
255 {
256  NS_LOG_FUNCTION (this);
257 
258  NS_ASSERT (!m_events->IsEmpty ());
259 
260  Scheduler::Event ev = m_events->PeekNext ();
261  return TimeStep (ev.key.m_ts);
262 }
263 
264 void
266 {
267  NS_LOG_FUNCTION (this << bundle);
268 
269  Time delay (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
270 
272  this, PeekPointer(bundle)));
273 }
274 
275 void
277 {
278  NS_LOG_FUNCTION (this << bundle);
279 
280  Simulator::Cancel (bundle->GetEventId ());
281 
282  Time delay (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
283 
285  this, PeekPointer(bundle)));
286 }
287 
288 void
290 {
291  NS_LOG_FUNCTION (this << nodeSysId);
292 
294  NS_ASSERT (bundle);
295 
297 }
298 
299 void
301 {
302  NS_LOG_FUNCTION (this);
303 
305 
307 
308  // Stop will be set if stop is called by simulation.
309  m_stop = false;
310  while (!IsFinished ())
311  {
312  Time nextTime = Next ();
313 
314  if ( nextTime <= GetSafeTime () )
315  {
316  ProcessOneEvent ();
318  }
319  else
320  {
321  // Block until packet or Null Message has been received.
323  }
324  }
325 }
326 
327 void
329 {
330  NS_LOG_FUNCTION (this);
331 
333 
335 
336  // Check for send completes
338 }
339 
340 void
342 {
343  NS_LOG_FUNCTION (this);
344 
346 
348 
349  // Check for send completes
351 }
352 
353 void
355 {
356  NS_LOG_FUNCTION (this);
357 
360 }
361 
362 Time
364 {
365  return m_safeTime;
366 }
367 
368 
369 uint32_t
371 {
372  return m_myId;
373 }
374 
375 void
377 {
378  NS_LOG_FUNCTION (this);
379 
380  ProcessOneEvent ();
381 }
382 
383 void
385 {
386  NS_LOG_FUNCTION (this);
387 
388  m_stop = true;
389 }
390 
391 void
393 {
394  NS_LOG_FUNCTION (this << delay.GetTimeStep ());
395 
397 }
398 
399 //
400 // Schedule an event for a _relative_ time in the future.
401 //
402 EventId
404 {
405  NS_LOG_FUNCTION (this << delay.GetTimeStep () << event);
406 
407  Time tAbsolute = delay + TimeStep (m_currentTs);
408 
409  NS_ASSERT (tAbsolute.IsPositive ());
410  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
411  Scheduler::Event ev;
412  ev.impl = event;
413  ev.key.m_ts = static_cast<uint64_t> (tAbsolute.GetTimeStep ());
414  ev.key.m_context = GetContext ();
415  ev.key.m_uid = m_uid;
416  m_uid++;
418  m_events->Insert (ev);
419  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
420 }
421 
422 void
423 NullMessageSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *event)
424 {
425  NS_LOG_FUNCTION (this << context << delay.GetTimeStep () << m_currentTs << event);
426 
427  Time tAbsolute(m_currentTs + delay.GetTimeStep ());
428 
429  NS_ASSERT (tAbsolute.IsPositive ());
430  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
431 
432  Scheduler::Event ev;
433  ev.impl = event;
434  ev.key.m_ts = tAbsolute.GetTimeStep ();
435  ev.key.m_context = context;
436  ev.key.m_uid = m_uid;
437  m_uid++;
439  m_events->Insert (ev);
440 }
441 
442 EventId
444 {
445  NS_LOG_FUNCTION (this << event);
446 
447  Scheduler::Event ev;
448  ev.impl = event;
449  ev.key.m_ts = m_currentTs;
450  ev.key.m_context = GetContext ();
451  ev.key.m_uid = m_uid;
452  m_uid++;
454  m_events->Insert (ev);
455  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
456 }
457 
458 EventId
460 {
461  NS_LOG_FUNCTION (this << event);
462 
463  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
464  m_destroyEvents.push_back (id);
465  m_uid++;
466  return id;
467 }
468 
469 Time
471 {
472  return TimeStep (m_currentTs);
473 }
474 
475 Time
477 {
478  if (IsExpired (id))
479  {
480  return TimeStep (0);
481  }
482  else
483  {
484  return TimeStep (id.GetTs () - m_currentTs);
485  }
486 }
487 
488 void
490 {
491  if (id.GetUid () == 2)
492  {
493  // destroy events.
494  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
495  {
496  if (*i == id)
497  {
498  m_destroyEvents.erase (i);
499  break;
500  }
501  }
502  return;
503  }
504  if (IsExpired (id))
505  {
506  return;
507  }
508  Scheduler::Event event;
509  event.impl = id.PeekEventImpl ();
510  event.key.m_ts = id.GetTs ();
511  event.key.m_context = id.GetContext ();
512  event.key.m_uid = id.GetUid ();
513  m_events->Remove (event);
514  event.impl->Cancel ();
515  // whenever we remove an event from the event list, we have to unref it.
516  event.impl->Unref ();
517 
519 }
520 
521 void
523 {
524  if (!IsExpired (id))
525  {
526  id.PeekEventImpl ()->Cancel ();
527  }
528 }
529 
530 bool
532 {
533  if (id.GetUid () == 2)
534  {
535  if (id.PeekEventImpl () == 0
536  || id.PeekEventImpl ()->IsCancelled ())
537  {
538  return true;
539  }
540  // destroy events.
541  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
542  {
543  if (*i == id)
544  {
545  return false;
546  }
547  }
548  return true;
549  }
550  if (id.PeekEventImpl () == 0
551  || id.GetTs () < m_currentTs
552  || (id.GetTs () == m_currentTs
553  && id.GetUid () <= m_currentUid)
554  || id.PeekEventImpl ()->IsCancelled ())
555  {
556  return true;
557  }
558  else
559  {
560  return false;
561  }
562 }
563 
564 Time
566 {
567  // XXX: I am fairly certain other compilers use other non-standard
568  // post-fixes to indicate 64 bit constants.
569  return TimeStep (0x7fffffffffffffffLL);
570 }
571 
572 uint32_t
574 {
575  return m_currentContext;
576 }
577 
579 {
581  NS_ASSERT (bundle);
582 
583  return Min (NullMessageSimulatorImpl::GetInstance ()->Next (), GetSafeTime ()) + bundle->GetDelay ();
584 }
585 
587 {
588  NS_LOG_FUNCTION (this << bundle);
589 
590  Time time = Min (Next (), GetSafeTime ()) + bundle->GetDelay ();
592 
593  ScheduleNullMessageEvent (bundle);
594 }
595 
596 
599 {
600  NS_ASSERT (g_instance != 0);
601  return g_instance;
602 }
603 } // namespace ns3
604 
Time CalculateGuaranteeTime(uint32_t systemId)
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
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 "...
#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:202
Iterator End(void) const
Get an iterator which indicates past-the-last Node in the container.
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:346
void ProcessOneEvent(void)
Process the next event on the queue.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:733
void RescheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
Collection of NS3 channels between local and remote nodes.
uint32_t GetSystemId(void) const
Definition: node.cc:121
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...
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.
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:197
virtual bool IsFinished(void) const
Check if the simulation should finish.
static EventId Schedule(Time const &delay, MEM mem_ptr, OBJ obj)
Schedule an event to expire after delay.
Definition: simulator.h:1381
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:1069
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
uint32_t m_uid
Event unique id.
Definition: scheduler.h:82
void Unref(void) const
Decrement the reference count.
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
static void Destroy(void)
Destroy the singleton.
virtual void Run(void)
Run the simulation.
static NullMessageSimulatorImpl * g_instance
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.
Iterator Begin(void) const
Get an iterator which refers to the first Node in the container.
virtual void ScheduleWithContext(uint32_t context, Time const &delay, EventImpl *event)
Schedule a future event execution (in a different context).
virtual uint32_t GetContext(void) const
Get the current simulation context.
static Ptr< RemoteChannelBundle > Find(uint32_t systemId)
void HandleArrivingMessagesBlocking(void)
Blocking receive of arriving messages.
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:391
Time TimeStep(uint64_t ts)
Definition: nstime.h:1064
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
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.
virtual bool IsExpired(const EventId &id) const
Check if an event has already run or been cancelled.
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
An identifier for simulation events.
Definition: event-id.h:53
static uint32_t GetSystemId()
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:234
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
virtual Time Now(void) const
Return the current simulation virtual time.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1007
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.
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
The SimulatorImpl base class.