13#include "ns3/frame-exchange-manager.h"
15#include "ns3/net-device-container.h"
16#include "ns3/node-container.h"
17#include "ns3/wifi-mac-queue.h"
18#include "ns3/wifi-net-device.h"
38 "Invalid Start: " << startTime <<
" and Stop: " <<
stopTime <<
" Time");
50 netDevices.
Add(
nodes.Get(i)->GetDevice(j));
61 for (
uint32_t j = 0; j < devices.GetN(); ++j)
66 NS_LOG_DEBUG(
"Ignoring deviceId: " << devices.Get(j)->GetIfIndex() <<
" on nodeId: "
67 << devices.Get(j)->GetNode()->GetId()
68 <<
" because it is not of type WifiNetDevice");
71 NS_LOG_INFO(
"Adding deviceId: " << devices.Get(j)->GetIfIndex()
72 <<
" on nodeId: " << devices.Get(j)->GetNode()->GetId());
73 const auto nodeId = devices.Get(j)->GetNode()->GetId();
74 const auto deviceId = devices.Get(j)->GetIfIndex();
75 if (device->GetMac()->GetQosSupported())
80 device->GetMac()->GetTxopQueue(ac)->TraceConnectWithoutContext(
83 .Bind(nodeId, deviceId));
91 ->TraceConnectWithoutContext(
94 .Bind(nodeId, deviceId));
96 device->GetMac()->TraceConnectWithoutContext(
99 device->GetMac()->TraceConnectWithoutContext(
102 for (
int i = 0; i < device->GetNPhys(); ++i)
104 device->GetPhy(i)->TraceConnectWithoutContext(
115 NS_ASSERT_MSG(startTime >=
Now(),
"Invalid Start: " << startTime <<
" less than current time");
117 "Invalid Start: " << startTime <<
" and Stop: " <<
m_stopTime <<
" Time");
144 for (
const auto& [nodeDevTuple, records] :
m_successMap)
146 results[{std::get<0>(nodeDevTuple), std::get<1>(nodeDevTuple)}] = records.size();
155 for (
const auto& [nodeDevTuple, records] :
m_successMap)
157 for (
const auto& record : records)
159 NS_ASSERT_MSG(!record.m_successLinkIdSet.empty(),
"No LinkId set on MPDU");
162 const auto firstLinkId = *record.m_successLinkIdSet.begin();
163 const auto nodeDevLinkTuple =
164 std::tuple<uint32_t, uint32_t, uint8_t>(std::get<0>(nodeDevTuple),
165 std::get<1>(nodeDevTuple),
167 if (
auto countIt = results.find(nodeDevLinkTuple); countIt != results.end())
173 results[nodeDevLinkTuple] = 1;
178 for (
const auto linkId : record.m_successLinkIdSet)
180 const auto nodeDevLinkTuple =
181 std::tuple<uint32_t, uint32_t, uint8_t>(std::get<0>(nodeDevTuple),
182 std::get<1>(nodeDevTuple),
184 if (
auto countIt = results.find(nodeDevLinkTuple); countIt != results.end())
190 results[nodeDevLinkTuple] = 1;
203 for (
const auto& [nodeDevTuple, records] :
m_failureMap)
205 results[{std::get<0>(nodeDevTuple), std::get<1>(nodeDevTuple)}] = records.size();
214 for (
const auto& [nodeDevTuple, records] :
m_failureMap)
216 for (
const auto& record : records)
218 NS_ASSERT_MSG(record.m_dropTime.has_value() && record.m_dropReason.has_value(),
219 "Incomplete dropped MPDU record");
220 if (record.m_dropReason == reason)
223 results.find({std::get<0>(nodeDevTuple), std::get<1>(nodeDevTuple)});
224 countIt != results.end())
230 results[{std::get<0>(nodeDevTuple), std::get<1>(nodeDevTuple)}] = 1;
242 for (
const auto& [nodeDevLinkTuple, records] :
m_successMap)
244 for (
const auto& record : records)
247 results.find({std::get<0>(nodeDevLinkTuple), std::get<1>(nodeDevLinkTuple)});
248 countIt != results.end())
250 countIt->second += record.m_retransmissions;
254 results[{std::get<0>(nodeDevLinkTuple), std::get<1>(nodeDevLinkTuple)}] =
255 record.m_retransmissions;
266 for (
const auto& [nodeDevLinkTuple, records] :
m_successMap)
268 count += records.size();
277 for (
const auto& [nodeDevTuple, records] :
m_failureMap)
279 count += records.size();
288 for (
const auto& [nodeDevTuple, records] :
m_failureMap)
290 for (
const auto& record : records)
292 NS_ASSERT_MSG(record.m_dropTime.has_value() && record.m_dropReason.has_value(),
293 "Incomplete dropped MPDU record");
294 if (record.m_dropReason == reason)
307 for (
const auto& [nodeDevTuple, records] :
m_successMap)
309 for (
const auto& record : records)
311 count += record.m_retransmissions;
327 for (
const auto& [nodeDevTuple, records] :
m_successMap)
329 for (
const auto& record : records)
331 NS_ASSERT_MSG(!record.m_successLinkIdSet.empty(),
"No LinkId set on MPDU");
334 const auto firstLinkId = *record.m_successLinkIdSet.begin();
335 const auto nodeDevLinkTuple =
336 std::tuple<uint32_t, uint32_t, uint8_t>(std::get<0>(nodeDevTuple),
337 std::get<1>(nodeDevTuple),
339 results[nodeDevLinkTuple].emplace_back(record);
343 for (
const auto linkId : record.m_successLinkIdSet)
345 const auto nodeDevLinkTuple =
346 std::tuple<uint32_t, uint32_t, uint8_t>(std::get<0>(nodeDevTuple),
347 std::get<1>(nodeDevTuple),
349 results[nodeDevLinkTuple].emplace_back(record);
370 NS_LOG_DEBUG(
"Ignoring enqueue because helper is stopped");
373 if (mpdu->GetHeader().IsData())
375 if (!mpdu->GetHeader().HasData())
380 MpduRecord record{.m_nodeId = nodeId, .m_deviceId = deviceId, .m_enqueueTime = now};
381 if (mpdu->GetHeader().IsQosData())
383 record.
m_tid = mpdu->GetHeader().GetQosTid();
385 NS_LOG_INFO(
"Creating inflight record for packet UID "
386 << mpdu->GetPacket()->GetUid() <<
" node " << nodeId <<
" device " << deviceId
387 <<
" tid " << +record.
m_tid);
396 const auto now =
Now();
399 NS_LOG_DEBUG(
"Ignoring TxStart because helper is stopped");
404 auto& [uid, record] = *pktRecord;
406 if (record.m_txStartTime.IsZero())
408 NS_LOG_INFO(
"TxStart called (first transmission) for inflight packet UID "
410 record.m_txStartTime = now;
414 NS_LOG_INFO(
"TxStart called (retransmission) for inflight packet UID "
416 record.m_retransmissions++;
425 NS_ASSERT_MSG(!mpdu->GetInFlightLinkIds().empty(),
"No LinkId set on MPDU");
426 const auto now =
Now();
429 if (
auto pktRecord =
m_inflightMap.find(mpdu->GetPacket()->GetUid());
434 NS_LOG_DEBUG(
"Ignoring acknowledgement because the time is out of range");
438 const auto linkIds = mpdu->GetInFlightLinkIds();
439 if (
auto pktRecord =
m_inflightMap.find(mpdu->GetPacket()->GetUid());
442 auto& [uid, record] = *pktRecord;
443 record.m_ackTime = now;
444 record.m_successLinkIdSet = linkIds;
445 record.m_mpduSeqNum = mpdu->GetHeader().GetSequenceNumber();
447 NS_LOG_INFO(
"Successful transmission logged of packet UID " << uid);
448 m_successMap[{nodeId, deviceId}].push_back(std::move(record));
449 NS_LOG_INFO(
"Erasing packet UID " << uid <<
" from inflight map due to success");
461 const auto now =
Now();
464 if (
auto pktRecord =
m_inflightMap.find(mpdu->GetPacket()->GetUid());
469 NS_LOG_DEBUG(
"Ignoring drop because the time is out of range");
472 if (
auto pktRecord =
m_inflightMap.find(mpdu->GetPacket()->GetUid());
475 auto& [uid, record] = *pktRecord;
477 record.m_dropTime = now;
478 record.m_dropReason = reason;
479 record.m_mpduSeqNum = mpdu->GetHeader().GetSequenceNumber();
480 NS_LOG_INFO(
"Failed transmission logged of packet UID " << uid);
482 m_failureMap[{nodeId, deviceId}].push_back(std::move(record));
483 NS_LOG_INFO(
"Erasing packet UID " << uid <<
" from inflight map due to failure");
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.
Smart pointer class similar to boost::intrusive_ptr.
static Time Now()
Return the current simulation virtual time.
Simulation virtual time values and global simulation resolution.
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Time m_stopTime
The stop time for recording statistics.
MpduRecordsPerNodeDevice_t m_successMap
The nested map of successful MPDUs.
void Reset()
Clear the data structures for all completed successful and failed MpduRecords.
std::unordered_map< std::tuple< uint32_t, uint32_t >, std::list< MpduRecord >, TupleHash > MpduRecordsPerNodeDevice_t
std::unordered_map of {nodeId, deviceId} tuple to a list of MPDU records
std::unordered_map< std::tuple< uint32_t, uint32_t, uint8_t >, std::list< MpduRecord >, TupleHash > MpduRecordsPerNodeDeviceLink_t
std::unordered_map of {nodeId, deviceId, linkId} tuple to a list of MPDU records
std::map< uint64_t, MpduRecord > m_inflightMap
In-flight MPDUs; key is a Packet UID.
void NotifyAcked(uint32_t nodeId, uint32_t deviceId, Ptr< const WifiMpdu > mpdu)
Callback for the WifiMac::AckedMpdu trace.
CountPerNodeDeviceLink_t GetSuccessesByNodeDeviceLink(WifiTxStatsHelper::MultiLinkSuccessType type=FIRST_LINK_IN_SET) const
Return the counts of successful MPDU transmissions in a hash map.
MultiLinkSuccessType
When Multi-Link Operation (MLO) is used, it is possible for MPDUs to be sent on multiple links concur...
void Stop(Time stopTime)
Set the stop time for statistics collection.
void NotifyTxStart(uint32_t nodeId, uint32_t deviceId, Ptr< const Packet > pkt, Watt_u)
Callback for the WifiPhy::PhyTxBegin trace.
uint64_t GetFailures() const
Return the count of failed MPDU transmissions across all enabled devices.
WifiTxStatsHelper()
Default constructor; start time initialized to zero and stop time to Time::Max().
Time m_startTime
The start time for recording statistics.
void NotifyMacEnqueue(uint32_t nodeId, uint32_t deviceId, Ptr< const WifiMpdu > mpdu)
Callback for the WifiMacQueue::Enqueue trace.
CountPerNodeDevice_t GetFailuresByNodeDevice() const
Return the counts of failed MPDU transmissions in a hash map.
std::unordered_map< std::tuple< uint32_t, uint32_t >, uint64_t, TupleHash > CountPerNodeDevice_t
std::unordered_map of {nodeId, deviceId} tuple to counter value
const MpduRecordsPerNodeDeviceLink_t GetSuccessRecords(WifiTxStatsHelper::MultiLinkSuccessType type=FIRST_LINK_IN_SET) const
Return a hash map of successful MPDU records.
const MpduRecordsPerNodeDevice_t & GetFailureRecords() const
Return a hash map of MPDU records for failed transmissions.
CountPerNodeDevice_t GetSuccessesByNodeDevice() const
Return the counts of successful MPDU transmissions in a hash map.
MpduRecordsPerNodeDevice_t m_failureMap
The nested map of failed MPDUs.
uint64_t GetSuccesses() const
Return the count of successful MPDU transmissions across all enabled devices.
void NotifyMacDropped(uint32_t nodeId, uint32_t deviceId, WifiMacDropReason reason, Ptr< const WifiMpdu > mpdu)
Callback for the WifiMac::DroppedMpdu trace.
void Enable(const NodeContainer &nodes)
Enables trace collection for all nodes and WifiNetDevices in the specified NodeContainer.
CountPerNodeDevice_t GetRetransmissionsByNodeDevice() const
Return the counts of MPDU retransmissions in a hash map.
uint64_t GetRetransmissions() const
Return the count of MPDU retransmissions across all enabled devices.
void Start(Time startTime)
Set the start time for statistics collection.
Time GetDuration() const
Return the duration since the helper was started or reset.
std::unordered_map< std::tuple< uint32_t, uint32_t, uint8_t >, uint64_t, TupleHash > CountPerNodeDeviceLink_t
std::unordered_map of {nodeId, deviceId, linkId} tuple to counter value
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
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...
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#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.
Time Now()
create an ns3::Time instance which contains the current simulation time.
WifiMacDropReason
The reason why an MPDU was dropped.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
double Watt_u
Watt weak type.
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Structure for recording information about an individual data MPDU transmission.
uint8_t m_tid
The TID for the MPDU.