Wiki

Clone wiki

papi / PAPI-LL


Low Level API

The low-level API (Application Programming Interface) manages hardware events in user-defined groups called Event Sets. It is meant for experienced application programmers and tool developers wanting fine-grained measurement and control of the PAPI interface. Unlike the high-level interface, it allows both PAPI preset and native events. Other features of the low-level API are the ability to obtain information about the executable and the hardware as well as to set options for multiplexing and overflow handling. Some of the benefits of using the low-level API rather than the high-level API are that it increases efficiency and functionality.

It should also be noted that the low-level interface could be used in conjunction with the high-level interface, as long as attention is paid to insure that the PAPI library is initialized prior to the first low-level PAPI call.

The low-level API is only as powerful as the substrate upon which it is built. Thus, some features may not be available on every platform. The converse may also be true, that more advanced features may be available on every platform and defined in the header file. Therefore, the user is encouraged to read the documentation for each platform carefully. There are approximately 50 functions that represent the low-level API. For an example using the low-level interface, see the Low Level Code Example below, or src/ctests/low_level.c in the PAPI source distribution.

Note that most functions are implemented in both C and Fortran, but some are implemented in only one of these two languages. For full details on the calling semantics of these functions, please refer to the PAPI Programmer’s Reference.


Initializing the Low Level API

The PAPI library must be initialized before it can be used. It can be initialized explicitly by calling the following low-level function:

C:

PAPI_library_init(''version'')

Fortran:

PAPIF_library_init(check)

Argument version:

Upon initialization, PAPI checks the argument against the internal value of PAPI_VER_CURRENT when the library was compiled. This guards against portability problems when updating the PAPI shared libraries on your system.

Note that this function must be called before calling any other low-level PAPI function.

On success, this function returns PAPI_VER_CURRENT.

On error, a positive return code other than PAPI_VER_CURRENT indicates a library version mismatch and a negative return code indicates an initialization error.

Beginning with PAPI 3.0, there are a number of options for examining the current version number of PAPI:

PAPI_VERSION produces an integer containing the complete current version including MAJOR, MINOR, and REVISION components. Typically the REVISION component changes with bug fixes or minor enhancements, the MINOR component changes with feature additions or API changes, and the MAJOR component changes with significant API structural changes.

PAPI_VER_CURRENT contains the MAJOR and MINOR components and is useful for determining library compatibility changes.

PAPI_VERSION_MAJOR, PAPI_VERSION_MINOR, PAPI_VERSION_REVISION are macros that extract specified component from the version number.

The following is a code example of using PAPI_library_init to initialize the PAPI library:

#include <papi.h>
#include <stdio.h>
int retval;

main()
{
/* Initialize the PAPI library */
retval = PAPI_library_init(PAPI_VER_CURRENT);

if (retval != PAPI_VER_CURRENT && retval > 0) {
  fprintf(stderr,"PAPI library version mismatch!\n");
  exit(1);
}

if (retval < 0) {
  fprintf(stderr, "Initialization error!\n");
  exit(1);
}

fprintf(stdout, "PAPI Version Number\n");
fprintf(stdout, "MAJOR:    %d\n", PAPI_MAJOR(retval));
fprintf(stdout, "MINOR:    %d\n", PAPI_MINOR(retval));
fprintf(stdout, "REVISION: %d\n", PAPI_REVISION(retval));
}

Output for PAPI Version 5.7.0

PAPI Version Number MAJOR: 5 MINOR: 7 REVISION: 0


Low Level Code Example

The following is a simple code example that applies the same technique as the High Level example, except it uses the Low Level API:

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

#define NUM_FLOPS 10000

main()
{
int retval, EventSet=PAPI_NULL;
long_long values[1];

/* Initialize the PAPI library */
retval = PAPI_library_init(PAPI_VER_CURRENT);
if (retval != PAPI_VER_CURRENT) {
  fprintf(stderr, "PAPI library init error!\n");
  exit(1);
}

/* Create the Event Set */
if (PAPI_create_eventset(&EventSet) != PAPI_OK)
    handle_error(1);

/* Add Total Instructions Executed to our Event Set */
if (PAPI_add_event(EventSet, PAPI_TOT_INS) != PAPI_OK)
    handle_error(1);

/* Start counting events in the Event Set */
if (PAPI_start(EventSet) != PAPI_OK)
    handle_error(1);

/* Defined in tests/do_loops.c in the PAPI source distribution */
do_flops(NUM_FLOPS);

/* Read the counting events in the Event Set */
if (PAPI_read(EventSet, values) != PAPI_OK)
    handle_error(1);

printf("After reading the counters: %lld\n",values[0]);

/* Reset the counting events in the Event Set */
if (PAPI_reset(EventSet) != PAPI_OK)
  handle_error(1);

do_flops(NUM_FLOPS);

/* Add the counters in the Event Set */
if (PAPI_accum(EventSet, values) != PAPI_OK)
   handle_error(1);
printf("After adding the counters: %lld\n",values[0]);

do_flops(NUM_FLOPS);

/* Stop the counting of events in the Event Set */
if (PAPI_stop(EventSet, values) != PAPI_OK)
    handle_error(1);

printf("After stopping the counters: %lld\n",values[0]);
}

Possible Output:

After reading the counters: 440973
After adding the counters: 882256
After stopping the counters: 443913

Notice that in order to get the desired results (the second line approximately twice as large as the first line), PAPI_reset was called to reset the counters, since PAPI_read did not reset the counters.


System Detection Low Level API

The sysdetect component comes with three additional functions that allow users to access system information.

Enumeration of device types present in the system:

PAPI_enum_dev_type(modifier, handle)

Device type attribute query:

PAPI_get_dev_type_attr(handle, attribute, value)

Device attribute query:

PAPI_get_dev_attr(handle, dev_id, attribute, value)

Code Example

#include <papi.h>

int main()
{
    int retval = PAPI_library_init(PAPI_CUR_VER);
    /* check retval for errors */

    /* sysdetect device type opaque handle */
    void *handle;

    /* sysdetect device type id */
    int id;

    /* device type count */
    int count;

    /* sysdetect enum modifier (filter devices by type) */
    int enum_modifier = PAPI_DEV_TYPE_ENUM__CPU | PAPI_DEV_TYPE_ENUM__CUDA;

    /* scan through device types available in the system */
    while (PAPI_OK == PAPI_enum_dev_type(enum_modifier, &handle)) {
        retval = PAPI_get_dev_type_attr(handle, PAPI_DEV_TYPE_ATTR__INT_PAPI_ID, &id);
        /* check retval for errors */

        retval = PAPI_get_dev_type_attr(handle, PAPI_DEV_TYPE_ATTR__INT_COUNT, &count);
        /* check retval for errors */

        if (PAPI_DEV_TYPE_ID__CUDA == id) {
            for (int i = 0; i < count; ++i) {
                unsigned int cc_major, cc_minor;
                retval = PAPI_get_dev_attr(handle, i, PAPI_DEV_ATTR__CUDA_UINT_COMP_CAP_MAJOR, &cc_major);
                /* check retval for errors */
                retval = PAPI_get_dev_attr(handle, i, PAPI_DEV_ATTR__CUDA_UINT_COMP_CAP_MINOR, &cc_minor);
                /* check retval for errors */
            }
        }
    }

    PAPI_shutdown();
    return EXIT_SUCCESS;
}

Updated