Implementation Considerations

The following considerations should be reviewed prior to working with the System Manager Listener API.

Use of Global Variables

Each application must create exactly one Listener object, which must exist for the lifetime of the program. Therefore, the usual implementation strategy will consist of global variables or static member variables of a class. For example, an application might specify the following global declarations:

Listener *listener = new Listener("sampleApp", "4.0", NULL, false);
Event *operationOne = listener->lookupEvent(RPC, "operation one");
Accumulator *accumOperationOne = operationOne->lookupAccumulator("duration of operation one");

The advantages of this approach include the following:

  1. The lookup operations are performed only once. Thereafter, the Event and Accumulator objects that are returned are used directly, and therefore, execute as efficiently as possible.
  2. The Events and Accumulators may be easily accessed from any part of the code by making calls similar to the following:

    accumOperationOne->recordValue(5);
    Duration anotherDuration(accumOperationOne);
    anotherDuration.start();
    -
    application code execution -
    anotherDuration.stop(true);

Use of Duration Objects

Since Duration objects can be reused (start may be called again after stop has been called), the application may choose to keep these objects in data structures associated with each thread that processes client requests, or the objects may be created on the stack as needed (the cost of instantiating a Duration object is small).

Location of System Manager Listener API Calls

Server application implementations often include a dispatch table, or some similar central location in the code where client requests are handled. Developers are recommended to add the top-level System Manager instrumentation code at a location similar to this within their application structure. Frequently, only a few lines of code will need to be added to enable a basic level of performance monitoring.

Performance Data to Record

The System Manager is not intended to be used as a code profiling library or as a replacement for a general-purpose logging facility. It is intended to be used to monitor the overall health and operation of an application, and to yield a small enough impact on performance that it may be easily deployed in the field. Generally, this requires counting and timing high-level operations in the application, such as the number of times each different RPC call is made to a server, how long it took the server to respond to these calls, and what other resources were required to formulate that response.

When implementing support for performance monitoring, consider whether to record the following:

Examples

The following examples demonstrate some possible implementations for gathering performance data.

Cache Statistics

The following code fragment demonstrates how to define Events and Accumulators to record statistics on the behavior of a cache, such as the hit and miss ratios and the amount of I/O performed by the cache:

Listener listener("sampleApp", "4.0", NULL, NULL);
Event *cache = listener->lookupEvent(USER, "cache");
Accumulator *hits = cache->lookupAccumulator("hits");
Accumulator *reads = cache->lookupAccumulator("reads");
Accumulator *writes = cache->lookupAccumulator("writes");

The following pseudocode demonstrates how to use the recordValue and recordEvent member functions to gather the results of cache activity:

if (dataIsInCache) {
   hits->recordValue(1);
} else {
   if (have to write dirty entries to make room) {
      writes->recordValue(pagesWritten);
   }
   // Read the data into the cache
   . . .
   // Record the cache activity
   reads->recordValue(pagesRead);
}
cache->recordEvent();

Object Store Statistics

The following code fragment demonstrates how to define a Container with subordinate Events and Meters to record performance data for an object store:

Container *store = listener->lookupContainer("storeName");
Event *creations = store->lookupEvent("document creations");
Meter *cacheSize = store->lookupMeter("cache size");
. . .
creations->recordEvent();
cacheSize->setValue(CacheSizeInMB);