Developer Guide

  • 2021.2
  • 06/11/2021
  • Public
Contents

Monitor Measurements from a Monitoring Application

A monitoring application runs concurrently with your real-time application, tracks the measurements, and performs actions based on those measurements.
This workflow is helpful in a later stage of development when you are monitoring your real-time application over a long period, but need to store more measurements than the buffer of your real-time application can hold. Memory is limited, and you don’t want to configure your real-time application to write the data to disk or send the data over the network because doing so adds too much latency. A monitoring application runs on a non-real-time core, allowing more flexibility for storing, writing, sending, or otherwise manipulating the data.
The measurement library supports use of a monitoring application by enabling you to create a shared memory ring buffer. The real-time application writes measurements to the buffer, and the monitoring application reads those measurements. What the monitoring application does with the measurements is up to you. It can be simple, just a few dozen lines in C as demonstrated in Measurement Monitoring Sample.
The monitoring application is also referred to as the reader, and the real-time application is the writer. You can have multiple measurement instances (structures) active concurrently. The only limitation is that you can have only one reader and writer per measurement instance.
The following diagram demonstrates the flow for this scenario:
The real-time application is instrumented with Instrumentation and Tracing Technology API (ITT API) and it is linked against the ITT Notify static library (
libittnotify.a
). At runtime, the static library reads the environment variable
INTEL_LIBITTNOTIFY64
and loads the measurement library collector (
libtcc_collector.so
), a dynamic library. The measurement library collector reads the environment variable
TCC_USE_SHARED_MEMORY
, initializes the structures for data collection in the shared memory, and stores the measurements there. The
libtcc.so
shared library is linked by the measurement library collector to handle internal function calls.
The monitoring application is linked with the
libtcc.so
shared library which provides functions for operating with the shared memory buffer. The monitoring application calls
tcc_measurement_buffer_get()
to read the data from the shared memory buffer while new data is added by the measurement library collector.

Example Workflow

The example contains the following steps:
Set up your real-time application:
  1. Add the ITT API to your application as described in Instrument the Code.
Set up your monitoring application:
  1. Create a ring buffer structure to access measurements.
    struct tcc_measurement_buffer* buffer = NULL;
  2. Call
    tcc_measurement_get_buffer_size_from_env
    and reference the measurement name. Be aware that the instrumented real-time application and the monitoring application should have the same
    TCC_MEASUREMENTS_BUFFERS
    environment variable.
    /*Extract the buffer size from the environment variable.*/ uint64_t buffer_size = tcc_measurement_get_buffer_size_from_env( measurement_name);
    Alternative methods to get the buffer size are acceptable. However, the rest of the steps are mandatory.
  3. Call
    tcc_measurement_buffer_init()
    to get the pointer to the ring buffer where the measurements are located.
    tcc_measurement_buffer_init(buffer_size, measurement_name, &buffer);
  4. Call
    tcc_measurement_buffer_check()
    to see whether a measurement ring buffer exists in shared memory.
    while (tcc_measurement_buffer_check(measurement_name)) { sleep(0); }
  5. Call
    tcc_measurement_buffer_get()
    to read the measurements while the buffer exists. You can then write your own code to perform additional tasks based on the measurements. This example prints the measurements. The example also prints a message when a measurement exceeds the deadline.
    /* Read values while shared memory exist*/ while (tcc_measurement_buffer_check(measurement_name)) { /* Get the value from the array of measurement results. If the returned * value is not zero, print the value.*/ if ((value = tcc_measurement_buffer_get(buffer)) != 0) { printf("%lu\n", value); counter++; } /* If the deadline is defined and the value exceeded, print a message * about it*/ if (deadline != 0 && value > deadline) { printf("Latency exceeding deadline: %lu CPU cycles (%ld %s)\n", value, tcc_measurement_convert_clock_to_time_units(value, time_unit), tcc_measurement_get_string_from_time_unit(time_unit)); } }
Prepare the environment for both applications:
At runtime, use the following environment variables to enable shared memory and set measurement buffer size.
  • Use this environment variable with your real-time application to enable shared memory:
    TCC_USE_SHARED_MEMORY=true
  • Coordinate your real-time application and monitoring application, so they agree on the name and size of the measurement buffer.
    TCC_MEASUREMENTS_BUFFERS=<measurement_name>:<buffer_size>[:deadline][,<measurement_name>:<buffer_size>[:deadline]]
In this example, “Workload” is the measurement name. “10” is the size of the measurement buffer. You must use the same variable with both the real-time application and the monitoring application.
TCC_MEASUREMENTS_BUFFERS=Workload:10 TCC_USE_SHARED_MEMORY=true ./real-time-application TCC_MEASUREMENTS_BUFFERS=Workload:10 ./monitoring-application
When setting the buffer size, consider how fast your monitoring application can read the measurements from the buffer, compared to how fast the real-time application writes new data. In particular, if your monitoring application includes some heavy processing of the data, sends data over the network, or stores data on the hard drive, it can be occupied with such activities for a few iterations of the real-time workload.
When the monitoring application reads an element of data, it frees space for the real-time application to write an element of data. If the monitoring application lags far behind the real-time application, and the buffer size is small, you might lose data because the buffer is full of unread data and the real-time application will drop any data that it cannot write.
For details about the environment variables, see Control Data Collection.

Product and Performance Information

1

Performance varies by use, configuration and other factors. Learn more at www.Intel.com/PerformanceIndex.