5#include "flow-monitor-output-stats.h"
8#include "ns3/flow-monitor-module.h"
9#include "ns3/rng-seed-manager.h"
24 m_tableName = tableName;
28 ret = db->SpinExec(
"CREATE TABLE IF NOT EXISTS " + tableName +
30 "FlowId INTEGER NOT NULL, "
31 "TxPackets INTEGER NOT NULL,"
32 "TxBytes INTEGER NOT NULL,"
33 "TxOfferedMbps DOUBLE NOT NULL,"
34 "RxBytes INTEGER NOT NULL,"
35 "ThroughputMbps DOUBLE NOT NULL, "
36 "MeanDelayMs DOUBLE NOT NULL, "
37 "MeanJitterMs DOUBLE NOT NULL, "
38 "RxPackets INTEGER NOT NULL, "
39 "SEED INTEGER NOT NULL,"
40 "RUN INTEGER NOT NULL,"
41 "PRIMARY KEY(FlowId,SEED,RUN)"
45 FlowMonitorOutputStats::DeleteWhere(m_db,
46 RngSeedManager::GetSeed(),
47 RngSeedManager::GetRun(),
53 FlowMonitorHelper& flowmonHelper,
54 const std::string& filename)
57 monitor->CheckForLostPackets();
58 Ptr<Ipv4FlowClassifier> classifier =
59 DynamicCast<Ipv4FlowClassifier>(flowmonHelper.GetClassifier());
60 FlowMonitor::FlowStatsContainer flowStats = monitor->GetFlowStats();
62 double averageFlowThroughput = 0.0;
63 double averageFlowDelay = 0.0;
65 std::ofstream outFile;
66 outFile.open(filename.c_str(), std::ofstream::out | std::ofstream::trunc);
67 if (!outFile.is_open())
69 std::cerr <<
"Can't open file " << filename << std::endl;
73 outFile.setf(std::ios_base::fixed);
75 for (
const auto& flowStat : flowStats)
77 Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(flowStat.first);
78 std::stringstream protoStream;
79 protoStream << (uint16_t)t.protocol;
82 protoStream.str(
"TCP");
86 protoStream.str(
"UDP");
91 m_db->SpinPrepare(&stmt,
"INSERT INTO " + m_tableName +
" VALUES (?,?,?,?,?,?,?,?,?,?,?);");
94 double rxDuration = flowStat.second.timeLastTxPacket.GetSeconds() -
95 flowStat.second.timeFirstTxPacket.GetSeconds();
96 double txOffered = flowStat.second.txBytes * 8.0 / rxDuration / 1000.0 / 1000.0;
98 outFile <<
"Flow " << flowStat.first <<
" (" << t.sourceAddress <<
":" << t.sourcePort
99 <<
" -> " << t.destinationAddress <<
":" << t.destinationPort <<
") proto "
100 << protoStream.str() <<
"\n";
101 outFile <<
" Tx Packets: " << flowStat.second.txPackets <<
"\n";
102 outFile <<
" Tx Bytes: " << flowStat.second.txBytes <<
"\n";
103 outFile <<
" TxOffered: " << txOffered <<
" Mbps\n";
104 outFile <<
" Rx Bytes: " << flowStat.second.rxBytes <<
"\n";
106 ret = m_db->Bind(stmt, 1, flowStat.first);
107 NS_ABORT_UNLESS(ret);
108 ret = m_db->Bind(stmt, 2, flowStat.second.txPackets);
109 NS_ABORT_UNLESS(ret);
110 ret = m_db->Bind(stmt, 3,
static_cast<uint32_t
>(flowStat.second.txBytes));
111 NS_ABORT_UNLESS(ret);
112 ret = m_db->Bind(stmt, 4, txOffered);
113 NS_ABORT_UNLESS(ret);
114 ret = m_db->Bind(stmt, 5,
static_cast<uint32_t
>(flowStat.second.rxBytes));
115 NS_ABORT_UNLESS(ret);
117 if (flowStat.second.rxPackets > 0)
119 double th = flowStat.second.rxBytes * 8.0 / rxDuration / 1000 / 1000;
120 double delay = 1000 * flowStat.second.delaySum.GetSeconds() / flowStat.second.rxPackets;
122 1000 * flowStat.second.jitterSum.GetSeconds() / flowStat.second.rxPackets;
124 averageFlowThroughput += th;
125 averageFlowDelay += delay;
127 ret = m_db->Bind(stmt, 6, th);
128 NS_ABORT_UNLESS(ret);
129 ret = m_db->Bind(stmt, 7, delay);
130 NS_ABORT_UNLESS(ret);
131 ret = m_db->Bind(stmt, 8, jitter);
132 NS_ABORT_UNLESS(ret);
134 outFile <<
" Throughput: " << th <<
" Mbps\n";
135 outFile <<
" Mean delay: " << delay <<
" ms\n";
136 outFile <<
" Mean jitter: " << jitter <<
" ms\n";
140 outFile <<
" Throughput: 0 Mbps\n";
141 outFile <<
" Mean delay: 0 ms (NOT VALID)\n";
142 outFile <<
" Mean jitter: 0 ms (NOT VALID)\n";
143 ret = m_db->Bind(stmt, 6, 0.0);
144 NS_ABORT_UNLESS(ret);
145 ret = m_db->Bind(stmt, 7, 0.0);
146 NS_ABORT_UNLESS(ret);
147 ret = m_db->Bind(stmt, 8, 0.0);
148 NS_ABORT_UNLESS(ret);
150 outFile <<
" Rx Packets: " << flowStat.second.rxPackets <<
"\n";
151 ret = m_db->Bind(stmt, 9, flowStat.second.rxPackets);
152 NS_ABORT_UNLESS(ret);
153 ret = m_db->Bind(stmt, 10, RngSeedManager::GetSeed());
154 NS_ABORT_UNLESS(ret);
155 ret = m_db->Bind(stmt, 11,
static_cast<uint32_t
>(RngSeedManager::GetRun()));
156 NS_ABORT_UNLESS(ret);
157 ret = m_db->SpinExec(stmt);
158 NS_ABORT_UNLESS(ret);
161 outFile <<
"\n\n Mean flow throughput: " << averageFlowThroughput / flowStats.size() <<
"\n";
162 outFile <<
" Mean flow delay: " << averageFlowDelay / flowStats.size() <<
"\n";
168FlowMonitorOutputStats::DeleteWhere(SQLiteOutput* p,
171 const std::string& table)
175 ret = p->SpinPrepare(&stmt,
"DELETE FROM \"" + table +
"\" WHERE SEED = ? AND RUN = ?;");
176 NS_ABORT_IF(ret ==
false);
177 ret = p->Bind(stmt, 1, seed);
178 NS_ABORT_IF(ret ==
false);
179 ret = p->Bind(stmt, 2, run);
181 ret = p->SpinExec(stmt);
182 NS_ABORT_IF(ret ==
false);
void Save(const Ptr< FlowMonitor > &monitor, FlowMonitorHelper &flowmonHelper, const std::string &filename)
Store the flow monitor output in the database.
void SetDb(SQLiteOutput *db, const std::string &tableName)
Install the output database.
FlowMonitorOutputStats()
FlowMonitorOutputStats constructor.