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"
33 : m_startTime(startTime),
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())
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::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.
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
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.
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
Time GetDuration() const
Return the duration since the helper was started or reset.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#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.
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...
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
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.
uint32_t m_nodeId
The sending node ID.