CollectingGlobalStatistics

Main.CollectingGlobalStatistics History

Hide minor edits - Show changes to markup

April 01, 2006, at 04:22 PM by Andras -
Changed lines 3-4 from:

How do I collect global statistics in a model? I read some warning agains global variables in the Manual and it recommends using a separate module instead, but I have no idea how to do that.

to:

How do I collect global statistics in a model? I read some warning agains global variables in the Manual and it recommends using a separate module instead, but I have no idea how to do that.

February 28, 2006, at 04:57 PM by Andras -
Changed lines 142-145 from:

I am intrested in the plugin mentioned which displays the information of collecting statistic.

to:

---

Notes

I am interested in the plugin mentioned which displays the information of collecting statistic. Michael

February 28, 2006, at 03:36 PM by Michael -
Added lines 141-142:

I am intrested in the plugin mentioned which displays the information of collecting statistic.

December 05, 2005, at 09:40 AM by Andras -
Changed line 89 from:
 class cStatisticsCollector : public cSimpleModule
to:
 class StatisticsCollector : public cSimpleModule
Changed line 97 from:
 Define_Module(cStatisticsCollector)
to:
 Define_Module(StatisticsCollector);
Changed lines 103-106 from:

simple cStatisticsCollector

 gates:
 in: in[]; // declare in[] and out[] to be vector gates
 out: out[];       
to:

simple StatisticsCollector

Changed lines 110-111 from:

submodules: StatisticsCollector: cStatisticsCollector;

to:
    submodules:
        statisticsCollector: StatisticsCollector;
Changed line 119 from:
 cStatisticsCollector *stats = check_and_cast<cStatisticsCollector *>(modp);
to:
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);
Changed lines 122-123 from:

Then you could use your `cStatisticsCollector methods to update the statistics.

to:

Then you could use your StatisticsCollector methods to update the statistics.

December 04, 2005, at 11:37 PM by Omer Sinan Kaya -
Changed line 89 from:
 class StatisticsCollector : public cSimpleModule
to:
 class cStatisticsCollector : public cSimpleModule
Added line 97:
 Define_Module(cStatisticsCollector)
Changed lines 100-101 from:

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

to:

Add this definition to your ned file.

Changed lines 103-105 from:
 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);
to:

simple cStatisticsCollector

 gates:
 in: in[]; // declare in[] and out[] to be vector gates
 out: out[];       

endsimple

Changed lines 110-111 from:

Then you could use your StatisticsCollector methods to update the statistics.

to:

Add a module of this type to your submodules list

Changed lines 113-115 from:
 double eed = ...
 stats->addEndToEndDelay(eed);
 ...
to:

submodules: StatisticsCollector: cStatisticsCollector;

Changed lines 117-121 from:

If you use classes such as cDoubleHistogram inside the StatisticsCollector (see Modules/Statistical data collection in the API-doc), the inspectors of those classes can display mean, stddev, etc and also the histogram graphically. If you keep or calculate additional statistics, you can make them visible via WATCH().

Now if you want to collect separate statistics for "subnet A" and "subnet B", you just create two instances of StatisticsCollector, and point ProtocolX's statsModulePath parameters to the appropriate one:

to:

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

Changed lines 120-121 from:
 net.subnetA.**.protX.statsModulePath = "net.subnetA.statisticsCollector"
 net.subnetB.**.protX.statsModulePath = "net.subnetB.statisticsCollector"
to:
 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 cStatisticsCollector *stats = check_and_cast<cStatisticsCollector *>(modp);
Added lines 125-142:

Then you could use your `cStatisticsCollector methods to update the statistics.

 double eed = ...
 stats->addEndToEndDelay(eed);
 ...

If you use classes such as cDoubleHistogram inside the StatisticsCollector (see Modules/Statistical data collection in the API-doc), the inspectors of those classes can display mean, stddev, etc and also the histogram graphically. If you keep or calculate additional statistics, you can make them visible via WATCH().

Now if you want to collect separate statistics for "subnet A" and "subnet B", you just create two instances of StatisticsCollector, and point ProtocolX's statsModulePath parameters to the appropriate one:

 net.subnetA.**.protX.statsModulePath = "net.subnetA.statisticsCollector"
 net.subnetB.**.protX.statsModulePath = "net.subnetB.statisticsCollector"

