Skip to content

Commit

Permalink
topdown: Created a component for interfacing with Intel's PERF_METRIC…
Browse files Browse the repository at this point in the history
…S MSR

Add a component that collects Intel's topdown metrics from the
PERF_METRICS MSR and automatically converts the raw metric values to
user-consumable percentages.

The intent of this component is to provide an intuitive interface for
accessing topdown metrics on the supported processors.

Tested on a RaptorLake-S/HX machine (family/model/stepping
0x6/0xb7/0x1). To add other supported architectures the switch statment
in _topdown_init_component() should be populated for the architecture's
model number, whether it supports level 2 topdown metrics, and in the
case of a heterogeneous processor what core type it must be run on.
  • Loading branch information
willowec committed Nov 17, 2024
1 parent 09fee01 commit ed66b8d
Show file tree
Hide file tree
Showing 8 changed files with 1,420 additions and 0 deletions.
35 changes: 35 additions & 0 deletions src/components/topdown/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# TOPDOWN Component

The `topdown` component enables accessing the `PERF_METRICS` Model Specific
Register (MSR) of modern Intel PMUs, and makes it simple to properly
interpret the results.

* [Enabling the TOPDOWN Component](#enabling-the-topdown-component)
* [Adding More Architectures](#adding_more_architectures)

## Enabling the TOPDOWN Component

To enable reading of topdown metrics the user needs to link against a
PAPI library that was configured with the topdown component enabled. As an
example the following command: `./configure --with-components="topdown"` is
sufficient to enable the component.

## Interpreting Results

The events added by this component ending in "_PERC" should be cast to double
values in order to be properly interpreted as percentages. An example of how
to do so follows:

PAPI_start(EventSet);

/* some block of code... */

PAPI_stop(EventSet, values);

printf("First metric was %.1f\n", *((double *)(&values[0])));

## Adding More Architectures

To contribute more supported architectures to the component, add the cpuid model
of the architecture to the case statement in `_topdown_init_component` of
[topdown.c](./topdown.c) and set the relevant options (`supports_l2`, etc.)
5 changes: 5 additions & 0 deletions src/components/topdown/Rules.topdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
COMPSRCS += components/topdown/topdown.c
COMPOBJS += topdown.o

topdown.o: components/topdown/topdown.c components/topdown/topdown.h $(HEADERS)
$(CC) $(LIBCFLAGS) $(OPTFLAGS) -c components/topdown/topdown.c -o topdown.o
22 changes: 22 additions & 0 deletions src/components/topdown/tests/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
NAME=topdown
include ../../Makefile_comp_tests.target

%.o:%.c
$(CC) $(CFLAGS) $(OPTFLAGS) $(INCLUDE) -c -o $@ $<

TESTS = topdown_basic topdown_L1 topdown_L2

topdown_tests: $(TESTS)

topdown_basic: topdown_basic.o $(UTILOBJS) $(PAPILIB)
$(CC) $(CFLAGS) $(INCLUDE) -o topdown_basic topdown_basic.o $(UTILOBJS) $(PAPILIB) $(LDFLAGS)

topdown_L1: topdown_L1.o $(UTILOBJS) $(PAPILIB)
$(CC) $(CFLAGS) $(INCLUDE) -o topdown_L1 topdown_L1.o $(UTILOBJS) $(PAPILIB) $(LDFLAGS)

topdown_L2: topdown_L2.o $(UTILOBJS) $(PAPILIB)
$(CC) $(CFLAGS) $(INCLUDE) -o topdown_L2 topdown_L2.o $(UTILOBJS) $(PAPILIB) $(LDFLAGS)


clean:
rm -f $(TESTS) *.o
177 changes: 177 additions & 0 deletions src/components/topdown/tests/topdown_L1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Specifically tests that the Level 1 topdown events make sense.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "papi.h"
#include "papi_test.h"

#define NUM_EVENTS 4
#define PERC_TOLERANCE 1.5

// fibonacci function to serve as a benchable code section
void __attribute__((optimize("O0"))) fib(int n)
{
long i, a = 0;
int b = 1;
for (i = 0; i < n; i++)
{
b = b + a;
a = b - a;
}
}

int main(int argc, char **argv)
{
int i, quiet, retval;
int EventSet = PAPI_NULL;
const PAPI_component_info_t *cmpinfo = NULL;
int numcmp, cid, topdown_cid = -1;
long long values[NUM_EVENTS];
double tmp;

/* Set TESTS_QUIET variable */
quiet = tests_quiet(argc, argv);

/* PAPI Initialization */
retval = PAPI_library_init(PAPI_VER_CURRENT);
if (retval != PAPI_VER_CURRENT)
{
test_fail(__FILE__, __LINE__, "PAPI_library_init failed\n", retval);
}

if (!quiet)
{
printf("Testing topdown component with PAPI %d.%d.%d\n",
PAPI_VERSION_MAJOR(PAPI_VERSION),
PAPI_VERSION_MINOR(PAPI_VERSION),
PAPI_VERSION_REVISION(PAPI_VERSION));
}

/*******************************/
/* Find the topdown component */
/*******************************/
numcmp = PAPI_num_components();
for (cid = 0; cid < numcmp; cid++)
{
if ((cmpinfo = PAPI_get_component_info(cid)) == NULL)
{
test_fail(__FILE__, __LINE__, "PAPI_get_component_info failed\n", 0);
}
if (!quiet)
{
printf("\tComponent %d - %d events - %s\n", cid,
cmpinfo->num_native_events,
cmpinfo->name);
}
if (strstr(cmpinfo->name, "topdown"))
{
topdown_cid = cid;

/* check that the component is enabled */
if (cmpinfo->disabled)
{
printf("Topdown component is disabled: %s\n", cmpinfo->disabled_reason);
test_fail(__FILE__, __LINE__, "Component is not enabled\n", 0);
}
}
}

if (topdown_cid < 0)
{
test_skip(__FILE__, __LINE__, "Topdown component not found\n", 0);
}

if (!quiet)
{
printf("\nFound Topdown Component at id %d\n", topdown_cid);
printf("\nAdding the level 1 topdown metrics..\n");
}

/* Create EventSet */
retval = PAPI_create_eventset(&EventSet);
if (retval != PAPI_OK)
{
test_fail(__FILE__, __LINE__,
"PAPI_create_eventset()", retval);
}

/* Add the level 1 topdown metrics */
retval = PAPI_add_named_event(EventSet, "TOPDOWN_RETIRING_PERC");
if (retval != PAPI_OK)
{
test_fail(__FILE__, __LINE__,
"Error adding TOPDOWN_RETIRING_PERC", retval);
}
retval = PAPI_add_named_event(EventSet, "TOPDOWN_BAD_SPEC_PERC");
if (retval != PAPI_OK)
{
test_fail(__FILE__, __LINE__,
"Error adding TOPDOWN_BAD_SPEC_PERC", retval);
}
retval = PAPI_add_named_event(EventSet, "TOPDOWN_FE_BOUND_PERC");
if (retval != PAPI_OK)
{
test_fail(__FILE__, __LINE__,
"Error adding TOPDOWN_FE_BOUND_PERC", retval);
}
retval = PAPI_add_named_event(EventSet, "TOPDOWN_BE_BOUND_PERC");
if (retval != PAPI_OK)
{
test_fail(__FILE__, __LINE__,
"Error adding TOPDOWN_BE_BOUND_PERC", retval);
}

/* stat a loop-based calculation of the sum of the fibonacci sequence */
/* the workload needs to be fairly large in order to acquire an accurate */
/* set of measurements */
PAPI_start(EventSet);
fib(6000000);
PAPI_stop(EventSet, values);

/* run some sanity checks: */

/* first, the sum of all level 1 metric percentages should be 100% */
tmp = 0;
for (i=0; i<NUM_EVENTS; i++) {
tmp += *((double *)(&values[i]));
}
if (!quiet)
printf("L1 metric percentages sum to %.2f%%\n", tmp);
if (tmp < 100 - PERC_TOLERANCE || tmp > 100 + PERC_TOLERANCE) {
test_fail(__FILE__, __LINE__,
"Level 1 topdown metric percentages did not sum to 100%%\n", 1);
}

if (!quiet)
printf("\tRetiring:\t%.1f%%\n", *((double *)(&values[0])));

/* next, verify that the percentage of bad spec slots is reasonable. */
/* for this benchmark, we can expect very low rate of bad speculation */
/* due to the fact that it consists of a simple for loop */
if (!quiet)
printf("\tBad spec:\t%.1f%%\n", *((double *)(&values[1])));
if (*((double *)(&values[1])) > 5.0) {
test_warn(__FILE__, __LINE__,
"The percentage of slots affected by bad speculation was unexpectedly high", 1);
}

/* finally, make sure the frontend/backend bound percentages make sense */
/* we should expect this benchmark to be significantly more limited */
/* by the back end, so check that be bound is larger than the fe bound */
if (!quiet) {
printf("\tFrontend bound:\t%.1f%%\n", *((double *)(&values[2])));
printf("\tBackend bound:\t%.1f%%\n", *((double *)(&values[3])));

}
if (*((double *)(&values[2])) > *((double *)(&values[3]))) {
test_warn(__FILE__, __LINE__,
"Frontend bound should be significantly smaller than backend bound", 1);
}

return 0;
}
Loading

0 comments on commit ed66b8d

Please sign in to comment.