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

This is a short example of how to use the OTF2 writing interface. This example is available as source code in the file otf2_writer_example.c . See also otf2_openmp_writer_example.c and otf2_pthread_writer_example.c when writing with multiple threads.

First include the OTF2 header.

#include <otf2/otf2.h>

For this example an additional include statement is necessary.

#include <stdlib.h>

Furthermore this example uses a function delivering dummy timestamps. Real world applications will use a timer like clock_gettime.

get_time( void )
{
static uint64_t sequence;
return sequence++;
}

Define a pre and post flush callback. If no memory is left in OTF2's internal memory buffer or the writer handle is closed a memory buffer flushing routine is triggered. The pre flush callback is triggered right before a buffer flush. It needs to return either OTF2_FLUSH to flush the recorded data to a file or OTF2_NO_FLUSH to suppress flushing data to a file. The post flush callback is triggered right after a memory buffer flush. It has to return a current timestamp which is recorded to mark the time spent in a buffer flush. Note that while the pre flush callback is always called, the post flush callback is only called during measurement when flushing an event file. In particular this means that closing the writer handle will only trigger the pre flush callback, and therefore the pre and post flush callbacks must be independent of each other–it is not permissible to start an operation in the pre flush callback and rely on the post flush callback to complete it. The callbacks are passed via a struct to OTF2.

pre_flush( void* userData,
OTF2_FileType fileType,
OTF2_LocationRef location,
void* callerData,
bool final )
{
return OTF2_FLUSH;
}
post_flush( void* userData,
OTF2_FileType fileType,
OTF2_LocationRef location )
{
return get_time();
}
static OTF2_FlushCallbacks flush_callbacks =
{
.otf2_pre_flush = pre_flush,
.otf2_post_flush = post_flush
};

Now everything is prepared to begin with the main program.

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

Create new archive handle.

OTF2_Archive* archive = OTF2_Archive_Open( "ArchivePath",
"ArchiveName",
1024 * 1024 /* event chunk size */,
4 * 1024 * 1024 /* def chunk size */,

Set the previously defined flush callbacks.

OTF2_Archive_SetFlushCallbacks( archive, &flush_callbacks, NULL );

We will operate in a serial context.

Now we can create the event files. Though physical files aren't created yet.

Get a local event writer for location 0.

OTF2_EvtWriter* evt_writer = OTF2_Archive_GetEvtWriter( archive, 0 );

Write an enter and a leave record for region 0 to the local event writer.

OTF2_EvtWriter_Enter( evt_writer,
NULL,
get_time(),
0 /* region */ );
OTF2_EvtWriter_Leave( evt_writer,
NULL,
get_time(),
0 /* region */ );

Now close the event writer, before closing the event files collectively.

OTF2_Archive_CloseEvtWriter( archive, evt_writer );

After we wrote all of the events we close the event files again.

The local definition files are optional, but create them nevertheless to please the reader.

OTF2_DefWriter* def_writer = OTF2_Archive_GetDefWriter( archive, 0 );
OTF2_Archive_CloseDefWriter( archive, def_writer );

Now write the global definitions by getting a writer object for it.

OTF2_GlobalDefWriter* global_def_writer = OTF2_Archive_GetGlobalDefWriter( archive );

We need to define the clock used for this trace and the overall timestamp range.

1 /* 1 tick per second */,
0 /* epoch */,
2 /* length */,

Now we can start writing the referenced definitions, starting with the strings.

OTF2_GlobalDefWriter_WriteString( global_def_writer, 0, "" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 1, "Initial Process" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 2, "Main Thread" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 3, "MyFunction" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 4, "Alternative function name (e.g. mangled one)" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 5, "Computes something" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 6, "MyHost" );
OTF2_GlobalDefWriter_WriteString( global_def_writer, 7, "node" );

Write definition for the code region which was just entered and left to the global definition writer.

0 /* id */,
3 /* region name */,
4 /* alternative name */,
5 /* description */,
0 /* source file */,
0 /* begin lno */,
0 /* end lno */ );

Write the system tree including a definition for the location group to the global definition writer.

0 /* id */,
6 /* name */,
7 /* class */,
0 /* id */,
1 /* name */,
0 /* system tree */,
OTF2_UNDEFINED_LOCATION_GROUP /* creating process */ );

Write a definition for the location to the global definition writer.

0 /* id */,
2 /* name */,
2 /* # events */,
0 /* location group */ );

At the end, close the archive and exit.

OTF2_Archive_Close( archive );
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_writer_example.c -o otf2_writer_example.o

Now you can link your program with:

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