November 15, 2005, at 05:33 PM by Andras -
Added lines 9-10:

Jump to preferred solution, or read the full text below.

Changed lines 81-82 from:

Using a single global module

to:

Using a single global module

Changed lines 118-121 from:

Now if you want to collect separate statistics for "subnet A" and "subnet B", you just create two instances of StatisticsCollector, and point ProtocolX statsModulePath parameters like this:

statsModulePath

to:

Now if you want to collect separate statistics for "subnet A" and "subnet B", you just create two instances of StatisticsCollector, and point ProtocolX's statsModulePath parameters to the appropriate one:

 net.subnetA.**.protX.statsModulePath = "net.subnetA.statisticsCollector"
 net.subnetB.**.protX.statsModulePath = "net.subnetB.statisticsCollector"

November 15, 2005, at 05:23 PM by Andras -
Changed lines 73-75 from:
to:

But even so, a drawback is that

  • (a) in the output file the recorded stats appear to belong to the particular module that recorded it, which might be misleading, and
  • (b) if you have to subnets in the model for which you want to collect statistics separately (i.e. "total pks dropped in subnet A" and "total pks dropped in subnet B"), then you're stuck.
Changed lines 77-78 from:
to:

A slightly more complex but superior solution is to use a a single global module, described below.

Changed lines 81-82 from:

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

to:

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

Added lines 115-118:

Now if you want to collect separate statistics for "subnet A" and "subnet B", you just create two instances of StatisticsCollector, and point ProtocolX statsModulePath parameters like this:

statsModulePath

November 15, 2005, at 05:14 PM by Andras -
Deleted lines 8-9:

Global variables

Changed line 17 from:
      virtual void handleMessage(cMessage *msg)
to:
      virtual void handleMessage(cMessage *msg);
Changed lines 32-39 from:

Using a single global module

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

How does it look like in practice? You could define a module called e.g. StatisticsCollector, and add public member functions to it for updating the statistics:

to:

To solve this, you can initialize the variable in the module's initialize() method. The drawback: if you have 100 instances of the module, the variable will be initialized 100 times. (That might be OK though.)

A similar problem occurs when you want to record the variables at the end of the simulation. If you just put the code into finish(), you'll end up recording the same value 100 times. The workaround is to introduce a statsAlreadyRecorded boolean global variable (which also has to be initialized in initialize()!).

This yields the following code:

Changed line 39 from:
 class StatisticsCollector : public cSimpleModule
to:
 class ProtocolX : public cSimpleModule
Changed lines 41-45 from:
   ...
   public:
     void addEndToEndDelay(double d);
     void incNumPacketsDropped();
     ...
to:
    protected:
      static bool statsAlreadyRecorded;
      static long totalPkDropped;

      virtual void initialize();
      virtual void handleMessage(cMessage *msg);
      virtual void finish()
Added lines 49-70:
 bool ProtocolX::statsAlreadyRecorded;
 long ProtocolX::totalPkDropped;

 void ProtocolX::initialize()
 {
     statsAlreadyRecorded = false;
     totalPkDropped = 0;
 }
 void ProtocolX::handleMessage(cMessage *msg)
 {
     ...
     totalPkDropped++;
     ...
 }
 void ProtocolX::finish()
 {
     if (!statsAlreadyRecorded) {
        recordScalar("total pks dropped", totalPkDropped);
        statsAlreadyRecorded = true;
     }
 }
Changed lines 73-74 from:

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

to:

Using a single global module

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

How does it look like in practice? You could define a module called e.g. StatisticsCollector, and add public member functions to it for updating the statistics:

Changed lines 83-85 from:
 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);
to:
 class StatisticsCollector : public cSimpleModule
 {
   ...
   public:
     void addEndToEndDelay(double d);
     void incNumPacketsDropped();
     ...
 };
Changed lines 93-94 from:

Then you could use your StatisticsCollector methods to update the statistics.

to:

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

Changed lines 96-98 from:
 double eed = ...
 stats->addEndToEndDelay(eed);
 ...
to:
 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);
Added lines 101-108:

Then you could use your StatisticsCollector methods to update the statistics.

 double eed = ...
 stats->addEndToEndDelay(eed);
 ...

