A Discrete-Event Network Simulator
Home
Tutorials ▼
English
Portuguese
Docs ▼
Wiki
Manual
Models
Develop ▼
API
Bugs
API
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Properties
Friends
Macros
Groups
Pages
distributed-simulator-impl.cc
Go to the documentation of this file.
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/*
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License version 2 as
5
* published by the Free Software Foundation;
6
*
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
11
*
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
*
16
* Author: George Riley <riley@ece.gatech.edu>
17
*/
18
19
#include "
distributed-simulator-impl.h
"
20
#include "
mpi-interface.h
"
21
22
#include "ns3/simulator.h"
23
#include "ns3/scheduler.h"
24
#include "ns3/event-impl.h"
25
#include "ns3/channel.h"
26
#include "ns3/node-container.h"
27
#include "ns3/ptr.h"
28
#include "ns3/pointer.h"
29
#include "ns3/assert.h"
30
#include "ns3/log.h"
31
32
#include <cmath>
33
34
#ifdef NS3_MPI
35
#include <mpi.h>
36
#endif
37
38
NS_LOG_COMPONENT_DEFINE
(
"DistributedSimulatorImpl"
);
39
40
namespace
ns3 {
41
42
NS_OBJECT_ENSURE_REGISTERED
(DistributedSimulatorImpl);
43
44
LbtsMessage::~LbtsMessage
()
45
{
46
}
47
48
Time
49
LbtsMessage::GetSmallestTime
()
50
{
51
return
m_smallestTime
;
52
}
53
54
uint32_t
55
LbtsMessage::GetTxCount
()
56
{
57
return
m_txCount
;
58
}
59
60
uint32_t
61
LbtsMessage::GetRxCount
()
62
{
63
return
m_rxCount
;
64
}
65
uint32_t
66
LbtsMessage::GetMyId
()
67
{
68
return
m_myId
;
69
}
70
71
Time
DistributedSimulatorImpl::m_lookAhead
=
Seconds
(0);
72
73
TypeId
74
DistributedSimulatorImpl::GetTypeId
(
void
)
75
{
76
static
TypeId
tid =
TypeId
(
"ns3::DistributedSimulatorImpl"
)
77
.
SetParent
<
Object
> ()
78
.AddConstructor<DistributedSimulatorImpl> ()
79
;
80
return
tid;
81
}
82
83
DistributedSimulatorImpl::DistributedSimulatorImpl
()
84
{
85
#ifdef NS3_MPI
86
m_myId
=
MpiInterface::GetSystemId
();
87
m_systemCount
=
MpiInterface::GetSize
();
88
89
// Allocate the LBTS message buffer
90
m_pLBTS
=
new
LbtsMessage
[
m_systemCount
];
91
m_grantedTime
=
Seconds
(0);
92
#else
93
NS_FATAL_ERROR
(
"Can't use distributed simulator without MPI compiled in"
);
94
#endif
95
96
m_stop
=
false
;
97
// uids are allocated from 4.
98
// uid 0 is "invalid" events
99
// uid 1 is "now" events
100
// uid 2 is "destroy" events
101
m_uid
= 4;
102
// before ::Run is entered, the m_currentUid will be zero
103
m_currentUid
= 0;
104
m_currentTs
= 0;
105
m_currentContext
= 0xffffffff;
106
m_unscheduledEvents
= 0;
107
m_events
= 0;
108
}
109
110
DistributedSimulatorImpl::~DistributedSimulatorImpl
()
111
{
112
}
113
114
void
115
DistributedSimulatorImpl::DoDispose
(
void
)
116
{
117
while
(!
m_events
->
IsEmpty
())
118
{
119
Scheduler::Event
next =
m_events
->
RemoveNext
();
120
next.
impl
->
Unref
();
121
}
122
m_events
= 0;
123
delete
[]
m_pLBTS
;
124
SimulatorImpl::DoDispose
();
125
}
126
127
void
128
DistributedSimulatorImpl::Destroy
()
129
{
130
while
(!
m_destroyEvents
.empty ())
131
{
132
Ptr<EventImpl>
ev =
m_destroyEvents
.front ().PeekEventImpl ();
133
m_destroyEvents
.pop_front ();
134
NS_LOG_LOGIC
(
"handle destroy "
<< ev);
135
if
(!ev->
IsCancelled
())
136
{
137
ev->
Invoke
();
138
}
139
}
140
141
MpiInterface::Destroy
();
142
}
143
144
145
void
146
DistributedSimulatorImpl::CalculateLookAhead
(
void
)
147
{
148
#ifdef NS3_MPI
149
if
(
MpiInterface::GetSize
() <= 1)
150
{
151
DistributedSimulatorImpl::m_lookAhead
=
Seconds
(0);
152
m_grantedTime
=
Seconds
(0);
153
}
154
else
155
{
156
NodeContainer
c =
NodeContainer::GetGlobal
();
157
for
(
NodeContainer::Iterator
iter = c.
Begin
(); iter != c.
End
(); ++iter)
158
{
159
if
((*iter)->GetSystemId () !=
MpiInterface::GetSystemId
())
160
{
161
continue
;
162
}
163
164
for
(uint32_t i = 0; i < (*iter)->GetNDevices (); ++i)
165
{
166
Ptr<NetDevice>
localNetDevice = (*iter)->GetDevice (i);
167
// only works for p2p links currently
168
if
(!localNetDevice->
IsPointToPoint
())
169
{
170
continue
;
171
}
172
Ptr<Channel>
channel = localNetDevice->
GetChannel
();
173
if
(channel == 0)
174
{
175
continue
;
176
}
177
178
// grab the adjacent node
179
Ptr<Node>
remoteNode;
180
if
(channel->
GetDevice
(0) == localNetDevice)
181
{
182
remoteNode = (channel->
GetDevice
(1))->GetNode ();
183
}
184
else
185
{
186
remoteNode = (channel->
GetDevice
(0))->GetNode ();
187
}
188
189
// if it's not remote, don't consider it
190
if
(remoteNode->
GetSystemId
() ==
MpiInterface::GetSystemId
())
191
{
192
continue
;
193
}
194
195
// compare delay on the channel with current value of
196
// m_lookAhead. if delay on channel is smaller, make
197
// it the new lookAhead.
198
TimeValue
delay;
199
channel->
GetAttribute
(
"Delay"
, delay);
200
if
(
DistributedSimulatorImpl::m_lookAhead
.IsZero ())
201
{
202
DistributedSimulatorImpl::m_lookAhead
= delay.
Get
();
203
m_grantedTime
= delay.
Get
();
204
}
205
if
(delay.
Get
().
GetSeconds
() <
DistributedSimulatorImpl::m_lookAhead
.
GetSeconds
())
206
{
207
DistributedSimulatorImpl::m_lookAhead
= delay.
Get
();
208
m_grantedTime
= delay.
Get
();
209
}
210
}
211
}
212
}
213
#else
214
NS_FATAL_ERROR
(
"Can't use distributed simulator without MPI compiled in"
);
215
#endif
216
}
217
218
void
219
DistributedSimulatorImpl::SetScheduler
(
ObjectFactory
schedulerFactory)
220
{
221
Ptr<Scheduler>
scheduler = schedulerFactory.
Create
<
Scheduler
> ();
222
223
if
(
m_events
!= 0)
224
{
225
while
(!
m_events
->
IsEmpty
())
226
{
227
Scheduler::Event
next =
m_events
->
RemoveNext
();
228
scheduler->
Insert
(next);
229
}
230
}
231
m_events
= scheduler;
232
}
233
234
void
235
DistributedSimulatorImpl::ProcessOneEvent
(
void
)
236
{
237
Scheduler::Event
next =
m_events
->
RemoveNext
();
238
239
NS_ASSERT
(next.
key
.
m_ts
>=
m_currentTs
);
240
m_unscheduledEvents
--;
241
242
NS_LOG_LOGIC
(
"handle "
<< next.
key
.
m_ts
);
243
m_currentTs
= next.
key
.
m_ts
;
244
m_currentContext
= next.
key
.
m_context
;
245
m_currentUid
= next.
key
.
m_uid
;
246
next.
impl
->
Invoke
();
247
next.
impl
->
Unref
();
248
}
249
250
bool
251
DistributedSimulatorImpl::IsFinished
(
void
)
const
252
{
253
return
m_events
->
IsEmpty
() ||
m_stop
;
254
}
255
256
uint64_t
257
DistributedSimulatorImpl::NextTs
(
void
)
const
258
{
259
NS_ASSERT
(!
m_events
->
IsEmpty
());
260
Scheduler::Event
ev =
m_events
->
PeekNext
();
261
return
ev.
key
.
m_ts
;
262
}
263
264
Time
265
DistributedSimulatorImpl::Next
(
void
)
const
266
{
267
return
TimeStep
(
NextTs
());
268
}
269
270
void
271
DistributedSimulatorImpl::Run
(
void
)
272
{
273
#ifdef NS3_MPI
274
CalculateLookAhead
();
275
m_stop
=
false
;
276
while
(!
m_events
->
IsEmpty
() && !
m_stop
)
277
{
278
Time
nextTime =
Next
();
279
if
(nextTime >
m_grantedTime
)
280
{
// Can't process, calculate a new LBTS
281
// First receive any pending messages
282
MpiInterface::ReceiveMessages
();
283
// reset next time
284
nextTime =
Next
();
285
// And check for send completes
286
MpiInterface::TestSendComplete
();
287
// Finally calculate the lbts
288
LbtsMessage
lMsg (
MpiInterface::GetRxCount
(),
MpiInterface::GetTxCount
(),
m_myId
, nextTime);
289
m_pLBTS
[
m_myId
] = lMsg;
290
MPI_Allgather (&lMsg,
sizeof
(
LbtsMessage
), MPI_BYTE,
m_pLBTS
,
291
sizeof
(
LbtsMessage
), MPI_BYTE, MPI_COMM_WORLD);
292
Time
smallestTime =
m_pLBTS
[0].
GetSmallestTime
();
293
// The totRx and totTx counts insure there are no transient
294
// messages; If totRx != totTx, there are transients,
295
// so we don't update the granted time.
296
uint32_t totRx =
m_pLBTS
[0].
GetRxCount
();
297
uint32_t totTx =
m_pLBTS
[0].
GetTxCount
();
298
299
for
(uint32_t i = 1; i <
m_systemCount
; ++i)
300
{
301
if
(
m_pLBTS
[i].GetSmallestTime () < smallestTime)
302
{
303
smallestTime =
m_pLBTS
[i].
GetSmallestTime
();
304
}
305
totRx +=
m_pLBTS
[i].
GetRxCount
();
306
totTx +=
m_pLBTS
[i].
GetTxCount
();
307
308
}
309
if
(totRx == totTx)
310
{
311
m_grantedTime
= smallestTime +
DistributedSimulatorImpl::m_lookAhead
;
312
}
313
}
314
if
(nextTime <=
m_grantedTime
)
315
{
// Save to process
316
ProcessOneEvent
();
317
}
318
}
319
320
// If the simulator stopped naturally by lack of events, make a
321
// consistency test to check that we didn't lose any events along the way.
322
NS_ASSERT
(!
m_events
->
IsEmpty
() ||
m_unscheduledEvents
== 0);
323
#else
324
NS_FATAL_ERROR
(
"Can't use distributed simulator without MPI compiled in"
);
325
#endif
326
}
327
328
uint32_t
DistributedSimulatorImpl::GetSystemId
()
const
329
{
330
return
m_myId
;
331
}
332
333
void
334
DistributedSimulatorImpl::Stop
(
void
)
335
{
336
m_stop
=
true
;
337
}
338
339
void
340
DistributedSimulatorImpl::Stop
(
Time
const
&time)
341
{
342
Simulator::Schedule
(time, &
Simulator::Stop
);
343
}
344
345
//
346
// Schedule an event for a _relative_ time in the future.
347
//
348
EventId
349
DistributedSimulatorImpl::Schedule
(
Time
const
&time,
EventImpl
*event)
350
{
351
Time
tAbsolute = time +
TimeStep
(
m_currentTs
);
352
353
NS_ASSERT
(tAbsolute.
IsPositive
());
354
NS_ASSERT
(tAbsolute >= TimeStep (
m_currentTs
));
355
Scheduler::Event
ev;
356
ev.
impl
= event;
357
ev.
key
.
m_ts
=
static_cast<
uint64_t
>
(tAbsolute.
GetTimeStep
());
358
ev.
key
.
m_context
=
GetContext
();
359
ev.
key
.
m_uid
=
m_uid
;
360
m_uid
++;
361
m_unscheduledEvents
++;
362
m_events
->
Insert
(ev);
363
return
EventId
(event, ev.
key
.
m_ts
, ev.
key
.
m_context
, ev.
key
.
m_uid
);
364
}
365
366
void
367
DistributedSimulatorImpl::ScheduleWithContext
(uint32_t context,
Time
const
&time,
EventImpl
*event)
368
{
369
NS_LOG_FUNCTION
(
this
<< context << time.
GetTimeStep
() <<
m_currentTs
<< event);
370
371
Scheduler::Event
ev;
372
ev.
impl
= event;
373
ev.key.m_ts =
m_currentTs
+ time.
GetTimeStep
();
374
ev.key.m_context = context;
375
ev.key.m_uid =
m_uid
;
376
m_uid
++;
377
m_unscheduledEvents
++;
378
m_events
->
Insert
(ev);
379
}
380
381
EventId
382
DistributedSimulatorImpl::ScheduleNow
(
EventImpl
*event)
383
{
384
Scheduler::Event
ev;
385
ev.
impl
= event;
386
ev.
key
.
m_ts
=
m_currentTs
;
387
ev.
key
.
m_context
=
GetContext
();
388
ev.
key
.
m_uid
=
m_uid
;
389
m_uid
++;
390
m_unscheduledEvents
++;
391
m_events
->
Insert
(ev);
392
return
EventId
(event, ev.
key
.
m_ts
, ev.
key
.
m_context
, ev.
key
.
m_uid
);
393
}
394
395
EventId
396
DistributedSimulatorImpl::ScheduleDestroy
(
EventImpl
*event)
397
{
398
EventId
id (
Ptr<EventImpl>
(event,
false
),
m_currentTs
, 0xffffffff, 2);
399
m_destroyEvents
.push_back (
id
);
400
m_uid
++;
401
return
id;
402
}
403
404
Time
405
DistributedSimulatorImpl::Now
(
void
)
const
406
{
407
return
TimeStep
(
m_currentTs
);
408
}
409
410
Time
411
DistributedSimulatorImpl::GetDelayLeft
(
const
EventId
&
id
)
const
412
{
413
if
(
IsExpired
(
id
))
414
{
415
return
TimeStep
(0);
416
}
417
else
418
{
419
return
TimeStep
(
id
.GetTs () -
m_currentTs
);
420
}
421
}
422
423
void
424
DistributedSimulatorImpl::Remove
(
const
EventId
&
id
)
425
{
426
if
(
id
.GetUid () == 2)
427
{
428
// destroy events.
429
for
(DestroyEvents::iterator i =
m_destroyEvents
.begin (); i !=
m_destroyEvents
.end (); i++)
430
{
431
if
(*i ==
id
)
432
{
433
m_destroyEvents
.erase (i);
434
break
;
435
}
436
}
437
return
;
438
}
439
if
(
IsExpired
(
id
))
440
{
441
return
;
442
}
443
Scheduler::Event
event;
444
event
.
impl
=
id
.PeekEventImpl ();
445
event
.key.m_ts =
id
.GetTs ();
446
event
.key.m_context =
id
.GetContext ();
447
event
.key.m_uid =
id
.GetUid ();
448
m_events
->
Remove
(event);
449
event
.impl->Cancel ();
450
// whenever we remove an event from the event list, we have to unref it.
451
event
.impl->Unref ();
452
453
m_unscheduledEvents
--;
454
}
455
456
void
457
DistributedSimulatorImpl::Cancel
(
const
EventId
&
id
)
458
{
459
if
(!
IsExpired
(
id
))
460
{
461
id
.PeekEventImpl ()->Cancel ();
462
}
463
}
464
465
bool
466
DistributedSimulatorImpl::IsExpired
(
const
EventId
&ev)
const
467
{
468
if
(ev.
GetUid
() == 2)
469
{
470
if
(ev.
PeekEventImpl
() == 0
471
|| ev.
PeekEventImpl
()->
IsCancelled
())
472
{
473
return
true
;
474
}
475
// destroy events.
476
for
(DestroyEvents::const_iterator i =
m_destroyEvents
.begin (); i !=
m_destroyEvents
.end (); i++)
477
{
478
if
(*i == ev)
479
{
480
return
false
;
481
}
482
}
483
return
true
;
484
}
485
if
(ev.
PeekEventImpl
() == 0
486
|| ev.
GetTs
() <
m_currentTs
487
|| (ev.
GetTs
() ==
m_currentTs
488
&& ev.
GetUid
() <=
m_currentUid
)
489
|| ev.
PeekEventImpl
()->
IsCancelled
())
490
{
491
return
true
;
492
}
493
else
494
{
495
return
false
;
496
}
497
}
498
499
Time
500
DistributedSimulatorImpl::GetMaximumSimulationTime
(
void
)
const
501
{
502
// XXX: I am fairly certain other compilers use other non-standard
503
// post-fixes to indicate 64 bit constants.
504
return
TimeStep
(0x7fffffffffffffffLL);
505
}
506
507
uint32_t
508
DistributedSimulatorImpl::GetContext
(
void
)
const
509
{
510
return
m_currentContext
;
511
}
512
513
}
// namespace ns3
src
mpi
model
distributed-simulator-impl.cc
Generated on Tue May 14 2013 11:08:29 for ns-3 by
1.8.1.2