5G-LENA nr-v4.0
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
lena-lte-comparison/flow-monitor-output-stats.cc
1// Copyright (c) 2020 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4
5#include "flow-monitor-output-stats.h"
6
7#include "ns3/abort.h"
8#include "ns3/flow-monitor-module.h"
9#include "ns3/rng-seed-manager.h"
10
11#include <fstream>
12
13namespace ns3
14{
15
17{
18}
19
20void
21FlowMonitorOutputStats::SetDb(SQLiteOutput* db, const std::string& tableName)
22{
23 m_db = db;
24 m_tableName = tableName;
25
26 bool ret;
27
28 ret = db->SpinExec("CREATE TABLE IF NOT EXISTS " + tableName +
29 " ("
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)"
42 ");");
43 NS_ABORT_UNLESS(ret);
44
45 FlowMonitorOutputStats::DeleteWhere(m_db,
46 RngSeedManager::GetSeed(),
47 RngSeedManager::GetRun(),
48 tableName);
49}
50
51void
52FlowMonitorOutputStats::Save(const Ptr<FlowMonitor>& monitor,
53 FlowMonitorHelper& flowmonHelper,
54 const std::string& filename)
55{
56 bool ret;
57 monitor->CheckForLostPackets();
58 Ptr<Ipv4FlowClassifier> classifier =
59 DynamicCast<Ipv4FlowClassifier>(flowmonHelper.GetClassifier());
60 FlowMonitor::FlowStatsContainer flowStats = monitor->GetFlowStats();
61
62 double averageFlowThroughput = 0.0;
63 double averageFlowDelay = 0.0;
64
65 std::ofstream outFile;
66 outFile.open(filename.c_str(), std::ofstream::out | std::ofstream::trunc);
67 if (!outFile.is_open())
68 {
69 std::cerr << "Can't open file " << filename << std::endl;
70 return;
71 }
72
73 outFile.setf(std::ios_base::fixed);
74
75 for (const auto& flowStat : flowStats)
76 {
77 Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(flowStat.first);
78 std::stringstream protoStream;
79 protoStream << (uint16_t)t.protocol;
80 if (t.protocol == 6)
81 {
82 protoStream.str("TCP");
83 }
84 if (t.protocol == 17)
85 {
86 protoStream.str("UDP");
87 }
88
89 sqlite3_stmt* stmt;
90
91 m_db->SpinPrepare(&stmt, "INSERT INTO " + m_tableName + " VALUES (?,?,?,?,?,?,?,?,?,?,?);");
92
93 // Measure the duration of the flow from sender's perspective
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;
97
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";
105
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);
116
117 if (flowStat.second.rxPackets > 0)
118 {
119 double th = flowStat.second.rxBytes * 8.0 / rxDuration / 1000 / 1000;
120 double delay = 1000 * flowStat.second.delaySum.GetSeconds() / flowStat.second.rxPackets;
121 double jitter =
122 1000 * flowStat.second.jitterSum.GetSeconds() / flowStat.second.rxPackets;
123
124 averageFlowThroughput += th;
125 averageFlowDelay += delay;
126
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);
133
134 outFile << " Throughput: " << th << " Mbps\n";
135 outFile << " Mean delay: " << delay << " ms\n";
136 outFile << " Mean jitter: " << jitter << " ms\n";
137 }
138 else
139 {
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);
149 }
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);
159 }
160
161 outFile << "\n\n Mean flow throughput: " << averageFlowThroughput / flowStats.size() << "\n";
162 outFile << " Mean flow delay: " << averageFlowDelay / flowStats.size() << "\n";
163
164 outFile.close();
165}
166
167void
168FlowMonitorOutputStats::DeleteWhere(SQLiteOutput* p,
169 uint32_t seed,
170 uint32_t run,
171 const std::string& table)
172{
173 bool ret;
174 sqlite3_stmt* stmt;
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);
180
181 ret = p->SpinExec(stmt);
182 NS_ABORT_IF(ret == false);
183}
184
185} // namespace ns3
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.