Reading the performance counters is done by two types of functions: The first type is generic, accepting which counter to read as an argument. The second type is logical, with the event name being part of the function's name. This separation allows the programmer two different modus operandi:
Both types are implemented using compile time generated inlined functions. The reasoning behind this implementation is that while it would be simpler to just generate a logical to physical counter map and have a function use that map, such method involves more overhead and cache pollution.
The first, counter-based interface is defined as:
unsigned long klogger_get_counter(unsigned long ctr); unsigned long long klogger_get_counter_ll(unsigned long ctr);where the first function returns just the lower 32 bits of the 64 bit counter, and the second function returns the entire 64 bit number. The ctr argument is a macro, named KLOGGER_COUNTERN where N is the counter number -- i.e. KLOGGER_COUNTER1, KLOGGER_COUNTER4, etc.
The second function type is declared as:
unsigned long klogger_get_EVENTNAME() unsigned long klogger_get_EVENTNAME_ll()where EVENTNAME is the actual name used in the configuration file.
Returning once again to our SCHEDOUT example, we can read the counter we defined using either function type. We bound logical counter 1 to the l2_cache_misses_user event. Thus, using the first function type, logging would take place using the following line:
klogger(SCHEDOUT, task->pid, klogger_get_counter(KLOGGER_COUNTER1);
If we want to use the function based on the event names, we just use the following line:
klogger(SCHEDOUT, task->pid, klogger_get_l2_cache_misses_user());
Sometimes the logging is not completely straightforward, involving some code preparing the data to be logged. In such cases, it may be important to know for which architecture the kernel was compiled. For that reason we use the KLOGGER_ARCH_COMPILED macro which is set to one of the klogger_arch_t enumeration values, defined in include/asm/klogger.h.