A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
null-message-simulator-impl.cc
Go to the documentation of this file.
1/*
2 * Copyright 2013. Lawrence Livermore National Security, LLC.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Steven Smith <smith84@llnl.gov>
7 */
8
9/**
10 * \file
11 * \ingroup mpi
12 * Implementation of class ns3::NullMessageSimulatorImpl.
13 */
14
16
17#include "mpi-interface.h"
21
22#include <ns3/assert.h>
23#include <ns3/channel.h>
24#include <ns3/double.h>
25#include <ns3/event-impl.h>
26#include <ns3/log.h>
27#include <ns3/node-container.h>
28#include <ns3/pointer.h>
29#include <ns3/ptr.h>
30#include <ns3/scheduler.h>
31#include <ns3/simulator.h>
32
33#include <cmath>
34#include <fstream>
35#include <iomanip>
36#include <iostream>
37
38namespace ns3
39{
40
41NS_LOG_COMPONENT_DEFINE("NullMessageSimulatorImpl");
42
43NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl);
44
45NullMessageSimulatorImpl* NullMessageSimulatorImpl::g_instance = nullptr;
46
47TypeId
49{
50 static TypeId tid =
51 TypeId("ns3::NullMessageSimulatorImpl")
53 .SetGroupName("Mpi")
54 .AddConstructor<NullMessageSimulatorImpl>()
55 .AddAttribute("SchedulerTune",
56 "Null Message scheduler tuning parameter",
57 DoubleValue(1.0),
59 MakeDoubleChecker<double>(0.01, 1.0));
60 return tid;
61}
62
84
89
90void
92{
93 NS_LOG_FUNCTION(this);
94
95 while (!m_events->IsEmpty())
96 {
97 Scheduler::Event next = m_events->RemoveNext();
98 next.impl->Unref();
99 }
100 m_events = nullptr;
102}
103
104void
106{
107 NS_LOG_FUNCTION(this);
108
109 while (!m_destroyEvents.empty())
110 {
111 Ptr<EventImpl> ev = m_destroyEvents.front().PeekEventImpl();
112 m_destroyEvents.pop_front();
113 NS_LOG_LOGIC("handle destroy " << ev);
114 if (!ev->IsCancelled())
115 {
116 ev->Invoke();
117 }
118 }
119
122}
123
124void
126{
127 NS_LOG_FUNCTION(this);
128
129 if (MpiInterface::GetSize() > 1)
130 {
132 for (auto iter = c.Begin(); iter != c.End(); ++iter)
133 {
134 if ((*iter)->GetSystemId() != MpiInterface::GetSystemId())
135 {
136 continue;
137 }
138
139 for (uint32_t i = 0; i < (*iter)->GetNDevices(); ++i)
140 {
141 Ptr<NetDevice> localNetDevice = (*iter)->GetDevice(i);
142 // only works for p2p links currently
143 if (!localNetDevice->IsPointToPoint())
144 {
145 continue;
146 }
147 Ptr<Channel> channel = localNetDevice->GetChannel();
148 if (!channel)
149 {
150 continue;
151 }
152
153 // grab the adjacent node
154 Ptr<Node> remoteNode;
155 if (channel->GetDevice(0) == localNetDevice)
156 {
157 remoteNode = (channel->GetDevice(1))->GetNode();
158 }
159 else
160 {
161 remoteNode = (channel->GetDevice(0))->GetNode();
162 }
163
164 // if it's not remote, don't consider it
165 if (remoteNode->GetSystemId() == MpiInterface::GetSystemId())
166 {
167 continue;
168 }
169
170 /**
171 * Add this channel to the remote channel bundle from this task to MPI task on other
172 * side of the channel.
173 */
174 Ptr<RemoteChannelBundle> remoteChannelBundle =
175 RemoteChannelBundleManager::Find(remoteNode->GetSystemId());
176 if (!remoteChannelBundle)
177 {
178 remoteChannelBundle =
179 RemoteChannelBundleManager::Add(remoteNode->GetSystemId());
180 }
181
182 TimeValue delay;
183 channel->GetAttribute("Delay", delay);
184 remoteChannelBundle->AddChannel(channel, delay.Get());
185 }
186 }
187 }
188
189 // Completed setup of remote channel bundles. Setup send and receive buffers.
191
192 // Initialized to 0 as we don't have a simulation start time.
193 m_safeTime = Time(0);
194}
195
196void
198{
199 NS_LOG_FUNCTION(this << schedulerFactory);
200
201 Ptr<Scheduler> scheduler = schedulerFactory.Create<Scheduler>();
202
203 if (m_events)
204 {
205 while (!m_events->IsEmpty())
206 {
207 Scheduler::Event next = m_events->RemoveNext();
208 scheduler->Insert(next);
209 }
210 }
211 m_events = scheduler;
212}
213
214void
216{
217 NS_LOG_FUNCTION(this);
218
219 Scheduler::Event next = m_events->RemoveNext();
220
221 PreEventHook(EventId(next.impl, next.key.m_ts, next.key.m_context, next.key.m_uid));
222
223 NS_ASSERT(next.key.m_ts >= m_currentTs);
225 m_eventCount++;
226
227 NS_LOG_LOGIC("handle " << next.key.m_ts);
228 m_currentTs = next.key.m_ts;
230 m_currentUid = next.key.m_uid;
231 next.impl->Invoke();
232 next.impl->Unref();
233}
234
235bool
237{
238 return m_events->IsEmpty() || m_stop;
239}
240
241Time
243{
244 NS_LOG_FUNCTION(this);
245
246 NS_ASSERT(!m_events->IsEmpty());
247
248 Scheduler::Event ev = m_events->PeekNext();
249 return TimeStep(ev.key.m_ts);
250}
251
252void
254{
255 NS_LOG_FUNCTION(this << bundle);
256
257 Time delay(m_schedulerTune * bundle->GetDelay().GetTimeStep());
258
259 bundle->SetEventId(Simulator::Schedule(delay,
261 this,
262 PeekPointer(bundle)));
263}
264
265void
267{
268 NS_LOG_FUNCTION(this << bundle);
269
270 Simulator::Cancel(bundle->GetEventId());
271
272 Time delay(m_schedulerTune * bundle->GetDelay().GetTimeStep());
273
274 bundle->SetEventId(Simulator::Schedule(delay,
276 this,
277 PeekPointer(bundle)));
278}
279
280void
290
291void
293{
294 NS_LOG_FUNCTION(this);
295
297
299
300 // Stop will be set if stop is called by simulation.
301 m_stop = false;
302 while (!IsFinished())
303 {
304 Time nextTime = Next();
305
306 if (nextTime <= GetSafeTime())
307 {
310 }
311 else
312 {
313 // Block until packet or Null Message has been received.
315 }
316 }
317}
318
319void
331
332void
344
345void
353
354Time
359
362{
363 return m_myId;
364}
365
366void
368{
369 NS_LOG_FUNCTION(this);
370
371 m_stop = true;
372}
373
376{
377 NS_LOG_FUNCTION(this << delay.GetTimeStep());
378
379 return Simulator::Schedule(delay, &Simulator::Stop);
380}
381
382//
383// Schedule an event for a _relative_ time in the future.
384//
387{
388 NS_LOG_FUNCTION(this << delay.GetTimeStep() << event);
389
390 Time tAbsolute = delay + TimeStep(m_currentTs);
391
392 NS_ASSERT(tAbsolute.IsPositive());
393 NS_ASSERT(tAbsolute >= TimeStep(m_currentTs));
395 ev.impl = event;
396 ev.key.m_ts = static_cast<uint64_t>(tAbsolute.GetTimeStep());
397 ev.key.m_context = GetContext();
398 ev.key.m_uid = m_uid;
399 m_uid++;
401 m_events->Insert(ev);
402 return EventId(event, ev.key.m_ts, ev.key.m_context, ev.key.m_uid);
403}
404
405void
407{
408 NS_LOG_FUNCTION(this << context << delay.GetTimeStep() << m_currentTs << event);
409
410 Time tAbsolute(m_currentTs + delay.GetTimeStep());
411
412 NS_ASSERT(tAbsolute.IsPositive());
413 NS_ASSERT(tAbsolute >= TimeStep(m_currentTs));
414
416 ev.impl = event;
417 ev.key.m_ts = tAbsolute.GetTimeStep();
418 ev.key.m_context = context;
419 ev.key.m_uid = m_uid;
420 m_uid++;
422 m_events->Insert(ev);
423}
424
427{
428 NS_LOG_FUNCTION(this << event);
429 return Schedule(Time(0), event);
430}
431
434{
435 NS_LOG_FUNCTION(this << event);
436
437 EventId id(Ptr<EventImpl>(event, false), m_currentTs, 0xffffffff, 2);
438 m_destroyEvents.push_back(id);
439 m_uid++;
440 return id;
441}
442
443Time
445{
446 return TimeStep(m_currentTs);
447}
448
449Time
451{
452 if (IsExpired(id))
453 {
454 return TimeStep(0);
455 }
456 else
457 {
458 return TimeStep(id.GetTs() - m_currentTs);
459 }
460}
461
462void
464{
465 if (id.GetUid() == EventId::UID::DESTROY)
466 {
467 // destroy events.
468 for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
469 {
470 if (*i == id)
471 {
472 m_destroyEvents.erase(i);
473 break;
474 }
475 }
476 return;
477 }
478 if (IsExpired(id))
479 {
480 return;
481 }
482 Scheduler::Event event;
483 event.impl = id.PeekEventImpl();
484 event.key.m_ts = id.GetTs();
485 event.key.m_context = id.GetContext();
486 event.key.m_uid = id.GetUid();
487 m_events->Remove(event);
488 event.impl->Cancel();
489 // whenever we remove an event from the event list, we have to unref it.
490 event.impl->Unref();
491
493}
494
495void
497{
498 if (!IsExpired(id))
499 {
500 id.PeekEventImpl()->Cancel();
501 }
502}
503
504bool
506{
507 if (id.GetUid() == EventId::UID::DESTROY)
508 {
509 if (id.PeekEventImpl() == nullptr || id.PeekEventImpl()->IsCancelled())
510 {
511 return true;
512 }
513 // destroy events.
514 for (auto i = m_destroyEvents.begin(); i != m_destroyEvents.end(); i++)
515 {
516 if (*i == id)
517 {
518 return false;
519 }
520 }
521 return true;
522 }
523 return id.PeekEventImpl() == nullptr || id.GetTs() < m_currentTs ||
524 (id.GetTs() == m_currentTs && id.GetUid() <= m_currentUid) ||
525 id.PeekEventImpl()->IsCancelled();
526}
527
528Time
530{
531 // XXX: I am fairly certain other compilers use other non-standard
532 // post-fixes to indicate 64 bit constants.
533 return TimeStep(0x7fffffffffffffffLL);
534}
535
541
542uint64_t
547
548Time
556
557void
567
574} // namespace ns3
#define Min(a, b)
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition double.h:31
An identifier for simulation events.
Definition event-id.h:45
@ INVALID
Invalid UID value.
Definition event-id.h:51
@ VALID
Schedule(), etc.
Definition event-id.h:59
@ DESTROY
ScheduleDestroy() events.
Definition event-id.h:55
A simulation event.
Definition event-impl.h:35
void Invoke()
Called by the simulation engine to notify the event that it is time to execute.
Definition event-impl.cc:36
void Cancel()
Marks the event as 'canceled'.
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.
keep track of a set of node pointers.
Iterator End() const
Get an iterator which indicates past-the-last Node in the container.
static NodeContainer GetGlobal()
Create a NodeContainer that contains a list of all nodes created through NodeContainer::Create() and ...
Iterator Begin() const
Get an iterator which refers to the first Node in the container.
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()
Initialize send and receive buffers.
Simulator implementation using MPI and a Null Message algorithm.
void CalculateLookAhead()
Calculate the lookahead allowable for this MPI task.
double m_schedulerTune
Null Message performance tuning parameter.
Ptr< Scheduler > m_events
The event priority queue.
void Remove(const EventId &id) override
Remove an event from the event list.
uint32_t m_currentUid
Unique id of the current event.
Time GetDelayLeft(const EventId &id) const override
Get the remaining time until this event will execute.
void HandleArrivingMessagesBlocking()
Blocking receive of arriving messages.
uint32_t m_systemCount
MPI communicator size.
void Run() override
Run the simulation.
void HandleArrivingMessagesNonBlocking()
Non blocking receive of pending messages.
uint32_t m_currentContext
Execution context of the current event.
void DoDispose() override
Destructor implementation.
uint32_t GetSystemId() const override
Get the system id of this simulator.
static NullMessageSimulatorImpl * GetInstance()
Time m_safeTime
The time for which it is safe for this task to execute events without danger of out-of-order events.
bool IsExpired(const EventId &id) const override
Check if an event has already run or been cancelled.
EventId ScheduleDestroy(EventImpl *event) override
Schedule an event to run at the end of the simulation, after the Stop() time or condition has been re...
static NullMessageSimulatorImpl * g_instance
Singleton instance.
void ProcessOneEvent()
Process the next event on the queue.
uint32_t m_uid
Next event unique id.
static TypeId GetTypeId()
Register this type.
uint64_t GetEventCount() const override
Get the number of events executed.
void SetScheduler(ObjectFactory schedulerFactory) override
Set the Scheduler to be used to manage the event list.
uint64_t m_currentTs
Timestamp of the current event.
Time GetMaximumSimulationTime() const override
Get the maximum representable simulation time.
void ScheduleWithContext(uint32_t context, const Time &delay, EventImpl *event) override
Schedule a future event execution (in a different context).
void NullMessageEventHandler(RemoteChannelBundle *bundle)
DestroyEvents m_destroyEvents
The container of events to run at Destroy()
void Cancel(const EventId &id) override
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
EventId Schedule(const Time &delay, EventImpl *event) override
Schedule a future event execution (in the same context).
uint32_t GetContext() const override
Get the current simulation context.
Time GetSafeTime()
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...
bool IsFinished() const override
Check if the simulation should finish.
void Stop() override
Tell the Simulator the calling event should be the last one executed.
void RescheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
bool m_stop
Flag calling for the end of the simulation.
Time Now() const override
Return the current simulation virtual time.
void Destroy() override
Execute the events scheduled with ScheduleDestroy().
void CalculateSafeTime()
Calculate the SafeTime.
void ScheduleNullMessageEvent(Ptr< RemoteChannelBundle > bundle)
EventId ScheduleNow(EventImpl *event) override
Schedule an event to run at the current virtual time.
Instantiate subclasses of ns3::Object.
Ptr< Object > Create() const
Create an Object instance of the configured TypeId.
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
Collection of ns-3 channels between local and remote nodes.
Time GetDelay() const
Get the minimum delay along any channel in this bundle.
static Time GetSafeTime()
Get the safe time across all channels in this bundle.
static Ptr< RemoteChannelBundle > Find(uint32_t systemId)
Get the bundle corresponding to a remote rank.
static void InitializeNullMessageEvents()
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 void Destroy()
Destroy the singleton.
Maintain the event list.
Definition scheduler.h:146
void Unref() const
Decrement the reference count.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
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:274
@ NO_CONTEXT
Flag for events not associated with any particular context.
Definition simulator.h:199
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition simulator.cc:175
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:94
bool IsPositive() const
Exactly equivalent to t >= 0.
Definition nstime.h:322
int64_t GetTimeStep() const
Get the raw time value, in the current resolution unit.
Definition nstime.h:434
Time Get() const
Definition time.cc:519
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#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:35
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Declaration of class ns3::MpiInterface.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition ptr.h:443
Ptr< const AttributeChecker > MakeDoubleChecker()
Definition double.h:82
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition double.h:32
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:173
EventKey key
Key for sorting and ordering Events.
Definition scheduler.h:175
EventImpl * impl
Pointer to the event implementation.
Definition scheduler.h:174
uint32_t m_context
Event context.
Definition scheduler.h:162
uint64_t m_ts
Event time stamp.
Definition scheduler.h:160
uint32_t m_uid
Event unique id.
Definition scheduler.h:161