A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 NS_LOG_COMPONENT_DEFINE ("NullMessageSimulatorImpl");
46 
47 namespace ns3 {
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")
57  .SetParent<Object> ()
58  .AddConstructor<NullMessageSimulatorImpl> ()
59  .AddAttribute ("SchedulerTune", "Null Message scheduler tuning parameter",
60  DoubleValue (1.0),
61  MakeDoubleAccessor (&NullMessageSimulatorImpl::m_schedulerTune),
62  MakeDoubleChecker<double> (0.01,1.0))
63  ;
64  return tid;
65 }
66 
68 {
69 #ifdef NS3_MPI
70  NS_LOG_FUNCTION (this);
71 
74 
75  m_stop = false;
76  // uids are allocated from 4.
77  // uid 0 is "invalid" events
78  // uid 1 is "now" events
79  // uid 2 is "destroy" events
80  m_uid = 4;
81  // before ::Run is entered, the m_currentUid will be zero
82  m_currentUid = 0;
83  m_currentTs = 0;
84  m_currentContext = 0xffffffff;
86  m_events = 0;
87 
88  m_safeTime = Seconds (0);
89 
90  NS_ASSERT (g_instance == 0);
91  g_instance = this;
92 
93 #else
94  NS_FATAL_ERROR ("Can't use Null Message simulator without MPI compiled in");
95 #endif
96 }
97 
99 {
100  NS_LOG_FUNCTION (this);
101 }
102 
103 void
105 {
106  NS_LOG_FUNCTION (this);
107 
108  while (!m_events->IsEmpty ())
109  {
110  Scheduler::Event next = m_events->RemoveNext ();
111  next.impl->Unref ();
112  }
113  m_events = 0;
115 }
116 
117 void
119 {
120  NS_LOG_FUNCTION (this);
121 
122  while (!m_destroyEvents.empty ())
123  {
124  Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
125  m_destroyEvents.pop_front ();
126  NS_LOG_LOGIC ("handle destroy " << ev);
127  if (!ev->IsCancelled ())
128  {
129  ev->Invoke ();
130  }
131  }
132 
135 }
136 
137 void
139 {
140  NS_LOG_FUNCTION (this);
141 
142  int num_local_nodes = 0;
143 
144  if (MpiInterface::GetSize () > 1)
145  {
147  for (NodeContainer::Iterator iter = c.Begin (); iter != c.End (); ++iter)
148  {
149  if ((*iter)->GetSystemId () != MpiInterface::GetSystemId ())
150  {
151  continue;
152  }
153 
154  num_local_nodes++;
155 
156  for (uint32_t i = 0; i < (*iter)->GetNDevices (); ++i)
157  {
158  Ptr<NetDevice> localNetDevice = (*iter)->GetDevice (i);
159  // only works for p2p links currently
160  if (!localNetDevice->IsPointToPoint ())
161  {
162  continue;
163  }
164  Ptr<Channel> channel = localNetDevice->GetChannel ();
165  if (channel == 0)
166  {
167  continue;
168  }
169 
170  // grab the adjacent node
171  Ptr<Node> remoteNode;
172  if (channel->GetDevice (0) == localNetDevice)
173  {
174  remoteNode = (channel->GetDevice (1))->GetNode ();
175  }
176  else
177  {
178  remoteNode = (channel->GetDevice (0))->GetNode ();
179  }
180 
181  // if it's not remote, don't consider it
182  if (remoteNode->GetSystemId () == MpiInterface::GetSystemId ())
183  {
184  continue;
185  }
186 
190  Ptr<RemoteChannelBundle> remoteChannelBundle = RemoteChannelBundleManager::Find (remoteNode->GetSystemId ());
191  if (!remoteChannelBundle)
192  {
193  remoteChannelBundle = RemoteChannelBundleManager::Add (remoteNode->GetSystemId ());
194  }
195 
196  TimeValue delay;
197  channel->GetAttribute ("Delay", delay);
198  remoteChannelBundle->AddChannel (channel, delay.Get () );
199  }
200  }
201  }
202 
203  // Completed setup of remote channel bundles. Setup send and receive buffers.
205 
206  // Initialized to 0 as we don't have a simulation start time.
207  m_safeTime = Time (0);
208 }
209 
210 void
212 {
213  NS_LOG_FUNCTION (this << schedulerFactory);
214 
215  Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler> ();
216 
217  if (m_events != 0)
218  {
219  while (!m_events->IsEmpty ())
220  {
221  Scheduler::Event next = m_events->RemoveNext ();
222  scheduler->Insert (next);
223  }
224  }
225  m_events = scheduler;
226 }
227 
228 void
230 {
231  NS_LOG_FUNCTION (this);
232 
233  Scheduler::Event next = m_events->RemoveNext ();
234 
235  NS_ASSERT (next.key.m_ts >= m_currentTs);
237 
238  NS_LOG_LOGIC ("handle " << next.key.m_ts);
239  m_currentTs = next.key.m_ts;
241  m_currentUid = next.key.m_uid;
242  next.impl->Invoke ();
243  next.impl->Unref ();
244 }
245 
246 bool
248 {
249  return m_events->IsEmpty () || m_stop;
250 }
251 
252 Time
254 {
255  NS_LOG_FUNCTION (this);
256 
257  NS_ASSERT (!m_events->IsEmpty ());
258 
259  Scheduler::Event ev = m_events->PeekNext ();
260  return TimeStep (ev.key.m_ts);
261 }
262 
263 void
265 {
266  NS_LOG_FUNCTION (this << bundle);
267 
268  Time time (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
269 
271  this, PeekPointer(bundle)));
272 }
273 
274 void
276 {
277  NS_LOG_FUNCTION (this << bundle);
278 
279  Simulator::Cancel (bundle->GetEventId ());
280 
281  Time time (m_schedulerTune * bundle->GetDelay ().GetTimeStep ());
282 
284  this, PeekPointer(bundle)));
285 }
286 
287 void
289 {
290  NS_LOG_FUNCTION (this << nodeSysId);
291 
293  NS_ASSERT (bundle);
294 
296 }
297 
298 void
300 {
301  NS_LOG_FUNCTION (this);
302 
304 
306 
307  // Stop will be set if stop is called by simulation.
308  m_stop = false;
309  while (!IsFinished ())
310  {
311  Time nextTime = Next ();
312 
313  if ( nextTime <= GetSafeTime () )
314  {
315  ProcessOneEvent ();
317  }
318  else
319  {
320  // Block until packet or Null Message has been received.
322  }
323  }
324 }
325 
326 void
328 {
329  NS_LOG_FUNCTION (this);
330 
332 
334 
335  // Check for send completes
337 }
338 
339 void
341 {
342  NS_LOG_FUNCTION (this);
343 
345 
347 
348  // Check for send completes
350 }
351 
352 void
354 {
355  NS_LOG_FUNCTION (this);
356 
359 }
360 
361 Time
363 {
364  return m_safeTime;
365 }
366 
367 
368 uint32_t
370 {
371  return m_myId;
372 }
373 
374 void
376 {
377  NS_LOG_FUNCTION (this);
378 
379  ProcessOneEvent ();
380 }
381 
382 void
384 {
385  NS_LOG_FUNCTION (this);
386 
387  m_stop = true;
388 }
389 
390 void
392 {
393  NS_LOG_FUNCTION (this << time.GetTimeStep ());
394 
396 }
397 
398 //
399 // Schedule an event for a _relative_ time in the future.
400 //
401 EventId
403 {
404  NS_LOG_FUNCTION (this << time.GetTimeStep () << event);
405 
406  Time tAbsolute = time + TimeStep (m_currentTs);
407 
408  NS_ASSERT (tAbsolute.IsPositive ());
409  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
410  Scheduler::Event ev;
411  ev.impl = event;
412  ev.key.m_ts = static_cast<uint64_t> (tAbsolute.GetTimeStep ());
413  ev.key.m_context = GetContext ();
414  ev.key.m_uid = m_uid;
415  m_uid++;
417  m_events->Insert (ev);
418  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
419 }
420 
421 void
422 NullMessageSimulatorImpl::ScheduleWithContext (uint32_t context, Time const &time, EventImpl *event)
423 {
424  NS_LOG_FUNCTION (this << context << time.GetTimeStep () << m_currentTs << event);
425 
426  Time tAbsolute(m_currentTs + time.GetTimeStep ());
427 
428  NS_ASSERT (tAbsolute.IsPositive ());
429  NS_ASSERT (tAbsolute >= TimeStep (m_currentTs));
430 
431  Scheduler::Event ev;
432  ev.impl = event;
433  ev.key.m_ts = tAbsolute.GetTimeStep ();
434  ev.key.m_context = context;
435  ev.key.m_uid = m_uid;
436  m_uid++;
438  m_events->Insert (ev);
439 }
440 
441 EventId
443 {
444  NS_LOG_FUNCTION (this << event);
445 
446  Scheduler::Event ev;
447  ev.impl = event;
448  ev.key.m_ts = m_currentTs;
449  ev.key.m_context = GetContext ();
450  ev.key.m_uid = m_uid;
451  m_uid++;
453  m_events->Insert (ev);
454  return EventId (event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
455 }
456 
457 EventId
459 {
460  NS_LOG_FUNCTION (this << event);
461 
462  EventId id (Ptr<EventImpl> (event, false), m_currentTs, 0xffffffff, 2);
463  m_destroyEvents.push_back (id);
464  m_uid++;
465  return id;
466 }
467 
468 Time
470 {
471  return TimeStep (m_currentTs);
472 }
473 
474 Time
476 {
477  if (IsExpired (id))
478  {
479  return TimeStep (0);
480  }
481  else
482  {
483  return TimeStep (id.GetTs () - m_currentTs);
484  }
485 }
486 
487 void
489 {
490  if (id.GetUid () == 2)
491  {
492  // destroy events.
493  for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
494  {
495  if (*i == id)
496  {
497  m_destroyEvents.erase (i);
498  break;
499  }
500  }
501  return;
502  }
503  if (IsExpired (id))
504  {
505  return;
506  }
507  Scheduler::Event event;
508  event.impl = id.PeekEventImpl ();
509  event.key.m_ts = id.GetTs ();
510  event.key.m_context = id.GetContext ();
511  event.key.m_uid = id.GetUid ();
512  m_events->Remove (event);
513  event.impl->Cancel ();
514  // whenever we remove an event from the event list, we have to unref it.
515  event.impl->Unref ();
516 
518 }
519 
520 void
522 {
523  if (!IsExpired (id))
524  {
525  id.PeekEventImpl ()->Cancel ();
526  }
527 }
528 
529 bool
531 {
532  if (ev.GetUid () == 2)
533  {
534  if (ev.PeekEventImpl () == 0
535  || ev.PeekEventImpl ()->IsCancelled ())
536  {
537  return true;
538  }
539  // destroy events.
540  for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
541  {
542  if (*i == ev)
543  {
544  return false;
545  }
546  }
547  return true;
548  }
549  if (ev.PeekEventImpl () == 0
550  || ev.GetTs () < m_currentTs
551  || (ev.GetTs () == m_currentTs
552  && ev.GetUid () <= m_currentUid)
553  || ev.PeekEventImpl ()->IsCancelled ())
554  {
555  return true;
556  }
557  else
558  {
559  return false;
560  }
561 }
562 
563 Time
565 {
566  // XXX: I am fairly certain other compilers use other non-standard
567  // post-fixes to indicate 64 bit constants.
568  return TimeStep (0x7fffffffffffffffLL);
569 }
570 
571 uint32_t
573 {
574  return m_currentContext;
575 }
576 
578 {
580  NS_ASSERT (bundle);
581 
582  return Min (NullMessageSimulatorImpl::GetInstance ()->Next (), GetSafeTime ()) + bundle->GetDelay ();
583 }
584 
586 {
587  NS_LOG_FUNCTION (this << bundle);
588 
589  Time time = Min (Next (), GetSafeTime ()) + bundle->GetDelay ();
591 
592  ScheduleNullMessageEvent (bundle);
593 }
594 
595 
598 {
599  NS_ASSERT (g_instance != 0);
600  return g_instance;
601 }
602 } // namespace ns3
603 
Time CalculateGuaranteeTime(uint32_t systemId)
virtual Time GetMaximumSimulationTime(void) const
Time Get(void) const
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:79
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:60
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
virtual void Cancel(const EventId &ev)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register the class in the ns-3 factory.
Definition: object-base.h:38
std::vector< Ptr< Node > >::const_iterator Iterator
Node container iterator.
Time TimeStep(uint64_t ts)
Definition: nstime.h:997
virtual void Destroy()
This method is typically invoked at the end of a simulation to avoid false-positive reports by a leak...
void HandleArrivingMessagesNonBlocking(void)
Non blocking receive of pending messages.
virtual EventId ScheduleNow(EventImpl *event)
EventImpl * impl
Definition: scheduler.h:73
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:61
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:170
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.
bool IsCancelled(void)
Definition: event-impl.cc:57
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
Definition: object.cc:335
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:95
virtual EventId Schedule(Time const &time, EventImpl *event)
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
void ProcessOneEvent(void)
Process the next event on the queue.
void RescheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
Collection of NS3 channels between local and remote nodes.
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Schedule an event to expire at the relative time "time" is reached.
Definition: simulator.h:825
EventImpl * PeekEventImpl(void) const
Definition: event-id.cc:65
uint32_t GetSystemId(void) const
Definition: node.cc:113
virtual EventId ScheduleDestroy(EventImpl *event)
void CalculateSafeTime(void)
Calculate the SafeTime.
void Invoke(void)
Called by the simulation engine to notify the event that it has expired.
Definition: event-impl.cc:40
static NullMessageSimulatorImpl * GetInstance(void)
static void TestSendComplete()
Check for completed sends.
virtual uint32_t GetSystemId(void) const
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Minimum.
Definition: int64x64.h:194
virtual bool IsFinished(void) const
If there are no more events lefts to be scheduled, or if simulation time has already reached the "sto...
static void Destroy()
Deletes storage used by the parallel environment.
hold objects of type ns3::Time
Definition: nstime.h:1008
Ptr< Object > Create(void) const
void Unref(void) const
Decrement the reference count.
T * PeekPointer(const Ptr< T > &p)
Definition: ptr.h:280
static void SendNullMessage(const Time &guaranteeUpdate, Ptr< RemoteChannelBundle > bundle)
Send a Null Message to across the specified bundle.
uint32_t GetUid(void) const
Definition: event-id.cc:83
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:58
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:233
static void Destroy(void)
Destroy the singleton.
virtual void Run(void)
Run the simulation until one of:
static NullMessageSimulatorImpl * g_instance
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 uint32_t GetContext(void) const
static Ptr< RemoteChannelBundle > Find(uint32_t systemId)
void HandleArrivingMessagesBlocking(void)
Blocking receive of arriving messages.
int64_t GetTimeStep(void) const
Definition: nstime.h:354
virtual Time GetDelayLeft(const EventId &id) const
virtual void ScheduleWithContext(uint32_t context, Time const &time, EventImpl *event)
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.
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:39
an identifier for simulation events.
Definition: event-id.h:46
static uint32_t GetSystemId()
static void Stop(void)
If an event invokes this method, it will be the last event scheduled by the Simulator::run method bef...
Definition: simulator.cc:165
virtual void Stop(void)
If an event invokes this method, it will be the last event scheduled by the Simulator::Run method bef...
virtual Time Now(void) const
Return the "current simulation time".
void ScheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
void NullMessageEventHandler(RemoteChannelBundle *bundle)
virtual bool IsExpired(const EventId &ev) const
This method has O(1) complexity.
virtual void Remove(const EventId &ev)
Remove an event from the event list.
a base class which provides memory management and object aggregation
Definition: object.h:64
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
static void InitializeSendReceiveBuffers(void)
Initialize send and receive buffers.
Hold a floating point type.
Definition: double.h:41
a unique identifier for an interface.
Definition: type-id.h:49
virtual void SetScheduler(ObjectFactory schedulerFactory)
TypeId SetParent(TypeId tid)
Definition: type-id.cc:610
static uint32_t GetSize()
uint64_t GetTs(void) const
Definition: event-id.cc:71