November 15, 2005, at 05:01 PM by Andras -
Added lines 9-10:

Global variables

Changed lines 12-17 from:

occurs with singletons, which are basically global variables put in the fancy way.

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

How does it look like in practice? You could define a module called e.g. StatisticsCollector, and add public member functions to it for updating the statistics:

to:

occurs with singletons, which are basically global variables put in the fancy way. Let's see an example:

Changed line 15 from:
 class StatisticsCollector : public cSimpleModule
to:
 class ProtocolX : public cSimpleModule
Changed lines 17-21 from:
   ...
   public:
     void addEndToEndDelay(double d);
     void incNumPacketsDropped();
     ...
to:
    protected:
      static long totalPkDropped; // counter
      virtual void handleMessage(cMessage *msg)
Added lines 21-29:
 long ProtocolX::totalPkDropped = 0; // definition and initialization -- WRONG!

 void ProtocolX::handleMessage(cMessage *msg)
 {
     ...
     totalPkDropped++;
     ...
 }
Changed lines 32-33 from:

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

to:

The problem is, when you restart the simulation in Tkenv, the counter will start counting where it left off last time, not from zero. C++ initializes global vars at the start of the program, and it has no idea that you also want to reset it when OMNeT++ rebuilds a network.

Using a single global module

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

How does it look like in practice? You could define a module called e.g. StatisticsCollector, and add public member functions to it for updating the statistics:

Changed lines 43-45 from:
 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);
to:
 class StatisticsCollector : public cSimpleModule
 {
   ...
   public:
     void addEndToEndDelay(double d);
     void incNumPacketsDropped();
     ...
 };
Changed lines 53-54 from:

Then you could use your StatisticsCollector methods to update the statistics.

to:

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

Changed lines 56-58 from:
 double eed = ...
 stats->addEndToEndDelay(eed);
 ...
to:
 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);
Added lines 61-68:

Then you could use your StatisticsCollector methods to update the statistics.

 double eed = ...
 stats->addEndToEndDelay(eed);
 ...

November 15, 2005, at 04:40 PM by Andras -
Changed lines 3-4 from:

How do I collect global statistics in a model?

to:

How do I collect global statistics in a model? I read some warning agains global variables in the Manual and it recommends using a separate module instead, but I have no idea how to do that.

Added lines 9-46:

To start with, global variables aren't very good for use in the model, because they don't get reset when you restart the simulation in Tkenv. The same problem occurs with singletons, which are basically global variables put in the fancy way.

A good way is to introduce a single global module, encapsulate the variables into it as private or protected data members, and expose them via public methods. Other modules can then call these public methods to get or set the values.

How does it look like in practice? You could define a module called e.g. StatisticsCollector, and add public member functions to it for updating the statistics:

 class StatisticsCollector : public cSimpleModule
 {
   ...
   public:
     void addEndToEndDelay(double d);
     void incNumPacketsDropped();
     ...
 };

Then from other modules you can get a pointer to it using cSimulation::moduleByPath(), then cast it to the specific subclass:

 const char *statsModulePath = par("statsModulePath");
 cModule *modp = simulation.moduleByPath(statsModulePath);
 StatisticsCollector *stats = check_and_cast<StatisticsCollector *>(modp);

Then you could use your StatisticsCollector methods to update the statistics.

 double eed = ...
 stats->addEndToEndDelay(eed);
 ...

If you use classes such as cDoubleHistogram inside the StatisticsCollector (see Modules/Statistical data collection in the API-doc), the inspectors of those classes can display mean, stddev, etc and also the histogram graphically. If you keep or calculate additional statistics, you can make them visible via WATCH().

And to make the whole thing look nice, it's possible to use a Tkenv plugin which displays a custom panel with whatever data needs to be displayed. (If someone needs this, please drop a note here, and I'll add more info. Andras)

November 15, 2005, at 04:28 PM by Andras -
Added lines 1-8:

Problem

How do I collect global statistics in a model?

Solution

Based on the mailing list post "RE: Singleton Class or a Statistics Collector Module" on 25 Nov 2003 (online)
Edit - History - Print - Recent Changes - Search
Page last modified on April 01, 2006, at 04:22 PM