====== Statistics Capability ======
The purpose of simulators is not only to compute timing information, but also to gather information about the behavior of the different hardware mechanism during the simulation. The **Statistic Capability** allow a standardize access to event counters within the different modules.
===== Description =====
Many information in the module can be characterized by a single counter: The number of //executed instruction// in the CPU, the number of //read hit// in the cache, and so on... The **Statistic Capability** proposes a standardized interface for such counters.
===== Interface =====
The Statistic Interface is very simple, just providing a method to access a counter based on its name, as shown in the figure below:
{{ statistic_capability.png }}
A counter should consist of a unsigned 64 bit integer (''uint64_t''). The interface allows to get a counter from its name provided as a string. If a counter with the provided name does not exists in the module, an exception is raised.
Note that accessing the counter through its name as a string is much less efficient than directly accessing the integer counter. However the module internally will not use this interface, but directly use the integer counters (the //cache module// for instance will directly increment the ''read_miss'' counter every time there is a read miss.
External components (like GUI for instance) will access those counters through the interface. As this kind of access does not occur very often, the penalty for acceding a counter through its name remains minimal.
The interface for the Statistic Capability is defined in the ''StatisticInterface'' presented below:
class StatisticInterface
{public:
virtual uint64_t get_statistic(const string &name)=0;
};
The next section describes how to use the statistic capability within your own modules.
===== How To use the Statistic Capability in your module =====
The **Statistic Capability** is meant to be used with modules which already use counters to count down some events during the simulation. As an example, let's focus on the //cache module//. This module has the following counters defined as properties of the cache class:
class Cache : public module
, ...
{ ...
uint64_t accesses; // Total number of accesses
uint64_t accesses_read; // Total number of read accesses
uint64_t accesses_write; // Total number of write accesses
uint64_t hits; // Total number of hits
uint64_t hits_read; // Total number of read hits
uint64_t hits_write; // Total number of write hits
uint64_t misses; // Total number of misses
uint64_t misses_read; // Total number of read misses
uint64_t misses_write; // Total number of write misses
...
}
To make the Cache module statistic compliant, the first step is to add a new include, so that the Statistic Interface is defined:
#include "statistics/StatisticService.h"
The second step to make the cache module Statistic compliant, is to make the module inherits the **Statistic Service**, modifying the class declaration and the class constructor as shown below:
class Cache : public module
, public StatisticService
, ...
{ ...
Cache(char *name) : module(name)
, StatisticService(name, this)
, ...
{ ...
}
...
}
Inheriting the **Statistic Service** automatically creates the following service port in the module:
ServiceExport < StatisticInterface > statistic_export;
You will be able to use the service through this port.
The third step consist of **registering each statistic** to make it available through the statistic service. This registration maps a string corresponding to the statistic to the statistic itself.
Registering a statistic is done by using the ''add'' method of the ''statistics'' repository as shown below:
statistics.add("stat",stat);
The code above associate the name "stat" to a ''uint64_t'' statistic named ''stat''.
To register the statistic of our cache module, we simply need to register all the statistic in the constructor of the class:
class Cache : public module
, public StatisticService
, ...
{ ...
Cache(char *name) : module(name)
, StatisticService(name, this)
, ...
{ ...
// --- Registering statistics ----------------
statistics.add("accesses",accesses);
statistics.add("accesses_read",accesses_read);
statistics.add("accesses_write",accesses_write);
statistics.add("hits",hits);
statistics.add("hits_read",hits_read);
statistics.add("hits_write",hits_write);
statistics.add("misses",misses);
statistics.add("misses_read",misses_read);
statistics.add("misses_write",misses_write);
// -------------------------------------------
}
...
}
The last step consist of accessing the statistics for your particular need. Let's say for instance you want to display the //cache miss rate//
at the end of the simulation. You will add the following code after the main simulation loop in your simulator:
cerr << "L1 miss rate: " << cache_l1.get_statistic("accesses_read") / cache_l1.get_statistic("misses_read") << endl;
Note that you can also display the miss rate as a timeline during the simlation by using the statistics in a dedicated thread displaying the timeline.
===== Reference Manual =====
* [[http://unisim.org/website/refman/capabilities/statistics/refman.pdf|Statistics Capability reference manual]]
===== Some modules using the Statistic Capability =====
The following module from the repository are using the Statistic Capability:
* [[modules:cycle:processors:powerpc405:|PowerPC 405 CPU]]
* [[modules:cycle:processors:armv5te|Arm v5te CPU]]
* [[modules:cycle:network:cachewb:|Write-back Cache]]
* [[modules:cycle:network:dram:|DRAM Memory]]