Skip to content

PAPI Multiplexing

Treece Burgess edited this page Aug 21, 2024 · 17 revisions

Multiplexing

Multiplexing allows more events to be counted than can be supported by the hardware. When a microprocessor has a limited number of hardware counters, a large application with many hours of run time may require days or weeks of profiling in order to gather enough information on which to base a performance analysis. Multiplexing overcomes this limitation by subdividing the usage of the counter hardware over time (timesharing) among a large number of performance events.

Using PAPI with Multiplexing

Initialization of Multiplex Support

Multiplex support in the PAPI library can be enabled and initialized by calling the following low-level function:

C:

int retval = PAPI_multiplex_init();

No arguments for PAPI_multiplex_init.

Fortran:

use iso_c_binding
integer(c_int) check
call PAPIF_multiplex_init(check)

Fortran arguments for PAPIF_multiplex_init:

  • check -- an error return value for Fortran.

The above function sets up the internal structures to allow more events to be counted than there are physical counters. It does this by timesharing the existing counters at some loss in precision. This function should be used after calling PAPI_library_init. After this function is called, the user can proceed to use the normal PAPI routines. It should be also noted that applications that make no use of multiplexing should not call this function.

On success, this function returns PAPI_OK and on error, a non-zero error code is returned.

For a code example, see the next section.

Converting an EventSet into a Multiplexed EventSet

A standard event set can be converted to a multiplexed event set by the calling the following low-level functions:

C:

int EventSet, EventCode;
int retval = PAPI_add_event(EventSet, EventCode);

Arguments for PAPI_add_event:

  • EventSet -- an integer handle for a PAPI event set as created by PAPI_create_eventset.
  • EventCode -- a defined event such as PAPI_TOT_INS.
int EventSet, cidx;
int retval = PAPI_assign_eventset_component(EventSet, cidx);

Arguments for PAPI_assign_eventset_component:

  • EventSet -- an integer handle for a PAPI event set as created by PAPI_create_eventset.
  • cidx -- an integer value for a component index; by convention the CPU is always 0.
int EventSet;
int retval = PAPI_set_multiplex(EventSet);

Arguments for PAPI_set_multiplex:

  • EventSet -- an integer handle for a PAPI event set as created by PAPI_create_eventset.

${{\color{Darkorange}{\textsf{Note: PAPI\_set\_multiplex cannot be called until after the EventSet is bound to a component. See paragraph below for details.}}}}$

Fortran:

use iso_c_binding
integer(c_int) EventSet, EventCode, check
call PAPIF_add_event(EventSet, EventCode, check)

Fortran arguments for PAPIF_add_event:

  • EventSet -- an integer handle for a PAPI event set as created by PAPI_create_eventset.
  • EventCode -- a defined event such as PAPI_TOT_INS.
  • check -- an error return value for Fortran.
use iso_c_binding
integer(c_int) EventSet, cidx, check
call PAPIF_assign_eventset_component(EventSet, cidx, check)

Fortran arguments for PAPIF_assign_eventset_component:

  • EventSet -- an integer handle for a PAPI event set as created by PAPI_create_eventset.
  • cidx -- an integer value for a component index; by convention the CPU is always 0.
  • check -- an error return value for Fortran.
use iso_c_binding
integer(c_int) EventSet, check
call PAPIF_set_multiplex(EventSet, check)

Fortran arguments for PAPIF_set_multiplex:

  • EventSet -- an integer handle for a PAPI event set as created by PAPI_create_eventset.
  • check -- an error return value for Fortran.

The above functions are used to convert a standard PAPI event set into an event set capable of handling multiplexed events. An event set must first be created with a call to PAPI_create_eventset. This event set is not bound to a component until either an event is added to it with PAPI_add_event(s) or by calling PAPI_assign_eventset_component. PAPI_set_multiplex cannot be called until after the event set is bound to a component. Events can be added to an event set either before or after converting it into a multiplexed set, but the conversion must be done prior to calling PAPI_start and using it as a multiplexed set.

Example

In the following code example, PAPI_add_event and PAPI_set_multiplex are used to convert a standard event set into a multiplexed event set:

#include <papi.h>
#include <stdio.h>
#include <stdlib.h>

void handle_error (int retval)
{
    printf("PAPI error %d: %s\n", retval, PAPI_strerror(retval));
    exit(1);
}

int main()
{
    int retval, i, EventSet = PAPI_NULL;
    unsigned int preset = 0x0;

    /* Initialize the PAPI library */
    retval = PAPI_library_init(PAPI_VER_CURRENT); // initialize PAPI library
    if (retval != PAPI_VER_CURRENT) // checking to make sure everything was correct with initialization
        handle_error(retval);
 
    /* Enable and initialize multiplex support */
    retval = PAPI_multiplex_init(); // enable and initialize multiplex support
    if (retval != PAPI_OK) // checking to make sure it was sucessfully initialized
        handle_error(retval);
 
    /* Create an EventSet */
    retval = PAPI_create_eventset(&EventSet); // crerating a new empty PAPI EventSet
    if (retval != PAPI_OK)
        handle_error(retval);

    /* Add Total Instructions to our EventSet,
    must be done such that we can call PAPI_set_multiplex */
    retval = PAPI_add_event(EventSet, PAPI_TOT_INS);
    if (retval != PAPI_OK)
        handle_error(retval);   

    /* Convert the EventSet to a multiplexed EventSet */
    retval = PAPI_set_multiplex(EventSet);
    if (retval != PAPI_OK)
        handle_error(retval);

    /* Adding events to the now multiplexed EventSet */
    for (i = 0; i < PAPI_MAX_PRESET_EVENTS; i++) {
        preset = PAPI_PRESET_MASK | i;
        if ((PAPI_query_event(preset) == PAPI_OK) && (preset != PAPI_TOT_INS)) {
            retval = PAPI_add_event(EventSet, preset);
            if (retval != PAPI_OK)
                handle_error(retval);
        }   
    }   
 
    /* Start counting events */
    retval = PAPI_start(EventSet);
    if (retval != PAPI_OK) // fails because no event is being actually added within the for loop
        handle_error(retval);

    /* Executes if all low-level PAPI
    function calls returned PAPI_OK */
    printf("\033[0;32mPASSED\n\033[0m");
    exit(0); 
}

Output

PASSED

On success, all PAPI functions return PAPI_OK and the above output is returned. On error, a non-zero error code is returned.

For more code examples, see ctests/multiplex1.c and ctests/multiplex2.c.

Multiplexing Issues

The following are some issues concerning multiplexing that the PAPI user should be aware of:

Hardware multiplexing is not supported by all platforms. On those platforms where it is supported, PAPI takes advantage of it. Otherwise, PAPI implements software multiplexing through the use of a high-resolution interval timer. For more information on which platforms support hardware or software multiplexing, see Appendix H.

Multiplexing unavoidably incurs a small amount of overhead when switching events. In addition, no single event is measured for the full analysis time. These factors can adversely affect the precision of reported counter values. In other words, the more events that are multiplexed, the more likely that the results will be statistically skewed. The amount of time spent in the measured regions should be greater than the multiplexing time slice times the number of events measured in order to get acceptable results.

The default time slice for multiplexing is currently set at 100000 microseconds. Occasionally this setting can cause a resonant situation in the code in which a given pattern repeats at the same frequency that timers are switched out. This can by addressed by changing the time slice setting by calling PAPI_set_opt with the PAPI_DEF_MPX_NS option.

Clone this wiki locally