A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
wifi-co-trace-helper.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Indraprastha Institute of Information Technology Delhi
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
8
9#include "ns3/assert.h"
10#include "ns3/log.h"
11#include "ns3/names.h"
12#include "ns3/net-device-container.h"
13#include "ns3/node-container.h"
14#include "ns3/node-list.h"
15#include "ns3/node.h"
16#include "ns3/pointer.h"
17#include "ns3/wifi-mac.h"
18#include "ns3/wifi-net-device.h"
19#include "ns3/wifi-phy-state-helper.h"
20#include "ns3/wifi-phy.h"
21
22#include <iomanip>
23#include <iostream>
24#include <sstream>
25#include <string>
26
27namespace ns3
28{
29
30NS_LOG_COMPONENT_DEFINE("WifiCoTraceHelper");
31
36
38{
39 NS_LOG_FUNCTION(this << startTime.As(Time::S) << stopTime.As(Time::S));
40 NS_ASSERT_MSG(startTime <= stopTime,
41 "Invalid Start: " << startTime << " and Stop: " << stopTime << " Time");
42
43 m_startTime = startTime;
45}
46
47void
49{
50 NS_LOG_FUNCTION(this << start.As(Time::S));
52 "Invalid Start: " << start << " and Stop: " << m_stopTime << " Time");
54 "Invalid Start: " << start << " less than Now(): " << Simulator::Now());
55 m_startTime = start;
56}
57
58void
60{
61 NS_LOG_FUNCTION(this << stop.As(Time::S));
63 "Invalid Start: " << m_startTime << " and Stop: " << stop << " Time");
65 "Invalid Stop: " << stop << " less than Now(): " << Simulator::Now());
66
67 m_stopTime = stop;
68}
69
70void
72{
73 NS_LOG_FUNCTION(this);
74
75 for (auto& record : m_deviceRecords)
76 {
77 record.m_linkStateDurations.clear();
78 }
79}
80
81void
83{
84 NS_LOG_FUNCTION(this << nodes.GetN());
85 NetDeviceContainer netDevices;
86 for (uint32_t i = 0; i < nodes.GetN(); ++i)
87 {
88 for (uint32_t j = 0; j < nodes.Get(i)->GetNDevices(); ++j)
89 {
90 netDevices.Add(nodes.Get(i)->GetDevice(j));
91 }
92 }
93 Enable(netDevices);
94}
95
96void
98{
99 NS_LOG_FUNCTION(this << devices.GetN());
100
101 for (uint32_t j = 0; j < devices.GetN(); ++j)
102 {
103 auto device = DynamicCast<WifiNetDevice>(devices.Get(j));
104 if (!device)
105 {
106 NS_LOG_INFO("Ignoring deviceId: " << devices.Get(j)->GetIfIndex() << " on nodeId: "
107 << devices.Get(j)->GetNode()->GetId()
108 << " because it is not of type WifiNetDevice");
109 continue;
110 }
111 const auto idx = m_numDevices++;
112 m_deviceRecords.emplace_back(device);
113
114 for (uint32_t k = 0; k < device->GetNPhys(); ++k)
115 {
116 auto wifiPhyStateHelper = device->GetPhy(k)->GetState();
117 auto linkCallback =
119 wifiPhyStateHelper->TraceConnectWithoutContext("State", linkCallback);
120 }
121 }
122}
123
124void
126{
127 NS_LOG_FUNCTION(this);
128 NS_ASSERT_MSG(m_deviceRecords.size() == m_numDevices, "m_deviceRecords size mismatch");
129
130 for (size_t i = 0; i < m_numDevices; ++i)
131 {
132 auto nodeName = m_deviceRecords[i].m_nodeName;
133 auto deviceName = m_deviceRecords[i].m_deviceName;
134 if (nodeName.empty())
135 {
136 nodeName = std::to_string(m_deviceRecords[i].m_nodeId);
137 }
138 if (deviceName.empty())
139 {
140 deviceName = std::to_string(m_deviceRecords[i].m_ifIndex);
141 }
142 auto numLinks = m_deviceRecords[i].m_linkStateDurations.size();
143 if (numLinks == 1)
144 {
145 auto& statistics = m_deviceRecords[i].m_linkStateDurations.begin()->second;
146 os << "\n"
147 << "---- COT for " << nodeName << ":" << deviceName << " ----"
148 << "\n";
149 PrintLinkStates(os, statistics, unit);
150 }
151 else if (numLinks > 1)
152 {
153 os << "\nDevice \"" << nodeName << ":" << deviceName
154 << "\" has statistics for multiple links: "
155 << "\n";
156 for (auto& linkStates : m_deviceRecords[i].m_linkStateDurations)
157 {
158 os << "\n"
159 << "---- COT for " << nodeName << ":" << deviceName << "#Link"
160 << std::to_string(linkStates.first) << " ---"
161 << "\n";
162 PrintLinkStates(os, linkStates.second, unit);
163 }
164 }
165 else
166 {
167 os << "\nDevice \"" << nodeName << ":" << deviceName << "\" has no statistics."
168 << "\n";
169 }
170 }
171 os << "\n";
172}
173
174std::ostream&
176 const std::map<WifiPhyState, Time>& linkStates,
177 Time::Unit unit) const
178{
179 NS_LOG_FUNCTION(this);
180 os << "Showing duration by states: "
181 << "\n";
182
183 const auto percents = ComputePercentage(linkStates);
184 const auto showPercents = !percents.empty();
185
186 std::vector<std::string> stateColumn{};
187 std::vector<std::string> durationColumn{};
188 std::vector<std::string> percentColumn{};
189
190 for (const auto& it : linkStates)
191 {
192 std::stringstream stateStream;
193 stateStream << it.first << ": ";
194 stateColumn.emplace_back(stateStream.str());
195
196 std::stringstream durationStream;
197 durationStream << std::showpoint << std::fixed << std::setprecision(2)
198 << it.second.As(unit);
199 durationColumn.emplace_back(durationStream.str());
200
201 if (showPercents)
202 {
203 std::stringstream percentStream;
204 percentStream << std::showpoint << std::fixed << std::setprecision(2) << " ("
205 << percents.at(it.first) << "%)";
206 percentColumn.emplace_back(percentStream.str());
207 }
208 }
209
210 AlignDecimal(durationColumn);
211 if (showPercents)
212 {
213 AlignDecimal(percentColumn);
214 }
215 AlignWidth(stateColumn);
216 AlignWidth(durationColumn);
217
218 for (size_t i = 0; i < stateColumn.size(); ++i)
219 {
220 os << stateColumn.at(i) << durationColumn.at(i);
221 if (showPercents)
222 {
223 os << percentColumn.at(i);
224 }
225 os << "\n";
226 }
227
228 return os;
229}
230
231void
232WifiCoTraceHelper::AlignDecimal(std::vector<std::string>& column) const
233{
234 size_t maxPos = 0;
235 char decimal = '.';
236
237 for (auto& s : column)
238 {
239 size_t pos = s.find_first_of(decimal);
240 if (pos > maxPos)
241 {
242 maxPos = pos;
243 }
244 }
245
246 for (auto& s : column)
247 {
248 auto padding = std::string(maxPos - s.find_first_of(decimal), ' ');
249 s = padding + s;
250 }
251}
252
253void
254WifiCoTraceHelper::AlignWidth(std::vector<std::string>& column) const
255{
256 size_t maxWidth = 0;
257
258 for (auto& s : column)
259 {
260 size_t width = s.length();
261 if (width > maxWidth)
262 {
263 maxWidth = width;
264 }
265 }
266
267 for (auto& s : column)
268 {
269 auto padding = std::string(maxWidth - s.length(), ' ');
270 s = s + padding;
271 }
272}
273
274std::map<WifiPhyState, double>
275WifiCoTraceHelper::ComputePercentage(const std::map<WifiPhyState, Time>& linkStates) const
276{
277 NS_LOG_FUNCTION(this);
278 Time total;
279 for (const auto& it : linkStates)
280 {
281 total += it.second;
282 }
283
284 if (total.IsZero())
285 {
286 return {};
287 }
288
289 std::map<WifiPhyState, double> percents;
290 for (const auto& it : linkStates)
291 {
292 percents[it.first] = it.second.GetDouble() * 100.0 / total.GetDouble();
293 }
294
295 return percents;
296}
297
298const std::vector<WifiCoTraceHelper::DeviceRecord>&
303
304void
306 std::size_t phyId,
307 Time start,
308 Time duration,
309 WifiPhyState state)
310{
311 NS_LOG_FUNCTION(this << idx << phyId << start.As(Time::S) << duration.As(Time::US) << state);
312 NS_ASSERT_MSG(duration.IsPositive(), "Duration shouldn't be negative: " << duration.As());
313 NS_ASSERT_MSG(idx < m_deviceRecords.size(), "Index out-of-bounds");
314
315 // Compute duration that overlaps with [m_startTime, m_stopTime]
316 const auto overlappingDuration =
317 ComputeOverlappingDuration(m_startTime, m_stopTime, start, start + duration);
318
319 if (!overlappingDuration.IsZero())
320 {
321 const auto nodeId = m_deviceRecords[idx].m_nodeId;
322 const auto deviceId = m_deviceRecords[idx].m_ifIndex;
323 const auto device = NodeList::GetNode(nodeId)->GetDevice(deviceId);
324 const auto wifiDevice = DynamicCast<WifiNetDevice>(device);
325 NS_ASSERT_MSG(wifiDevice, "Error, Device type is not WifiNetDevice.");
326
327 auto linkId = wifiDevice->GetMac()->GetLinkForPhy(phyId);
328
329 if (linkId.has_value())
330 {
331 NS_LOG_INFO("Add device node "
332 << m_deviceRecords[idx].m_nodeId << " index "
333 << m_deviceRecords[idx].m_ifIndex << " linkId " << *linkId << " duration "
334 << overlappingDuration.As(Time::US) << " state " << state);
335 m_deviceRecords[idx].AddLinkMeasurement(*linkId, start, overlappingDuration, state);
336 }
337 else
338 {
339 NS_LOG_DEBUG("LinkId not found for phyId:" << phyId);
340 }
341 }
342}
343
344Time
346{
347 const auto Zero{Seconds(0)};
348
349 NS_ASSERT_MSG(start1 >= Zero && stop1 >= Zero && start1 <= stop1,
350 "Interval: [" << start1 << "," << stop1 << "] is invalid.");
351 NS_ASSERT_MSG(start2 >= Zero && stop2 >= Zero && start2 <= stop2,
352 "Interval: [" << start2 << "," << stop2 << "] is invalid.");
353
354 const auto maxStart = Max(start1, start2);
355 const auto minStop = Min(stop1, stop2);
356 const auto duration = minStop - maxStart;
357
358 return duration > Zero ? duration : Zero;
359}
360
362 : m_nodeId(device->GetNode()->GetId()),
363 m_ifIndex(device->GetIfIndex())
364{
365 NS_LOG_FUNCTION(this << device);
366 if (!Names::FindName(device->GetNode()).empty())
367 {
368 m_nodeName = Names::FindName(device->GetNode());
369 }
370 if (!Names::FindName(device).empty())
371 {
373 }
374}
375
376void
378 Time start,
379 Time duration,
380 WifiPhyState state)
381{
382 NS_LOG_FUNCTION(this << linkId << start.As(Time::S) << duration.As(Time::S) << state);
383 auto& stateDurations = m_linkStateDurations[linkId];
384 stateDurations[state] += duration;
385}
386
387} // namespace ns3
#define Max(a, b)
#define Min(a, b)
static std::string FindName(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and,...
Definition names.cc:818
holds a vector of ns3::NetDevice pointers
void Add(NetDeviceContainer other)
Append the contents of another NetDeviceContainer to the end of this container.
keep track of a set of node pointers.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition node.cc:138
static Ptr< Node > GetNode(uint32_t n)
Definition node-list.cc:240
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
bool IsPositive() const
Exactly equivalent to t >= 0.
Definition nstime.h:322
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
Unit
The unit to use to interpret a number representing time.
Definition nstime.h:100
@ US
microsecond
Definition nstime.h:107
@ S
second
Definition nstime.h:105
double GetDouble() const
Get the raw time value, in the current resolution unit.
Definition nstime.h:439
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
std::map< WifiPhyState, double > ComputePercentage(const std::map< WifiPhyState, Time > &linkStates) const
A helper function used by PrintStatistics method.
void AlignWidth(std::vector< std::string > &column) const
A helper function used by PrintLinkStates method to format the output.
Time ComputeOverlappingDuration(Time start1, Time stop1, Time start2, Time stop2)
Compute overlapping time-duration between two intervals.
void Stop(Time stopTime)
Stops the collection of statistics at a specified time.
void Enable(NodeContainer nodes)
Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
void PrintStatistics(std::ostream &os, Time::Unit unit=Time::Unit::AUTO) const
Print measurement results on an output stream.
Time m_stopTime
Instant at which statistics collection should stop.
void Start(Time startTime)
Starts the collection of statistics from a specified start time.
Time m_startTime
Instant at which statistics collection should start.
std::ostream & PrintLinkStates(std::ostream &os, const std::map< WifiPhyState, Time > &linkStates, Time::Unit unit) const
A helper function used by PrintStatistics method.
void NotifyWifiPhyState(std::size_t idx, std::size_t phyId, Time start, Time duration, WifiPhyState state)
A callback used to update statistics.
std::vector< DeviceRecord > m_deviceRecords
Stores the collected statistics.
const std::vector< DeviceRecord > & GetDeviceRecords() const
Returns measurement results on each installed device.
void AlignDecimal(std::vector< std::string > &column) const
A helper function used by PrintLinkStates method to format the output.
uint32_t m_numDevices
Count the number of devices traced by this helper.
void Reset()
Resets the current statistics, clearing all links and their durations.
WifiCoTraceHelper()
Default Constructor.
Time stopTime
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1344
NodeContainer nodes
Every class exported by the ns3 library is enclosed in the ns3 namespace.
WifiPhyState
The state of the PHY layer.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580
void AddLinkMeasurement(size_t linkId, Time start, Time duration, WifiPhyState state)
Update the duration statistics for the provided linkId and state.
std::string m_deviceName
Device name. It's empty if the name isn't configured.
DeviceRecord(Ptr< WifiNetDevice > device)
Constructor.
std::string m_nodeName
Name of Node on which the WifiNetDevice is installed.