diff -r 5d448b8564e5 examples/stats/.project --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/stats/.project Wed Jul 01 16:12:09 2009 +0200 @@ -0,0 +1,11 @@ + + + stats + + + + + + + + diff -r 5d448b8564e5 examples/stats/README --- a/examples/stats/README Mon Jun 29 13:24:10 2009 +0200 +++ b/examples/stats/README Wed Jul 01 16:12:09 2009 +0200 @@ -14,3 +14,23 @@ 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 diff -r 5d448b8564e5 examples/stats/wifi-example-db.sh --- a/examples/stats/wifi-example-db.sh Mon Jun 29 13:24:10 2009 +0200 +++ b/examples/stats/wifi-example-db.sh Wed Jul 01 16:12:09 2009 +0200 @@ -64,8 +64,8 @@ from Singletons rx, Singletons tx, Experiments exp \ where rx.run = tx.run AND \ rx.run = exp.run AND \ - rx.name='receiver-rx-packets' AND \ - tx.name='sender-tx-packets' \ + rx.variable='receiver-rx-packets' AND \ + tx.variable='sender-tx-packets' \ group by exp.input \ order by abs(exp.input) ASC;" diff -r 5d448b8564e5 examples/stats/wifi-example-omnet.anf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/stats/wifi-example-omnet.anf Wed Jul 01 16:12:09 2009 +0200 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff -r 5d448b8564e5 examples/stats/wifi-example-omnet.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/stats/wifi-example-omnet.sh Wed Jul 01 16:12:09 2009 +0200 @@ -0,0 +1,22 @@ +#!/bin/sh + +DISTANCES="25 50 75 100 125 145 147 150 152 155 157 160 162 165 167 170 172 175 177 180" +TRIALS="1 2 3 4 5" + +echo WiFi Experiment Example - OMNeT++ output + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:bin/ + +for trial in $TRIALS +do + for distance in $DISTANCES + do + echo Trial $trial, distance $distance + ../../waf --run "wifi-example-sim --format=omnet --distance=$distance --run=run-$distance-$trial" + done +done + +rm *.sca +mv ../../*.sca . + +echo "Done; data in data-run-*.sca files. Open SCAVE, create a new workspace and import this directory." diff -r 5d448b8564e5 examples/stats/wifi-example-sim.cc --- a/examples/stats/wifi-example-sim.cc Mon Jun 29 13:24:10 2009 +0200 +++ b/examples/stats/wifi-example-sim.cc Wed Jul 01 16:12:09 2009 +0200 @@ -200,6 +200,7 @@ Ptr > totalTx = CreateObject >(); 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 @@ Ptr totalRx = CreateObject(); 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 @@ Ptr appTx = CreateObject(); appTx->SetKey("sender-tx-packets"); + appTx->SetContext("node[0]"); Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx", MakeCallback(&PacketCounterCalculator::PacketUpdate, appTx)); @@ -237,6 +240,7 @@ Ptr > appRx = CreateObject >(); appRx->SetKey("receiver-rx-packets"); + appRx->SetContext("node[1]"); receiver->SetCounter(appRx); data.AddDataCalculator(appRx); @@ -263,6 +267,7 @@ Ptr appTxPkts = CreateObject(); appTxPkts->SetKey("tx-pkt-size"); + appTxPkts->SetContext("node[0]"); Config::Connect("/NodeList/0/ApplicationList/*/$Sender/Tx", MakeCallback (&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate, @@ -277,6 +282,7 @@ Ptr delayStat = CreateObject(); delayStat->SetKey("delay"); + delayStat->SetContext("."); receiver->SetDelayTracker(delayStat); data.AddDataCalculator(delayStat); diff -r 5d448b8564e5 src/contrib/stats/basic-data-calculators.h --- a/src/contrib/stats/basic-data-calculators.h Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/basic-data-calculators.h Wed Jul 01 16:12:09 2009 +0200 @@ -29,7 +29,8 @@ //------------------------------------------------------------ //-------------------------------------------- template - class MinMaxAvgTotalCalculator : public DataCalculator { + class MinMaxAvgTotalCalculator : public DataCalculator, + public StatisticalSummary { public: MinMaxAvgTotalCalculator(); virtual ~MinMaxAvgTotalCalculator(); @@ -38,6 +39,15 @@ 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 @@ } // end MinMaxAvgTotalCalculator::Update } + template void MinMaxAvgTotalCalculator::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 @@ -178,7 +180,7 @@ void CounterCalculator::Output(DataOutputCallback &callback) const { - callback.OutputSingleton(m_key, "count", m_count); + callback.OutputSingleton(m_context, m_key, m_count); // end CounterCalculator::Output } diff -r 5d448b8564e5 src/contrib/stats/data-calculator.cc --- a/src/contrib/stats/data-calculator.cc Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/data-calculator.cc Wed Jul 01 16:12:09 2009 +0200 @@ -27,6 +27,8 @@ NS_LOG_COMPONENT_DEFINE("DataCalculator"); +static double zero = 0; +const double ns3::NaN = zero / zero; //-------------------------------------------------------------- //---------------------------------------------- @@ -70,6 +72,20 @@ //---------------------------------------------- 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() { m_enabled = true; diff -r 5d448b8564e5 src/contrib/stats/data-calculator.h --- a/src/contrib/stats/data-calculator.h Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/data-calculator.h Wed Jul 01 16:12:09 2009 +0200 @@ -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 @@ 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 @@ bool m_enabled; // Descendant classes *must* check & respect m_enabled! std::string m_key; + std::string m_context; virtual void DoDispose(void); diff -r 5d448b8564e5 src/contrib/stats/data-output-interface.h --- a/src/contrib/stats/data-output-interface.h Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/data-output-interface.h Wed Jul 01 16:12:09 2009 +0200 @@ -23,6 +23,7 @@ #include "ns3/object.h" #include "ns3/nstime.h" +#include "ns3/data-calculator.h" namespace ns3 { @@ -52,6 +53,10 @@ 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; diff -r 5d448b8564e5 src/contrib/stats/omnet-data-output.cc --- a/src/contrib/stats/omnet-data-output.cc Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/omnet-data-output.cc Wed Jul 01 16:12:09 2009 +0200 @@ -19,6 +19,7 @@ */ #include +#include #include "ns3/log.h" #include "ns3/nstime.h" @@ -54,26 +55,31 @@ } //---------------------------------------------- + +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 @@ } 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 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 @@ // end OmnetDataOutput::Output } + OmnetDataOutput::OmnetOutputCallback::OmnetOutputCallback (std::ostream *scalar) : m_scalar(scalar) @@ -104,42 +122,92 @@ } 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 } diff -r 5d448b8564e5 src/contrib/stats/omnet-data-output.h --- a/src/contrib/stats/omnet-data-output.h Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/omnet-data-output.h Wed Jul 01 16:12:09 2009 +0200 @@ -45,24 +45,28 @@ 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: diff -r 5d448b8564e5 src/contrib/stats/sqlite-data-output.cc --- a/src/contrib/stats/sqlite-data-output.cc Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/sqlite-data-output.cc Wed Jul 01 16:12:09 2009 +0200 @@ -154,6 +154,25 @@ } 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, int val) diff -r 5d448b8564e5 src/contrib/stats/sqlite-data-output.h --- a/src/contrib/stats/sqlite-data-output.h Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/sqlite-data-output.h Wed Jul 01 16:12:09 2009 +0200 @@ -48,6 +48,10 @@ public: SqliteOutputCallback(Ptr 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); diff -r 5d448b8564e5 src/contrib/stats/time-data-calculators.cc --- a/src/contrib/stats/time-data-calculators.cc Mon Jun 29 13:24:10 2009 +0200 +++ b/src/contrib/stats/time-data-calculators.cc Wed Jul 01 16:12:09 2009 +0200 @@ -70,12 +70,12 @@ 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 }