====== 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]]