From 68ee14873d4868c68b8258c12ac788b6d3d5ab0b Mon Sep 17 00:00:00 2001 From: Matteo Drago Date: Wed, 25 Jan 2023 11:28:59 +0100 Subject: [PATCH] Include stats calculator to ease performance evaluation * Add stats calculator + example * Update CMakeLists.txt --- CMakeLists.txt | 2 + examples/CMakeLists.txt | 9 + examples/stats-calculator-example.cc | 161 ++++++++++ helper/bursty-app-stats-calculator.cc | 403 ++++++++++++++++++++++++++ helper/bursty-app-stats-calculator.h | 221 ++++++++++++++ 5 files changed, 796 insertions(+) create mode 100644 examples/stats-calculator-example.cc create mode 100644 helper/bursty-app-stats-calculator.cc create mode 100644 helper/bursty-app-stats-calculator.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f69ae17a5..7f541b17b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ build_lib( model/vr-burst-generator.cc helper/bursty-helper.cc helper/burst-sink-helper.cc + helper/bursty-app-stats-calculator.cc HEADER_FILES model/burst-generator.h model/burst-sink.h model/bursty-application.h @@ -20,6 +21,7 @@ build_lib( model/vr-burst-generator.h helper/bursty-helper.h helper/burst-sink-helper.h + helper/bursty-app-stats-calculator.h LIBRARIES_TO_LINK ${libcore} ${libapplications} ${libpoint-to-point} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 79719157b..bd9159714 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -42,4 +42,13 @@ build_lib_example( ${libapplications} ${libcore} ${libwifi} +) + +build_lib_example( + NAME stats-calculator-example + SOURCE_FILES stats-calculator-example.cc + LIBRARIES_TO_LINK ${libvr-app} + ${libapplications} + ${libcore} + ${libwifi} ) \ No newline at end of file diff --git a/examples/stats-calculator-example.cc b/examples/stats-calculator-example.cc new file mode 100644 index 000000000..69aaf1e26 --- /dev/null +++ b/examples/stats-calculator-example.cc @@ -0,0 +1,161 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2021 SIGNET Lab, Department of Information Engineering, + * University of Padova + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" + +#include "ns3/seq-ts-size-frag-header.h" +#include "ns3/bursty-helper.h" +#include "ns3/burst-sink-helper.h" +#include "ns3/bursty-app-stats-calculator.h" + +/** + * An example on how to use the BurstyAppStatsCalculator. + * Example based on bursty-application-example. + */ + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("BurstyApplicationExample"); + +std::string +AddressToString (const Address &addr) +{ + std::stringstream addressStr; + addressStr << InetSocketAddress::ConvertFrom (addr).GetIpv4 () << ":" + << InetSocketAddress::ConvertFrom (addr).GetPort (); + return addressStr.str (); +} + +void +BurstTx(uint32_t nodeId, + Ptr statsCalculator, + Ptr burst, + const Address& from, + const Address& to, + const SeqTsSizeFragHeader& header) +{ + NS_LOG_INFO ("Sent burst seq=" << header.GetSeq () << " of header.GetSize ()=" + << header.GetSize () << " (burst->GetSize ()=" << burst->GetSize () + << ") bytes from " << AddressToString (from) << " to " + << AddressToString (to) << " at " << header.GetTs ().As (Time::S)); + statsCalculator->TxBurst(nodeId, burst, from, to, header); +} + +void +BurstRx(uint32_t nodeId, + Ptr statsCalculator, + Ptr burst, + const Address& from, + const Address& to, + const SeqTsSizeFragHeader& header) +{ + NS_LOG_INFO ("Received burst seq=" + << header.GetSeq () << " of header.GetSize ()=" << header.GetSize () + << " (burst->GetSize ()=" << burst->GetSize () << ") bytes from " + << AddressToString (from) << " to " << AddressToString (to) << " at " + << header.GetTs ().As (Time::S)); + + statsCalculator->RxBurst(nodeId, burst, from, to, header); +} + +int +main (int argc, char *argv[]) +{ + double simTimeSec = 10; + CommandLine cmd (__FILE__); + cmd.AddValue ("SimulationTime", "Length of simulation in seconds.", simTimeSec); + cmd.Parse (argc, argv); + + Time::SetResolution (Time::NS); + LogComponentEnableAll (LOG_PREFIX_TIME); + LogComponentEnable ("BurstyApplicationExample", LOG_INFO); + + Config::SetDefault("ns3::BurstyAppStatsCalculator::EpochDuration", TimeValue(Seconds(0.1))); + Config::SetDefault("ns3::BurstyAppStatsCalculator::WriteToFile", BooleanValue(true)); + + // Setup two nodes + NodeContainer nodes; + nodes.Create (2); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + + InternetStackHelper stack; + stack.Install (nodes); + + uint16_t portNumber = 50000; + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + Ipv4Address serverAddress = interfaces.GetAddress (0); + Ipv4Address sinkAddress = Ipv4Address::GetAny (); // 0.0.0.0 + + // Create bursty application helper + BurstyHelper burstyHelper ("ns3::UdpSocketFactory", InetSocketAddress (serverAddress, portNumber)); + burstyHelper.SetAttribute ("FragmentSize", UintegerValue (1200)); + burstyHelper.SetBurstGenerator ("ns3::SimpleBurstGenerator", + "PeriodRv", StringValue ("ns3::ConstantRandomVariable[Constant=100e-3]"), + "BurstSizeRv", StringValue ("ns3::ConstantRandomVariable[Constant=10e3]")); + + // Install bursty application + ApplicationContainer serverApps = burstyHelper.Install (nodes.Get (1)); + Ptr burstyApp = serverApps.Get (0)->GetObject (); + Ptr statsCalculator = CreateObject(); + + // Example of connecting to the trace sources + burstyApp->TraceConnectWithoutContext ("BurstTx", MakeBoundCallback (&BurstTx, nodes.Get (1)->GetId (), statsCalculator)); + + // Create burst sink helper + BurstSinkHelper burstSinkHelper ("ns3::UdpSocketFactory", + InetSocketAddress (sinkAddress, portNumber)); + + // Install burst sink + ApplicationContainer clientApps = burstSinkHelper.Install (nodes.Get (0)); + Ptr burstSink = clientApps.Get (0)->GetObject (); + + // Example of connecting to the trace sources + burstSink->TraceConnectWithoutContext("BurstRx", MakeBoundCallback(&BurstRx, nodes.Get (0)->GetId (), statsCalculator)); + + // Stop bursty app after simTimeSec + serverApps.Stop (Seconds (simTimeSec)); + Simulator::Stop (Seconds(simTimeSec)); + Simulator::Run (); + Simulator::Destroy (); + + // Stats + std::cout << "Total RX bursts: " << burstyApp->GetTotalTxBursts () << "/" + << burstSink->GetTotalRxBursts () << std::endl; + std::cout << "Total RX fragments: " << burstyApp->GetTotalTxFragments () << "/" + << burstSink->GetTotalRxFragments () << std::endl; + std::cout << "Total RX bytes: " << burstyApp->GetTotalTxBytes () << "/" + << burstSink->GetTotalRxBytes () << std::endl; + + return 0; +} diff --git a/helper/bursty-app-stats-calculator.cc b/helper/bursty-app-stats-calculator.cc new file mode 100644 index 000000000..f31074ebb --- /dev/null +++ b/helper/bursty-app-stats-calculator.cc @@ -0,0 +1,403 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation; +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include +#include "bursty-app-stats-calculator.h" +#include "ns3/string.h" +#include "ns3/nstime.h" +#include +#include +#include +#include + +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/seq-ts-size-frag-header.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("BurstyAppStatsCalculator"); + +NS_OBJECT_ENSURE_REGISTERED (BurstyAppStatsCalculator); + +BurstyAppStatsCalculator::BurstyAppStatsCalculator () + : m_firstWrite (true), + m_pendingOutput (false), + m_aggregatedStats (true) +{ + NS_LOG_FUNCTION (this); +} + +BurstyAppStatsCalculator::~BurstyAppStatsCalculator () +{ + NS_LOG_FUNCTION (this); +} + +TypeId +BurstyAppStatsCalculator::GetTypeId (void) +{ + static TypeId tid = + TypeId ("ns3::BurstyAppStatsCalculator") + .SetParent () + .SetGroupName ("Applications") + .AddConstructor () + .AddAttribute ("StartTime", "Start time of the on going epoch.", TimeValue (Seconds (0.)), + MakeTimeAccessor (&BurstyAppStatsCalculator::SetStartTime, + &BurstyAppStatsCalculator::GetStartTime), + MakeTimeChecker ()) + .AddAttribute ("EpochDuration", "Epoch duration.", TimeValue (Seconds (0.25)), + MakeTimeAccessor (&BurstyAppStatsCalculator::GetEpoch, + &BurstyAppStatsCalculator::SetEpoch), + MakeTimeChecker ()) + .AddAttribute ("OutputFilename", + "Name of the file where the downlink results will be saved.", + StringValue ("AppStats.txt"), + MakeStringAccessor (&BurstyAppStatsCalculator::SetOutputFilename, + &BurstyAppStatsCalculator::GetOutputFilename), + MakeStringChecker ()) + .AddAttribute ("AggregatedStats", + "Choice to show the results aggregated of disaggregated. As of now, " + "non-aggregated stats are not supported", + BooleanValue (true), + MakeBooleanAccessor (&BurstyAppStatsCalculator::m_aggregatedStats), + MakeBooleanChecker ()) + .AddAttribute ("ManualUpdate", + "Choice to perform manual statistics update, e.g., triggered by an " + "external class.", + BooleanValue (false), + MakeBooleanAccessor (&BurstyAppStatsCalculator::GetManualUpdate, + &BurstyAppStatsCalculator::SetManualUpdate), + MakeBooleanChecker ()) + .AddAttribute ("WriteToFile", + "Choice to write stats to file besides computing and exchange them " + "with external classes", + BooleanValue (false), + MakeBooleanAccessor (&BurstyAppStatsCalculator::m_writeToFile), + MakeBooleanChecker ()); + return tid; +} + +void +BurstyAppStatsCalculator::DoDispose () +{ + NS_LOG_FUNCTION (this); +} + +void +BurstyAppStatsCalculator::SetStartTime (Time t) +{ + m_startTime = t; + if (m_aggregatedStats) + { + RescheduleEndEpoch (); + } +} + +Time +BurstyAppStatsCalculator::GetStartTime () const +{ + return m_startTime; +} + +void +BurstyAppStatsCalculator::SetEpoch (Time e) +{ + m_epochDuration = e; + if (m_aggregatedStats) + { + RescheduleEndEpoch (); + } +} + +Time +BurstyAppStatsCalculator::GetEpoch () const +{ + return m_epochDuration; +} + +void +BurstyAppStatsCalculator::SetManualUpdate (bool u) +{ + NS_LOG_FUNCTION (this); + m_manualUpdate = u; + if (m_manualUpdate) + { + NS_LOG_UNCOND ("Cancel EndEpoch event"); + m_endEpochEvent.Cancel (); + } +} + +bool +BurstyAppStatsCalculator::GetManualUpdate () const +{ + NS_LOG_FUNCTION (this); + return m_manualUpdate; +} + +void +BurstyAppStatsCalculator::TxBurst (uint32_t nodeId, Ptr burst, const Address &from, const Address &to, const SeqTsSizeFragHeader &header) +{ + NS_LOG_FUNCTION(this << " TxBurst nodeId=" << nodeId << " burst seq=" << header.GetSeq () << " of " << header.GetSize () + << " bytes transmitted at " << std::setprecision (9) + << header.GetTs ().As (Time::S)); + + if (m_aggregatedStats) + { + if (Simulator::Now () >= m_startTime) + { + m_txBursts[nodeId]++; + m_txData[nodeId] += header.GetSize (); + } + m_pendingOutput = true; + } +} + +void +BurstyAppStatsCalculator::RxBurst (uint32_t nodeId, Ptr burst, const Address &from, const Address &to, const SeqTsSizeFragHeader &header) +{ + NS_LOG_FUNCTION (this << " RxBurst nodeId=" << nodeId << " burst seq=" << header.GetSeq () << " of " << header.GetSize () + << " bytes transmitted at " << std::setprecision (9) + << header.GetTs ().As (Time::S)); + if (m_aggregatedStats) + { + if (Simulator::Now () >= m_startTime) + { + m_rxBursts[nodeId]++; + m_rxData[nodeId] += header.GetSize (); + + auto it = m_delay.find (nodeId); + if (it == m_delay.end ()) + { + NS_LOG_DEBUG (this << " Creating delay stats calculator for node " << nodeId); + m_delay[nodeId] = CreateObject> (); + } + + uint64_t delay = Simulator::Now().GetNanoSeconds() - header.GetTs ().GetNanoSeconds(); + m_delay[nodeId]->Update (delay); + } + m_pendingOutput = true; + } +} + +std::map +BurstyAppStatsCalculator::ReadResults (void) +{ + NS_LOG_FUNCTION (this); + + // Get the list of node IDs + std::vector nodeIdsVector; + for (auto it = m_txBursts.begin (); it != m_txBursts.end (); ++it) + { + if (find (nodeIdsVector.begin (), nodeIdsVector.end (), (*it).first) == nodeIdsVector.end ()) + { + nodeIdsVector.push_back ((*it).first); + } + } + + std::map results; + for (auto it = nodeIdsVector.begin (); it != nodeIdsVector.end (); + ++it) + { + AppResults item; + uint32_t nodeId = *it; + item.imsi = nodeId; + + item.txBursts = m_txBursts[nodeId]; + item.txData = m_txData[nodeId]; + + item.rxBursts = m_rxBursts[nodeId]; + item.rxData = m_rxData[nodeId]; + + auto iter = m_delay.find (nodeId); + + // if no delay info have been recorded yet, put it to zero + if (iter == m_delay.end ()) + { + item.delayMean = 0.0; + item.delayStdev = 0.0; + item.delayMin = 0.0; + item.delayMax = 0.0; + } + else + { + item.delayMean = m_delay[nodeId]->getMean (); + item.delayStdev = m_delay[nodeId]->getStddev (); + item.delayMin = m_delay[nodeId]->getMin (); + item.delayMax = m_delay[nodeId]->getMax (); + } + results.insert (std::make_pair (item.imsi, item)); + } + if (m_writeToFile) + { + ShowResults (); + } + ResetResults (); + return results; +} + +void +BurstyAppStatsCalculator::ShowResults (void) +{ + std::ofstream outFile; + + if (m_firstWrite == true) + { + outFile.open (GetOutputFilename ().c_str ()); + if (!outFile.is_open ()) + { + NS_LOG_ERROR ("Can't open file " << GetOutputFilename ().c_str ()); + return; + } + + m_firstWrite = false; + outFile << "start\tend\tNodeId\tnTxBursts\tTxBytes\tnRxBursts\tRxBytes\tdelay\tstdDev\tmin\tmax\t"; + outFile << std::endl; + } + else + { + outFile.open (GetOutputFilename ().c_str (), std::ios_base::app); + if (!outFile.is_open ()) + { + NS_LOG_ERROR ("Can't open file " << GetOutputFilename ().c_str ()); + return; + } + } + + WriteResults (outFile); + m_pendingOutput = false; +} + +void +BurstyAppStatsCalculator::WriteResults (std::ofstream &outFile) +{ + NS_LOG_FUNCTION (this); + + // Get the list of node IDs + + std::vector nodeIdsVector; + for (auto it = m_txBursts.begin (); it != m_txBursts.end (); ++it) + { + if (find (nodeIdsVector.begin (), nodeIdsVector.end (), (*it).first) == nodeIdsVector.end ()) + { + nodeIdsVector.push_back ((*it).first); + } + } + + // Check if there is some ID missing + for (auto it = m_rxBursts.begin (); it != m_rxBursts.end (); ++it) + { + if (find (nodeIdsVector.begin (), nodeIdsVector.end (), (*it).first) == nodeIdsVector.end ()) + { + nodeIdsVector.push_back ((*it).first); + } + } + + Time endTime; + if (m_manualUpdate) + { + endTime = Simulator::Now (); + } + else + { + endTime = m_startTime + m_epochDuration; + } + + for (auto it = nodeIdsVector.begin (); it != nodeIdsVector.end (); + ++it) + { + uint32_t nodeId = *it; + outFile << m_startTime.GetNanoSeconds () / 1.0e9 << "\t"; + outFile << endTime.GetNanoSeconds () / 1.0e9 << "\t"; + + outFile << nodeId << "\t"; + + outFile << m_txBursts[nodeId] << "\t"; + outFile << m_txData[nodeId] << "\t"; + + outFile << m_rxBursts[nodeId] << "\t"; + outFile << m_rxData[nodeId] << "\t"; + + auto iter = m_delay.find (nodeId); + + // if no delay info have been recorded yet, put it to zero + if (iter == m_delay.end ()) + { + outFile << 0.0 << "\t"; + outFile << 0.0 << "\t"; + outFile << 0.0 << "\t"; + outFile << 0.0 << "\t"; + } + else + { + outFile << m_delay[nodeId]->getMean () << "\t"; + outFile << m_delay[nodeId]->getStddev () << "\t"; + outFile << m_delay[nodeId]->getMin () << "\t"; + outFile << m_delay[nodeId]->getMax () << "\t"; + } + + + outFile << std::endl; + } + + outFile.close (); +} + +void +BurstyAppStatsCalculator::ResetResults (void) +{ + NS_LOG_FUNCTION (this); + + m_rxBursts.erase (m_rxBursts.begin (), m_rxBursts.end ()); + m_txBursts.erase (m_txBursts.begin (), m_txBursts.end ()); + + m_txData.erase (m_txData.begin (), m_txData.end ()); + m_rxData.erase (m_rxData.begin (), m_rxData.end ()); + + m_delay.erase (m_delay.begin (), m_delay.end ()); +} + +void +BurstyAppStatsCalculator::RescheduleEndEpoch (void) +{ + NS_LOG_FUNCTION (this); + m_endEpochEvent.Cancel (); + NS_ASSERT (Simulator::Now ().GetMilliSeconds () == 0); // below event time assumes this + m_endEpochEvent = Simulator::Schedule (m_startTime + m_epochDuration, &BurstyAppStatsCalculator::EndEpoch, this); +} + +void +BurstyAppStatsCalculator::EndEpoch (void) +{ + NS_LOG_FUNCTION (this); + ShowResults (); + ResetResults (); + m_startTime += m_epochDuration; + m_endEpochEvent = Simulator::Schedule (m_epochDuration, &BurstyAppStatsCalculator::EndEpoch, this); +} + +void +BurstyAppStatsCalculator::SetOutputFilename (std::string filename) +{ + m_outputFilename = filename; +} + +std::string +BurstyAppStatsCalculator::GetOutputFilename (void) const +{ + return m_outputFilename; +} diff --git a/helper/bursty-app-stats-calculator.h b/helper/bursty-app-stats-calculator.h new file mode 100644 index 000000000..f52e23a4c --- /dev/null +++ b/helper/bursty-app-stats-calculator.h @@ -0,0 +1,221 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef BURSTY_APP_STATS_CALCULATOR_H_ +#define BURSTY_APP_STATS_CALCULATOR_H_ + +#include "ns3/basic-data-calculators.h" +#include "ns3/internet-module.h" +#include "ns3/lte-common.h" +#include "ns3/network-module.h" +#include "ns3/object.h" +#include "ns3/seq-ts-size-frag-header.h" +#include "ns3/uinteger.h" + +#include +#include +#include + +namespace ns3 +{ + +struct AppResults +{ + uint16_t imsi; + uint16_t txBursts; + uint32_t txData; + uint16_t rxBursts; + uint32_t rxData; + double delayMean; + double delayStdev; + double delayMin; + double delayMax; +}; + +/** + * \ingroup application + * + */ +class BurstyAppStatsCalculator : public Object +{ + public: + /** + * Class constructor + */ + BurstyAppStatsCalculator(); + + /** + * Class constructor + */ + BurstyAppStatsCalculator(std::string protocolType); + + /** + * Class destructor + */ + virtual ~BurstyAppStatsCalculator(); + + // Inherited from ns3::Object + /** + * Register this type. + * \return The object TypeId. + */ + static TypeId GetTypeId(void); + void DoDispose(); + + /** + * + * \param e the epoch duration + */ + void SetEpoch(Time e); + + /** + * + * \return the epoch duration + */ + Time GetEpoch() const; + + /** + * + * \param t the value of the StartTime attribute + */ + void SetStartTime(Time t); + + /** + * + * \return the value of the StartTime attribute + */ + Time GetStartTime() const; + + /** + * Reschedules EndEpoch event. Usually used after + * execution of SetStartTime() or SetEpoch() + */ + void RescheduleEndEpoch(); + + /** + * + * \param u set the update mode (true if manual, automatic otherwise) + */ + void SetManualUpdate(bool u); + + /** + * + * \return whether the update is manual or not + */ + bool GetManualUpdate() const; + + /** + * Notifies the stats calculator that a burst of packets has been transmitted. + * \param nodeId ID of the node sending the burst + * \param burst packet representing the complete burst + * \param from address of the transmitting terminal + * \param to address of the receiving terminal + * \param header burst header containing trasmission information + */ + void TxBurst(uint32_t nodeId, + Ptr burst, + const Address& from, + const Address& to, + const SeqTsSizeFragHeader& header); + + /** + * Notifies the stats calculator that a burst of packets has been transmitted. + * \param nodeId ID of the node receiving the burst + * \param burst packet representing the complete burst + * \param from address of the transmitting terminal + * \param to address of the receiving terminal + * \param header burst header containing trasmission information + */ + void RxBurst(uint32_t nodeId, + Ptr burst, + const Address& from, + const Address& to, + const SeqTsSizeFragHeader& header); + + /** + * + */ + std::map ReadResults(void); + + /** + * Called after each epoch to write collected + * statistics to output files. During first call + * it opens output files and write columns descriptions. + * During next calls it opens output files in append mode. + */ + void ShowResults(void); + + /** + * Writes collected statistics to output file and closes it. + * @param outFile ofstream for statistics + */ + void WriteResults(std::ofstream& outFile); + + /** + * Erases collected statistics + */ + void ResetResults(); + + /** + * + * \param filename name of the output file + */ + void SetOutputFilename(std::string filename); + + /** + * + * \return name of the output file + */ + std::string GetOutputFilename() const; + + private: + /** + * Function called in every endEpochEvent. It calls + * ShowResults() to write statistics to output files + * and ResetResults() to clear collected statistics. + */ + void EndEpoch(void); + + EventId m_endEpochEvent; //!< Event id for next end epoch event + Time m_startTime; //!< Start time of the on going epoch + Time m_epochDuration; //!< Epoch duration + + bool m_firstWrite; //! true if output files have not been opened yet + bool m_pendingOutput; //!< true if any output is pending + bool m_aggregatedStats; //!< true if results are shown aggregated + bool m_manualUpdate; //!< true if update is triggered by external entity (such as RAN-AI) + bool m_writeToFile; //!< determine if the traces must be output to file or just evaluated and + //!< exchanged with external classes + + std::map + m_txBursts; //!< number of bursts sent in a specific epoch per node ID + std::map m_txData; //!< number of bytes sent in a specific epoch per node ID + + std::map + m_rxBursts; //!< number of bursts received in a specific epoch per node ID + std::map + m_rxData; //!< number of bytes received in a specific epoch per node ID + + std::map>> + m_delay; //!< delay statistics calculator for a specific epoch, per node ID + + std::string m_outputFilename; //!< name of the output file +}; + +} // namespace ns3 + +#endif /* BURSTY_APP_STATS_CALCULATOR_H_ */