3.1-rc3 (revision d9ca08bb)
Usage in reading mode - a simple example

This is a short example of how to use the OTF2 reading interface. It shows how to define and register callbacks and how to use the reader interface to read all events of a given OTF2 archive. This example is available as source code in the file otf2_reader_example.c .

First include the OTF2 header.

#include <otf2/otf2.h>

For this example some additional include statements are necessary.

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

Define an event callback for entering and leaving a region.

Enter_print( OTF2_LocationRef location,
void* userData,
OTF2_AttributeList* attributes,
OTF2_RegionRef region )
{
printf( "Entering region %u at location %" PRIu64 " at time %" PRIu64 ".\n",
region, location, time );
}
Leave_print( OTF2_LocationRef location,
void* userData,
OTF2_AttributeList* attributes,
OTF2_RegionRef region )
{
printf( "Leaving region %u at location %" PRIu64 " at time %" PRIu64 ".\n",
region, location, time );
}

The global definition file provides all location IDs that are included in the OTF2 trace archive. When reading the global definitions these location IDs must be collected and stored by the user. Probably, the easiest way to do that is to use a C++ container.

struct vector
{
size_t capacity;
size_t size;
uint64_t members[];
};
GlobDefLocation_Register( void* userData,
OTF2_LocationRef location,
OTF2_LocationType locationType,
uint64_t numberOfEvents,
OTF2_LocationGroupRef locationGroup )
{
struct vector* locations = userData;
if ( locations->size == locations->capacity )
{
}
locations->members[ locations->size++ ] = location;
}

Now everything is prepared to begin with the main program.

int
main( int argc,
char** argv )
{

Create a new reader handle. The path to the OTF2 anchor file must be provided as argument.

OTF2_Reader* reader = OTF2_Reader_Open( "ArchivePath/ArchiveName.otf2" );

We will operate in an serial context.

OTF2 provides an API to query the number of locations prior reading the global definitions. We use this to pre-allocate the storage for all locations.

uint64_t number_of_locations;
&number_of_locations );
struct vector* locations = malloc( sizeof( *locations )
+ number_of_locations
* sizeof( *locations->members ) );
locations->capacity = number_of_locations;
locations->size = 0;

Get the global definition reader from the reader handle.

OTF2_GlobalDefReader* global_def_reader = OTF2_Reader_GetGlobalDefReader( reader );

Register the above defined global definition callbacks. All other definition callbacks will be deactivated. And instruct the reader to pass the locations object to each call of the callbacks.

&GlobDefLocation_Register );
global_def_reader,
global_def_callbacks,
locations );
OTF2_GlobalDefReaderCallbacks_Delete( global_def_callbacks );

Read all global definitions. Every time a location definition is read, the previously registered callback is triggered. In definitions_read the number of read definitions is returned.

uint64_t definitions_read = 0;
global_def_reader,
&definitions_read );

After reading all global definitions all location IDs are stored in the vector locations. After that, the locations that are supposed to be read are selected. In this example all.

for ( size_t i = 0; i < locations->size; i++ )
{
OTF2_Reader_SelectLocation( reader, locations->members[ i ] );
}

When the locations are selected the according event and definition files can be opened. Note that the local definition files are optional, thus we need to remember the success of this call.

bool successful_open_def_files =

When the files are opened the event and definition reader handle can be requested. In this example for all. To apply mapping tables stored in the local definitions, the local definitions must be read. Though the existence of these files are optional. The call to OTF2_Reader_GetEvtReader is mandatory, but the result is unused.

for ( size_t i = 0; i < locations->size; i++ )
{
if ( successful_open_def_files )
{
OTF2_DefReader* def_reader =
OTF2_Reader_GetDefReader( reader, locations->members[ i ] );
if ( def_reader )
{
uint64_t def_reads = 0;
def_reader,
&def_reads );
OTF2_Reader_CloseDefReader( reader, def_reader );
}
}
OTF2_EvtReader* evt_reader =
OTF2_Reader_GetEvtReader( reader, locations->members[ i ] );
}

The definition files can now be closed, if it was successfully opened in the first place.

if ( successful_open_def_files )
{
}

Open a new global event reader. This global reader automatically contains all previously opened local event readers.

OTF2_GlobalEvtReader* global_evt_reader = OTF2_Reader_GetGlobalEvtReader( reader );

Register the above defined global event callbacks. All other global event callbacks will be deactivated.

&Enter_print );
&Leave_print );
global_evt_reader,
event_callbacks,
NULL );

Read all events in the OTF2 archive. The events are automatically ordered by the time they occurred in the trace. Every time an enter or leave event is read, the previously registered callbacks are triggered. In events_read the number of read events is returned.

uint64_t events_read = 0;
global_evt_reader,
&events_read );

The global event reader can now be closed and the event files too.

OTF2_Reader_CloseGlobalEvtReader( reader, global_evt_reader );

At the end, close the reader and exit. All opened event and definition readers are closed automatically.

OTF2_Reader_Close( reader );
free( locations );
return EXIT_SUCCESS;
}

To compile your program use a command like the following. Note that we need to activate the C99 standard explicitly for GCC.

$(CC) $(CFLAGS) $(OTF2_CFLAGS) -c otf2_reader_example.c -o otf2_reader_example.o

Now you can link your program with:

$(CC) $(CFLAGS) otf2_reader_example.o $(OTF2_LDFLAGS) $(OTF2_LIBS) -o otf2_reader_example