EMANE  1.0.1
Statistic Service

The StatisticRegistrar is used by components to create statistics and statistic tables. Statistics and statistic tables are owned by the emulator framework so StatisticRegistrar::registerNumeric, StatisticRegistrar::registerNonNumeric and StatisticRegistrar::registerTable all return borrowed references. The framework takes care of cleaning these up after all component plugins have been destroyed.

Registering Statistics

Statistics and statistic tables can only be registered during Component::initialize. The StatisticRegistrar is accessible via the initialize method's Registrar argument.

There are two types of statistics:

Both statistic types are templates and are thread safe. StatisticNumeric instances can be instantiated with the following types:

  • std::int64_t
  • std::int32_t
  • std::int16_t
  • std::int8_t
  • std::uint64_t
  • std::uint32_t
  • std::uint16_t
  • std::uint8_t
  • bool
  • float
  • double

StatisticNonNumeric template instances can be instantiated with the following types:

  • std::string
  • INETAddr

Statistics can be given the StatisticProperties::CLEARABLE property during registration. This property lets client applications clear the statistic using the Remote Control Port API.

The following snippet shows an example of registering clearable statistics.

avgUpstreamProcessingDelay_.registerStatistic(
statisticRegistrar.registerNumeric<Average>("avgUpstreamProcessingDelay" + sInstance_,
StatisticProperties::CLEARABLE,
"Average upstream processing delay"));
// upstream tx ucast
pNumUpstreamPacketsUnicastTx_ =
statisticRegistrar.registerNumeric<Counter>("numUpstreamPacketsUnicastTx" + sInstance_,
StatisticProperties::CLEARABLE,
"Number of upstream unicast packets transmitted");
pNumUpstreamBytesUnicastTx_ =
statisticRegistrar.registerNumeric<Counter>("numUpstreamBytesUnicastTx" + sInstance_,
StatisticProperties::CLEARABLE,
"Number of upstream unicast bytes transmitted");

Registering Statistic Tables

A StatisticTable is a two dimensional table of Any instances. An Any instance is sort of a smart union. It can hold any of the types allowed when creating instances of StatisticNumeric and StatisticNonNumeric.

Statistic Table rules:

  • Every row in a statistic table must contain the same number of columns.
  • Each entry in a column may have a different Any type although doing so may make your table hard to interpret.
  • You may change the Any type of an entry on every update since you are using Any instances - this would be even harder to interpret.

You specify the number of columns in a table by setting the table column names. The number of column names will equal the number of columns in the table. The template parameters to StatisticTable allow you to set the table key type, the column index that will be used to sort the table and a binary predicate that takes two element keys as arguments and returns a bool which is used to sort the table. The template parameter defaults are usually what you want.

pLocationTable_ =
statisticRegistrar.registerTable<NEMId>("LocationEventInfoTable",
{"NEM","Latitude","Longitude","Altitude","Pitch","Roll","Yaw","Azimuth","Elevation","Magnitude"},
StatisticProperties::NONE,
"Shows the location event information received");
pPathlossTable_ =
statisticRegistrar.registerTable<NEMId>("PathlossEventInfoTable",
{"NEM","Forward Pathloss","Reverse Pathloss"},
StatisticProperties::NONE,
"Shows the precomputed pathloss information received");
pAntennaProfileTable_ =
statisticRegistrar.registerTable<NEMId>("AntennaProfileEventInfoTable",
{"NEM","Antenna Profile","Antenna Azimuth","Antenna Elevation"},
StatisticProperties::NONE,
"Shows the antenna profile information received");

Just like statistics, statistic tables can be clearable. Clearing a statistic table is not as straight forward as clearing a statistic. In order to manage statistic table entries you will need to keep track of which items are in the table and what their current values are. An external clear request may be like pulling the rug out from under your table management logic.

To address this you need to pass a callable object that takes a single StatisticTable * as an argument and returns void. When a table clear request is made the emulator will call the callable to allow it to clear the table. This is one of the few instances where the framework will call a component method from an internal thread. So even though a StatisticTable is thread safe, execution of this callable is not. If you are accessing shared data in the callable you must use a synchronization object.

When you register a table with a callable it automatically applies the CLEARABLE property to the table. If you wish to register a clearable table without a callable use the other form of the method and manually set the CLEARABLE property.

pStatisticUnicastDropTable_ =
statisticRegistrar.registerTable<NEMId>("UnicastPacketDropTable" + sInstance_,
unicastDropTableLabels_,
[this](StatisticTablePublisher * pTable)
{
std::lock_guard<std::mutex> m(nemUnicastDropTableMutex_);
nemUnicastDropCodeMap_.clear();
pTable->clear();
},
"Unicast packets dropped by reason code");