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
keep track of time values and allow control of global simulation resolution
Definition: nstime.h:81
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
virtual void Cancel(const EventId &ev)
Set the cancel bit on this event: the event&#39;s associated function will not be invoked when it expires...
std::vector< Ptr< Node > >::const_iterator Iterator
Time TimeStep(uint64_t ts)
Definition: nstime.h:950
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:72
#define NS_ASSERT(condition)
Definition: assert.h:64
NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl)
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:171
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&#39;s destructor, whichever comes first...
Definition: object.cc:336
virtual EventId Schedule(Time const &time, EventImpl *event)
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: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 &quot;time&quot; is reached.
Definition: simulator.h:824
EventImpl * PeekEventImpl(void) const
Definition: event-id.cc:65
uint32_t GetSystemId(void) const
Definition: node.cc:111
virtual EventId ScheduleDestroy(EventImpl *event)
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
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
virtual bool IsFinished(void) const
If there are no more events lefts to be scheduled, or if simulation time has already reached the &quot;sto...
static void Destroy()
Deletes storage used by the parallel environment.
hold objects of type ns3::Time
Definition: nstime.h:961
Ptr< Object > Create(void) const
void Unref(void) const
Decrement the reference count.
T * PeekPointer(const Ptr< T > &p)
Definition: ptr.h:279
static void SendNullMessage(const Time &guaranteeUpdate, Ptr< RemoteChannelBundle > bundle)
Send a Null Message to across the specified bundle.
int64x64_t Min(const int64x64_t &a, const int64x64_t &b)
Definition: int64x64.h:90
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:57
#define NS_LOG_LOGIC(msg)
Definition: log.h:368
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:356
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 &quot;current simulation time&quot;.
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:63
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object&#39;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:611
static uint32_t GetSize()
uint64_t GetTs(void) const
Definition: event-id.cc:71