Bug #645: fixes for opening stats file with OMNeT++
This commit is contained in:
@@ -14,3 +14,23 @@ More information on the statistics package and this example is
|
||||
available online on the ns-3 wiki at:
|
||||
|
||||
http://www.nsnam.org/wiki/index.php/Statistical_Framework_for_Network_Simulation
|
||||
|
||||
*** Using ns-3 with the OMNeT++ analysis tool ***
|
||||
|
||||
The stat framework can write out the result in a format that is compatible with the
|
||||
output format of OMNeT++ 4 Discrete Event Simulator Framework.
|
||||
Use the wifi-example-omnet.sh script to generate the results in OMNeT++ format.
|
||||
|
||||
If you want to analyse the results with OMNeT++'s result analyser tool:
|
||||
a) Download OMNeT++ 4 and install it. Start the IDE. (www.omnetpp.org)
|
||||
b) If you do not want to install the whole simulator framework, there is a seperate
|
||||
package which contains only the analysis tool from the OMNeT++ package.
|
||||
You can download it from http://omnetpp.org/download/release/omnetpp-scave.tgz
|
||||
|
||||
Once you are running the OMNeT++ IDE or the separate analysis tool (SCAVE)
|
||||
- Choose File|Import...|Existing Projects into Workspace, then click [Next]
|
||||
- Select root directory. (choose the examples/stats directory) and click [Finish]
|
||||
|
||||
Double click the wifi-example-omnet.anf in the opened project and select
|
||||
the Chart page to see the created chart. Experiment with the analysis tool and read its
|
||||
documentation: http://omnetpp.org/doc/omnetpp40/userguide/ch09.html
|
||||
|
||||
@@ -200,6 +200,7 @@ int main(int argc, char *argv[]) {
|
||||
Ptr<CounterCalculator<uint32_t> > totalTx =
|
||||
CreateObject<CounterCalculator<uint32_t> >();
|
||||
totalTx->SetKey("wifi-tx-frames");
|
||||
totalTx->SetContext("node[0]");
|
||||
Config::Connect("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx",
|
||||
MakeBoundCallback(&TxCallback, totalTx));
|
||||
data.AddDataCalculator(totalTx);
|
||||
@@ -211,6 +212,7 @@ int main(int argc, char *argv[]) {
|
||||
Ptr<PacketCounterCalculator> totalRx =
|
||||
CreateObject<PacketCounterCalculator>();
|
||||
totalRx->SetKey("wifi-rx-frames");
|
||||
totalRx->SetContext("node[1]");
|
||||
Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx",
|
||||
MakeCallback(&PacketCounterCalculator::PacketUpdate,
|
||||
totalRx));
|
||||
@@ -225,6 +227,7 @@ int main(int argc, char *argv[]) {
|
||||
Ptr<PacketCounterCalculator> appTx =
|
||||
CreateObject<PacketCounterCalculator>();
|
||||
appTx->SetKey("sender-tx-packets");
|
||||
appTx->SetContext("node[0]");
|
||||
Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx",
|
||||
MakeCallback(&PacketCounterCalculator::PacketUpdate,
|
||||
appTx));
|
||||
@@ -237,6 +240,7 @@ int main(int argc, char *argv[]) {
|
||||
Ptr<CounterCalculator<> > appRx =
|
||||
CreateObject<CounterCalculator<> >();
|
||||
appRx->SetKey("receiver-rx-packets");
|
||||
appRx->SetContext("node[1]");
|
||||
receiver->SetCounter(appRx);
|
||||
data.AddDataCalculator(appRx);
|
||||
|
||||
@@ -263,6 +267,7 @@ int main(int argc, char *argv[]) {
|
||||
Ptr<PacketSizeMinMaxAvgTotalCalculator> appTxPkts =
|
||||
CreateObject<PacketSizeMinMaxAvgTotalCalculator>();
|
||||
appTxPkts->SetKey("tx-pkt-size");
|
||||
appTxPkts->SetContext("node[0]");
|
||||
Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx",
|
||||
MakeCallback
|
||||
(&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate,
|
||||
@@ -277,6 +282,7 @@ int main(int argc, char *argv[]) {
|
||||
Ptr<TimeMinMaxAvgTotalCalculator> delayStat =
|
||||
CreateObject<TimeMinMaxAvgTotalCalculator>();
|
||||
delayStat->SetKey("delay");
|
||||
delayStat->SetContext(".");
|
||||
receiver->SetDelayTracker(delayStat);
|
||||
data.AddDataCalculator(delayStat);
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace ns3 {
|
||||
//------------------------------------------------------------
|
||||
//--------------------------------------------
|
||||
template <typename T = uint32_t>
|
||||
class MinMaxAvgTotalCalculator : public DataCalculator {
|
||||
class MinMaxAvgTotalCalculator : public DataCalculator,
|
||||
public StatisticalSummary {
|
||||
public:
|
||||
MinMaxAvgTotalCalculator();
|
||||
virtual ~MinMaxAvgTotalCalculator();
|
||||
@@ -38,6 +39,15 @@ namespace ns3 {
|
||||
|
||||
virtual void Output(DataOutputCallback &callback) const;
|
||||
|
||||
long getCount() const { return m_count; }
|
||||
double getSum() const { return m_total; }
|
||||
double getMin() const { return m_min; }
|
||||
double getMax() const { return m_max; }
|
||||
double getMean() const { return m_total / (double)m_count; }
|
||||
double getStddev() const { return NaN; } // unsupported
|
||||
double getVariance() const { return NaN; } // unsupported
|
||||
double getSqrSum() const { return NaN; } // unsupported
|
||||
|
||||
protected:
|
||||
virtual void DoDispose(void);
|
||||
|
||||
@@ -86,23 +96,15 @@ namespace ns3 {
|
||||
}
|
||||
// end MinMaxAvgTotalCalculator::Update
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MinMaxAvgTotalCalculator<T>::Output(DataOutputCallback &callback) const
|
||||
{
|
||||
callback.OutputSingleton(m_key, "count", m_count);
|
||||
if (m_count > 0) {
|
||||
callback.OutputSingleton(m_key, "total", m_total);
|
||||
callback.OutputSingleton(m_key, "average", m_total/m_count);
|
||||
callback.OutputSingleton(m_key, "max", m_max);
|
||||
callback.OutputSingleton(m_key, "min", m_min);
|
||||
}
|
||||
// end MinMaxAvgTotalCalculator::Output
|
||||
callback.OutputStatistic(m_context, m_key, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
//--------------------------------------------
|
||||
template <typename T = uint32_t>
|
||||
@@ -178,7 +180,7 @@ namespace ns3 {
|
||||
void
|
||||
CounterCalculator<T>::Output(DataOutputCallback &callback) const
|
||||
{
|
||||
callback.OutputSingleton(m_key, "count", m_count);
|
||||
callback.OutputSingleton(m_context, m_key, m_count);
|
||||
// end CounterCalculator::Output
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("DataCalculator");
|
||||
|
||||
static double zero = 0;
|
||||
const double ns3::NaN = zero / zero;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
//----------------------------------------------
|
||||
@@ -68,6 +70,20 @@ DataCalculator::GetKey() const
|
||||
// end DataCalculator::GetKey
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
void
|
||||
DataCalculator::SetContext(const std::string context)
|
||||
{
|
||||
m_context = context;
|
||||
// end DataCalculator::SetContext
|
||||
}
|
||||
|
||||
std::string
|
||||
DataCalculator::GetContext() const
|
||||
{
|
||||
return m_context;
|
||||
// end DataCalculator::GetContext
|
||||
}
|
||||
//----------------------------------------------
|
||||
void
|
||||
DataCalculator::Enable()
|
||||
|
||||
@@ -26,9 +26,56 @@
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
namespace ns3 {
|
||||
extern const double NaN;
|
||||
inline bool isNaN(double x) { return x != x; }
|
||||
|
||||
class DataOutputCallback;
|
||||
|
||||
class StatisticalSummary {
|
||||
public:
|
||||
/**
|
||||
* Returns the number of the observations.
|
||||
*/
|
||||
virtual long getCount() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the sum of the values.
|
||||
* @see getWeightedSum()
|
||||
*/
|
||||
virtual double getSum() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the sum of the squared values.
|
||||
* @see getWeightedSqrSum()
|
||||
*/
|
||||
virtual double getSqrSum() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the minimum of the values.
|
||||
*/
|
||||
virtual double getMin() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the maximum of the values.
|
||||
*/
|
||||
virtual double getMax() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the mean of the (weighted) observations.
|
||||
*/
|
||||
virtual double getMean() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the standard deviation of the (weighted) observations.
|
||||
*/
|
||||
virtual double getStddev() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the variance of the (weighted) observations.
|
||||
*/
|
||||
virtual double getVariance() const = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
//--------------------------------------------
|
||||
class DataCalculator : public Object {
|
||||
@@ -43,6 +90,9 @@ namespace ns3 {
|
||||
void SetKey(const std::string key);
|
||||
std::string GetKey() const;
|
||||
|
||||
void SetContext(const std::string context);
|
||||
std::string GetContext() const;
|
||||
|
||||
virtual void Start(const Time& startTime);
|
||||
virtual void Stop(const Time& stopTime);
|
||||
|
||||
@@ -52,6 +102,7 @@ namespace ns3 {
|
||||
bool m_enabled; // Descendant classes *must* check & respect m_enabled!
|
||||
|
||||
std::string m_key;
|
||||
std::string m_context;
|
||||
|
||||
virtual void DoDispose(void);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-calculator.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -52,6 +53,10 @@ namespace ns3 {
|
||||
public:
|
||||
virtual ~DataOutputCallback() {}
|
||||
|
||||
virtual void OutputStatistic(std::string key,
|
||||
std::string variable,
|
||||
const StatisticalSummary *statSum) = 0;
|
||||
|
||||
virtual void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
int val) = 0;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/nstime.h"
|
||||
@@ -54,26 +55,31 @@ OmnetDataOutput::DoDispose()
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
|
||||
inline bool isNumeric(const std::string& s) {
|
||||
char *endp;
|
||||
strtod(s.c_str(), &endp);
|
||||
return endp == s.c_str() + s.size();
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::Output(DataCollector &dc)
|
||||
{
|
||||
|
||||
std::ofstream scalarFile;
|
||||
std::string fn = m_filePrefix + ".sca";
|
||||
scalarFile.open(fn.c_str(), std::ios_base::app);
|
||||
std::string fn = m_filePrefix +"-"+dc.GetRunLabel()+ ".sca";
|
||||
scalarFile.open(fn.c_str(), std::ios_base::out);
|
||||
|
||||
scalarFile << std::endl;
|
||||
// TODO add timestamp to the runlevel
|
||||
scalarFile << "run " << dc.GetRunLabel() << std::endl;
|
||||
scalarFile << std::endl;
|
||||
scalarFile << "attr experiment \"" << dc.GetExperimentLabel()
|
||||
<< "\"" << std::endl;
|
||||
scalarFile << "attr strategy \"" << dc.GetStrategyLabel()
|
||||
<< "\"" << std::endl;
|
||||
scalarFile << "attr input \"" << dc.GetInputLabel()
|
||||
scalarFile << "attr measurement \"" << dc.GetInputLabel()
|
||||
<< "\"" << std::endl;
|
||||
scalarFile << "attr description \"" << dc.GetDescription()
|
||||
<< "\"" << std::endl;
|
||||
scalarFile << std::endl;
|
||||
|
||||
for (MetadataList::iterator i = dc.MetadataBegin();
|
||||
i != dc.MetadataEnd(); i++) {
|
||||
@@ -83,7 +89,18 @@ OmnetDataOutput::Output(DataCollector &dc)
|
||||
}
|
||||
|
||||
scalarFile << std::endl;
|
||||
|
||||
if (isNumeric(dc.GetInputLabel())) {
|
||||
scalarFile << "scalar . measurement \"" << dc.GetInputLabel()
|
||||
<< "\"" << std::endl;
|
||||
}
|
||||
for (MetadataList::iterator i = dc.MetadataBegin();
|
||||
i != dc.MetadataEnd(); i++) {
|
||||
std::pair<std::string, std::string> blob = (*i);
|
||||
if (isNumeric(blob.second)) {
|
||||
scalarFile << "scalar . \"" << blob.first << "\" \"" << blob.second << "\""
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
OmnetOutputCallback callback(&scalarFile);
|
||||
|
||||
for (DataCalculatorList::iterator i = dc.DataCalculatorBegin();
|
||||
@@ -97,6 +114,7 @@ OmnetDataOutput::Output(DataCollector &dc)
|
||||
// end OmnetDataOutput::Output
|
||||
}
|
||||
|
||||
|
||||
OmnetDataOutput::OmnetOutputCallback::OmnetOutputCallback
|
||||
(std::ostream *scalar) :
|
||||
m_scalar(scalar)
|
||||
@@ -104,42 +122,92 @@ OmnetDataOutput::OmnetOutputCallback::OmnetOutputCallback
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputStatistic(std::string context,
|
||||
std::string name,
|
||||
const StatisticalSummary *statSum)
|
||||
{
|
||||
if (context == "")
|
||||
context = ".";
|
||||
if (name == "")
|
||||
name = "\"\"";
|
||||
(*m_scalar) << "statistic " << context << " " << name << std::endl;
|
||||
if (!isNaN(statSum->getCount()))
|
||||
(*m_scalar) << "field count " << statSum->getCount() << std::endl;
|
||||
if (!isNaN(statSum->getSum()))
|
||||
(*m_scalar) << "field sum " << statSum->getSum() << std::endl;
|
||||
if (!isNaN(statSum->getMean()))
|
||||
(*m_scalar) << "field mean " << statSum->getMean() << std::endl;
|
||||
if (!isNaN(statSum->getMin()))
|
||||
(*m_scalar) << "field min " << statSum->getMin() << std::endl;
|
||||
if (!isNaN(statSum->getMax()))
|
||||
(*m_scalar) << "field max " << statSum->getMax() << std::endl;
|
||||
if (!isNaN(statSum->getSqrSum()))
|
||||
(*m_scalar) << "field sqrsum " << statSum->getSqrSum() << std::endl;
|
||||
if (!isNaN(statSum->getStddev()))
|
||||
(*m_scalar) << "field stddev " << statSum->getStddev() << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
int val)
|
||||
{
|
||||
(*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
|
||||
if (context == "")
|
||||
context = ".";
|
||||
if (name == "")
|
||||
name = "\"\"";
|
||||
(*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
|
||||
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
uint32_t val)
|
||||
{
|
||||
(*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
|
||||
if (context == "")
|
||||
context = ".";
|
||||
if (name == "")
|
||||
name = "\"\"";
|
||||
(*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
|
||||
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
double val)
|
||||
{
|
||||
(*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
|
||||
if (context == "")
|
||||
context = ".";
|
||||
if (name == "")
|
||||
name = "\"\"";
|
||||
(*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
|
||||
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
std::string val)
|
||||
{
|
||||
(*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
|
||||
if (context == "")
|
||||
context = ".";
|
||||
if (name == "")
|
||||
name = "\"\"";
|
||||
(*m_scalar) << "scalar " << context << " " << name << " " << val << std::endl;
|
||||
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
|
||||
}
|
||||
|
||||
void
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
OmnetDataOutput::OmnetOutputCallback::OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
Time val)
|
||||
{
|
||||
(*m_scalar) << "scalar " << key << " " << variable << " " << val << std::endl;
|
||||
if (context == "")
|
||||
context = ".";
|
||||
if (name == "")
|
||||
name = "\"\"";
|
||||
(*m_scalar) << "scalar " << context << " " << name << " " << val.GetTimeStep() << std::endl;
|
||||
// end OmnetDataOutput::OmnetOutputCallback::OutputSingleton
|
||||
}
|
||||
|
||||
@@ -45,24 +45,28 @@ namespace ns3 {
|
||||
public:
|
||||
OmnetOutputCallback(std::ostream *scalar);
|
||||
|
||||
void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
void OutputStatistic(std::string context,
|
||||
std::string name,
|
||||
const StatisticalSummary *statSum);
|
||||
|
||||
void OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
int val);
|
||||
|
||||
void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
void OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
uint32_t val);
|
||||
|
||||
void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
void OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
double val);
|
||||
|
||||
void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
void OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
std::string val);
|
||||
|
||||
void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
void OutputSingleton(std::string context,
|
||||
std::string name,
|
||||
Time val);
|
||||
|
||||
private:
|
||||
|
||||
@@ -153,6 +153,25 @@ SqliteDataOutput::SqliteOutputCallback::SqliteOutputCallback
|
||||
// end SqliteDataOutput::SqliteOutputCallback::SqliteOutputCallback
|
||||
}
|
||||
|
||||
void
|
||||
SqliteDataOutput::SqliteOutputCallback::OutputStatistic(std::string key,
|
||||
std::string variable,
|
||||
const StatisticalSummary *statSum)
|
||||
{
|
||||
OutputSingleton(key,variable+"-count", (double)statSum->getCount());
|
||||
if (!isNaN(statSum->getSum()))
|
||||
OutputSingleton(key,variable+"-total", statSum->getSum());
|
||||
if (!isNaN(statSum->getMax()))
|
||||
OutputSingleton(key,variable+"-max", statSum->getMax());
|
||||
if (!isNaN(statSum->getMin()))
|
||||
OutputSingleton(key,variable+"-min", statSum->getMin());
|
||||
if (!isNaN(statSum->getSqrSum()))
|
||||
OutputSingleton(key,variable+"-sqrsum", statSum->getSqrSum());
|
||||
if (!isNaN(statSum->getStddev()))
|
||||
OutputSingleton(key,variable+"-stddev", statSum->getStddev());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SqliteDataOutput::SqliteOutputCallback::OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
|
||||
@@ -48,6 +48,10 @@ namespace ns3 {
|
||||
public:
|
||||
SqliteOutputCallback(Ptr<SqliteDataOutput> owner, std::string run);
|
||||
|
||||
void OutputStatistic(std::string key,
|
||||
std::string variable,
|
||||
const StatisticalSummary *statSum);
|
||||
|
||||
void OutputSingleton(std::string key,
|
||||
std::string variable,
|
||||
int val);
|
||||
|
||||
@@ -70,12 +70,12 @@ TimeMinMaxAvgTotalCalculator::Update(const Time i)
|
||||
void
|
||||
TimeMinMaxAvgTotalCalculator::Output(DataOutputCallback &callback) const
|
||||
{
|
||||
callback.OutputSingleton(m_key, "count", m_count);
|
||||
callback.OutputSingleton(m_context, m_key + "-count", m_count);
|
||||
if (m_count > 0) {
|
||||
callback.OutputSingleton(m_key, "total", m_total);
|
||||
callback.OutputSingleton(m_key, "average", m_total/Scalar(m_count));
|
||||
callback.OutputSingleton(m_key, "max", m_max);
|
||||
callback.OutputSingleton(m_key, "min", m_min);
|
||||
callback.OutputSingleton(m_context, m_key + "-total", m_total);
|
||||
callback.OutputSingleton(m_context, m_key + "-average", m_total/Scalar(m_count));
|
||||
callback.OutputSingleton(m_context, m_key + "-max", m_max);
|
||||
callback.OutputSingleton(m_context, m_key + "-min", m_min);
|
||||
}
|
||||
// end TimeMinMaxAvgTotalCalculator::Output
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user