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 
29 
32 #include "remote-channel-bundle.h"
33 #include "mpi-interface.h"
34 
35 #include <ns3/simulator.h>
36 #include <ns3/scheduler.h>
37 #include <ns3/event-impl.h>
38 #include <ns3/channel.h>
39 #include <ns3/node-container.h>
40 #include <ns3/double.h>
41 #include <ns3/ptr.h>
42 #include <ns3/pointer.h>
43 #include <ns3/assert.h>
44 #include <ns3/log.h>
45 
46 #include <cmath>
47 #include <iostream>
48 #include <fstream>
49 #include <iomanip>
50 
51 namespace ns3 {
52 
53 NS_LOG_COMPONENT_DEFINE ("NullMessageSimulatorImpl");
54 
55 NS_OBJECT_ENSURE_REGISTERED (NullMessageSimulatorImpl);
56 
57 NullMessageSimulatorImpl* NullMessageSimulatorImpl::g_instance = 0;
58 
59 TypeId
61 {
62  static TypeId tid = TypeId ("ns3::NullMessageSimulatorImpl")
64  .SetGroupName ("Mpi")
65  .AddConstructor<NullMessageSimulatorImpl> ()
66  .AddAttribute ("SchedulerTune", "Null Message scheduler tuning parameter",
67  DoubleValue (1.0),
69  MakeDoubleChecker<double> (0.01,1.0))
70  ;
71  return tid;
72 }
73 
75 {
76  NS_LOG_FUNCTION (this);
77 
80 
81  m_stop = false;
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 
97 {
98  NS_LOG_FUNCTION (this);
99 }
100 
101 void
103 {
104  NS_LOG_FUNCTION (this);
105 
106  while (!m_events->IsEmpty ())
107  {
108  Scheduler::Event next = m_events->RemoveNext ();
109  next.impl->Unref ();
110  }
111  m_events = 0;
113 }
114 
115 void
117 {
118  NS_LOG_FUNCTION (this);
119 
120  while (!m_destroyEvents.empty ())
121  {
122  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
123  m_destroyEvents.pop_front ();
124  NS_LOG_LOGIC ("handle destroy " << ev);
125  if (!ev->IsCancelled ())
126  {
127  ev->Invoke ();
128  }
129  }
130 
133 }
134 
135 void
137 {
138  NS_LOG_FUNCTION (this);
139 
140  int num_local_nodes = 0;
141 
142  if (MpiInterface::GetSize () > 1)
143  {
145  for (NodeContainer::Iterator iter = c.Begin (); iter != c.End (); ++iter)
146  {
147  if ((*iter)->GetSystemId () != MpiInterface::GetSystemId ())
148  {
149  continue;
150  }
151 
152  num_local_nodes++;
153 
154  for (uint32_t i = 0; i < (*iter)->GetNDevices (); ++i)
155  {
156  Ptr<NetDevice> localNetDevice = (*iter)->GetDevice (i);
157  // only works for p2p links currently
158  if (!localNetDevice->IsPointToPoint ())
159  {
160  continue;
161  }
162  Ptr<Channel> channel = localNetDevice->GetChannel ();
163  if (channel == 0)
164  {
165  continue;
166  }
167 
168  // grab the adjacent node
169  Ptr<Node> remoteNode;
170  if (channel->GetDevice (0) == localNetDevice)
171  {
172  remoteNode = (channel->GetDevice (1))->GetNode ();
173  }
174  else
175  {
176  remoteNode = (channel->GetDevice (0))->GetNode ();
177  }
178 
179  // if it's not remote, don't consider it
180  if (remoteNode->GetSystemId () == MpiInterface::GetSystemId ())
181  {
182  continue;
183  }
184 
188  Ptr<RemoteChannelBundle> remoteChannelBundle = RemoteChannelBundleManager::Find (remoteNode->GetSystemId ());
189  if (!remoteChannelBundle)
190  {
191  remoteChannelBundle = RemoteChannelBundleManager::Add (remoteNode->GetSystemId ());
192  }
193 
194  TimeValue delay;
195  channel->GetAttribute ("Delay", delay);
196  remoteChannelBundle->AddChannel (channel, delay.Get () );
197  }
198  }
199  }
200 
201  // Completed setup of remote channel bundles. Setup send and receive buffers.
203 
204  // Initialized to 0 as we don't have a simulation start time.
205  m_safeTime = Time (0);
206 }
207 
208 void
210 {
211  NS_LOG_FUNCTION (this << schedulerFactory);
212 
213  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
214 
215  if (m_events != 0)
216  {
217  while (!m_events->IsEmpty ())
218  {
219  Scheduler::Event next = m_events->RemoveNext ();
220  scheduler->Insert (next);
221  }
222  }
223  m_events = scheduler;
224 }
225 
226 void
228 {
229  NS_LOG_FUNCTION (this);
230 
231  Scheduler::Event next = m_events->RemoveNext ();
232 
233  PreEventHook (EventId (next.impl, next.key.m_ts,
234  next.key.m_context, next.key.m_uid));
235 
236  NS_ASSERT (next.key.m_ts >= m_currentTs);
238  m_eventCount++;
239 
240  NS_LOG_LOGIC ("handle " << next.key.m_ts);
241  m_currentTs = next.key.m_ts;
243  m_currentUid = next.key.m_uid;
244  next.impl->Invoke ();
245  next.impl->Unref ();
246 }
247 
248 bool
250 {
251  return m_events->IsEmpty () || m_stop;
252 }
253 
254 Time
256 {
257  NS_LOG_FUNCTION (this);
258 
259  NS_ASSERT (!m_events->IsEmpty ());
260 
261  Scheduler::Event ev = m_events->PeekNext ();
262  return TimeStep (ev.key.m_ts);
263 }
264 
265 void
267 {
268  NS_LOG_FUNCTION (this << bundle);
269 
270  Time delay (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
271 
273  this, PeekPointer(bundle)));
274 }
275 
276 void
278 {
279  NS_LOG_FUNCTION (this << bundle);
280 
281  Simulator::Cancel (bundle->GetEventId ());
282 
283  Time delay (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
284 
286  this, PeekPointer(bundle)));
287 }
288 
289 void
291 {
292  NS_LOG_FUNCTION (this << nodeSysId);
293 
295  NS_ASSERT (bundle);
296 
298 }
299 
300 void
302 {
303  NS_LOG_FUNCTION (this);
304 
306 
308 
309  // Stop will be set if stop is called by simulation.
310  m_stop = false;
311  while (!IsFinished ())
312  {
313  Time nextTime = Next ();
314 
315  if ( nextTime <= GetSafeTime () )
316  {
317  ProcessOneEvent ();
319  }
320  else
321  {
322  // Block until packet or Null Message has been received.
324  }
325  }
326 }
327 
328 void
330 {
331  NS_LOG_FUNCTION (this);
332 
334 
336 
337  // Check for send completes
339 }
340 
341 void
343 {
344  NS_LOG_FUNCTION (this);
345 
347 
349 
350  // Check for send completes
352 }
353 
354 void
356 {
357  NS_LOG_FUNCTION (this);
358 
361 }
362 
363 Time
365 {
366  return m_safeTime;
367 }
368 
369 
370 uint32_t
372 {
373  return m_myId;
374 }
375 
376 void
378 {
379  NS_LOG_FUNCTION (this);
380 
381  m_stop = true;
382 }
383 
384 void
386 {
387  NS_LOG_FUNCTION (this << delay.GetTimeStep ());
388 
390 }
391 
392 //
393 // Schedule an event for a _relative_ time in the future.
394 //
395 EventId
397 {
398  NS_LOG_FUNCTION (this << delay.GetTimeStep () << event);
399 
400  Time tAbsolute = delay + TimeStep (m_currentTs);
401 
402  NS_ASSERT (tAbsolute.IsPositive ());
403  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
404  Scheduler::Event ev;
405  ev.impl = event;
406  ev.key.m_ts = static_cast<uint64_t> (tAbsolute.GetTimeStep ());
407  ev.key.m_context = GetContext ();
408  ev.key.m_uid = m_uid;
409  m_uid++;
411  m_events->Insert (ev);
412  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
413 }
414 
415 void
416 NullMessageSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &delay, EventImpl *event)
417 {
418  NS_LOG_FUNCTION (this << context << delay.GetTimeStep () << m_currentTs << event);
419 
420  Time tAbsolute(m_currentTs + delay.GetTimeStep ());
421 
422  NS_ASSERT (tAbsolute.IsPositive ());
423  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
424 
425  Scheduler::Event ev;
426  ev.impl = event;
427  ev.key.m_ts = tAbsolute.GetTimeStep ();
428  ev.key.m_context = context;
429  ev.key.m_uid = m_uid;
430  m_uid++;
432  m_events->Insert (ev);
433 }
434 
435 EventId
437 {
438  NS_LOG_FUNCTION (this << event);
439  return Schedule (Time (0), event);
440 }
441 
442 EventId
444 {
445  NS_LOG_FUNCTION (this << event);
446 
447  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
448  m_destroyEvents.push_back (id);
449  m_uid++;
450  return id;
451 }
452 
453 Time
455 {
456  return TimeStep (m_currentTs);
457 }
458 
459 Time
461 {
462  if (IsExpired (id))
463  {
464  return TimeStep (0);
465  }
466  else
467  {
468  return TimeStep (id.GetTs () - m_currentTs);
469  }
470 }
471 
472 void
474 {
475  if (id.GetUid () == EventId::UID::DESTROY)
476  {
477  // destroy events.
478  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
479  {
480  if (*i == id)
481  {
482  m_destroyEvents.erase (i);
483  break;
484  }
485  }
486  return;
487  }
488  if (IsExpired (id))
489  {
490  return;
491  }
492  Scheduler::Event event;
493  event.impl = id.PeekEventImpl ();
494  event.key.m_ts = id.GetTs ();
495  event.key.m_context = id.GetContext ();
496  event.key.m_uid = id.GetUid ();
497  m_events->Remove (event);
498  event.impl->Cancel ();
499  // whenever we remove an event from the event list, we have to unref it.
500  event.impl->Unref ();
501 
503 }
504 
505 void
507 {
508  if (!IsExpired (id))
509  {
510  id.PeekEventImpl ()->Cancel ();
511  }
512 }
513 
514 bool
516 {
517  if (id.GetUid () == EventId::UID::DESTROY)
518  {
519  if (id.PeekEventImpl () == 0
520  || id.PeekEventImpl ()->IsCancelled ())
521  {
522  return true;
523  }
524  // destroy events.
525  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
526  {
527  if (*i == id)
528  {
529  return false;
530  }
531  }
532  return true;
533  }
534  if (id.PeekEventImpl () == 0
535  || id.GetTs () < m_currentTs
536  || (id.GetTs () == m_currentTs
537  && id.GetUid () <= m_currentUid)
538  || id.PeekEventImpl ()->IsCancelled ())
539  {
540  return true;
541  }
542  else
543  {
544  return false;
545  }
546 }
547 
548 Time
550 {
551  // XXX: I am fairly certain other compilers use other non-standard
552  // post-fixes to indicate 64 bit constants.
553  return TimeStep (0x7fffffffffffffffLL);
554 }
555 
556 uint32_t
558 {
559  return m_currentContext;
560 }
561 
562 uint64_t
564 {
565  return m_eventCount;
566 }
567 
569 {
571  NS_ASSERT (bundle);
572 
573  return Min (NullMessageSimulatorImpl::GetInstance ()->Next (), GetSafeTime ()) + bundle->GetDelay ();
574 }
575 
577 {
578  NS_LOG_FUNCTION (this << bundle);
579 
580  Time time = Min (Next (), GetSafeTime ()) + bundle->GetDelay ();
582 
583  ScheduleNullMessageEvent (bundle);
584 }
585 
586 
589 {
590  NS_ASSERT (g_instance != 0);
591  return g_instance;
592 }
593 } // namespace ns3
594 
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:41
An identifier for simulation events.
Definition: event-id.h:54
A simulation event.
Definition: event-impl.h:45
void Invoke(void)
Called by the simulation engine to notify the event that it is time to execute.
Definition: event-impl.cc:46
static void Destroy()
Deletes storage used by the parallel environment.
static uint32_t GetSystemId()
Get the id number of this rank.
static uint32_t GetSize()
Get the number of ranks used by ns-3.
virtual Ptr< Channel > GetChannel(void) const =0
virtual bool IsPointToPoint(void) const =0
Return true if the net device is on a point-to-point link.
keep track of a set of node pointers.
Iterator Begin(void) const
Get an iterator which refers to the first Node in the container.
Iterator End(void) const
Get an iterator which indicates past-the-last Node in the container.
static NodeContainer GetGlobal(void)
Create a NodeContainer that contains a list of all nodes created through NodeContainer::Create() and ...
std::vector< Ptr< Node > >::const_iterator Iterator
Node container iterator.
uint32_t GetSystemId(void) const
Definition: node.cc:123
static void ReceiveMessagesBlocking()
Blocking message receive.
static void ReceiveMessagesNonBlocking()
Non-blocking check for received messages complete.
static void SendNullMessage(const Time &guaranteeUpdate, Ptr< RemoteChannelBundle > bundle)
Send a Null Message to across the specified bundle.
static void TestSendComplete()
Check for completed sends.
static void InitializeSendReceiveBuffers(void)
Initialize send and receive buffers.
Simulator implementation using MPI and a Null Message algorithm.
double m_schedulerTune
Null Message performance tuning parameter.
Ptr< Scheduler > m_events
The event priority queue.
virtual void Remove(const EventId &id)
Remove an event from the event list.
virtual bool IsExpired(const EventId &id) const
Check if an event has already run or been cancelled.
uint32_t m_currentUid
Unique id of the current event.
uint32_t m_systemCount
MPI communicator size.
void ProcessOneEvent(void)
Process the next event on the queue.
virtual void SetScheduler(ObjectFactory schedulerFactory)
Set the Scheduler to be used to manage the event list.
uint32_t m_currentContext
Execution context of the current event.
Time m_safeTime
The time for which it is safe for this task to execute events without danger of out-of-order events.
void CalculateSafeTime(void)
Calculate the SafeTime.
virtual void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Time CalculateGuaranteeTime(uint32_t systemId)
static NullMessageSimulatorImpl * g_instance
Singleton instance.
virtual EventId Schedule(Time const &delay, EventImpl *event)
Schedule a future event execution (in the same context).
virtual Time Now(void) const
Return the current simulation virtual time.
uint32_t m_uid
Next event unique id.
virtual Time GetMaximumSimulationTime(void) const
Get the maximum representable simulation time.
virtual Time GetDelayLeft(const EventId &id) const
Get the remaining time until this event will execute.
uint64_t m_currentTs
Timestamp of the current event.
void HandleArrivingMessagesNonBlocking(void)
Non blocking receive of pending messages.
virtual void ScheduleWithContext(uint32_t context, Time const &delay, EventImpl *event)
Schedule a future event execution (in a different context).
void NullMessageEventHandler(RemoteChannelBundle *bundle)
virtual EventId ScheduleNow(EventImpl *event)
Schedule an event to run at the current virtual time.
DestroyEvents m_destroyEvents
The container of events to run at Destroy()
virtual uint64_t GetEventCount(void) const
Get the number of events executed.
virtual void Destroy()
Execute the events scheduled with ScheduleDestroy().
virtual void DoDispose(void)
Destructor implementation.
static NullMessageSimulatorImpl * GetInstance(void)
virtual void Run(void)
Run the simulation.
Time GetSafeTime(void)
Get the current SafeTime; the maximum time that events can be processed based on information received...
int m_unscheduledEvents
Number of events that have been inserted but not yet scheduled, not counting the "destroy" events; th...
virtual void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
void HandleArrivingMessagesBlocking(void)
Blocking receive of arriving messages.
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...
static TypeId GetTypeId(void)
Register this type.
void RescheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
bool m_stop
Flag calling for the end of the simulation.
virtual uint32_t GetContext(void) const
Get the current simulation context.
virtual uint32_t GetSystemId(void) const
Get the system id of this simulator.
void CalculateLookAhead(void)
Calculate the lookahead allowable for this MPI task.
void ScheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
virtual bool IsFinished(void) const
Check if the simulation should finish.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create(void) const
Create an Object instance of the configured TypeId.
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
Collection of ns-3 channels between local and remote nodes.
Time GetDelay(void) const
Get the minimum delay along any channel in this bundle.
static Ptr< RemoteChannelBundle > Find(uint32_t systemId)
Get the bundle corresponding to a remote rank.
static void InitializeNullMessageEvents(void)
Setup initial Null Message events for every RemoteChannelBundle.
static Ptr< RemoteChannelBundle > Add(uint32_t systemId)
Add RemoteChannelBundle from this task to MPI task on other side of the link.
static Time GetSafeTime(void)
Get the safe time across all channels in this bundle.
static void Destroy(void)
Destroy the singleton.
Maintain the event list.
Definition: scheduler.h:156
void Unref(void) const
Decrement the reference count.
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Definition: simulator.cc:268
static void Stop(void)
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:180
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:556
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition: simulator.h:199
The SimulatorImpl base class.
virtual void PreEventHook(const EventId &id)
Hook called before processing each event.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
int64_t GetTimeStep(void) const
Get the raw time value, in the current resolution unit.
Definition: nstime.h:415
bool IsPositive(void) const
Exactly equivalent to t >= 0.
Definition: nstime.h:316
AttributeValue implementation for Time.
Definition: nstime.h:1308
Time Get(void) const
Definition: time.cc:519
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
@ INVALID
INVALID.
Definition: aodv-rtable.h:51
@ VALID
VALID.
Definition: aodv-rtable.h:50
#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
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
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:218
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#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
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Declaration of class ns3::MpiInterface.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:793
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:415
channel
Definition: third.py:92
Declaration of classes ns3::NullMessageSentBuffer and ns3::NullMessageMpiInterface.
Declaration of class ns3::NullMessageSimulatorImpl.
Declaration of class ns3::RemoteChannelBundleManager.
Declaration of class ns3::RemoteChannelBundle.
Scheduler event.
Definition: scheduler.h:182
EventKey key
Key for sorting and ordering Events.
Definition: scheduler.h:184
EventImpl * impl
Pointer to the event implementation.
Definition: scheduler.h:183
uint32_t m_context
Event context.
Definition: scheduler.h:172
uint64_t m_ts
Event time stamp.
Definition: scheduler.h:170
uint32_t m_uid
Event unique id.
Definition: scheduler.h:171