Developer Guide

  • 2021.1
  • 11/03/2021
  • Public
Contents

Monitor Measurements with an 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. The monitoring application runs on a non-real-time core, allowing more flexibility for storing, writing, sending, or otherwise manipulating the data. The measurement library enables you to create a shared memory 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 ITT APIs and it is linked against the ITT Notify static library (
libittnotify64.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:
Prepare the environment for both applications:
  1. Enable shared memory:
    TCC_USE_SHARED_MEMORY=true
  2. Coordinate your reader and writer, so they agree on the name and size of the measurement buffer. This example uses an environment variable as described in Control Data Collection. Here, “Workload” corresponds to your measurement name and 10 is the size of the measurement history.
    TCC_MEASUREMENTS_BUFFERS=Workload:10
The real-time application writes measurements to the buffer. If the total number of measurements exceeds the defined size, the new measurements will overwrite the old measurements.
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.
If the monitoring application lags far behind the real-time application, and the buffer size is small, you might lose data as the real-time application will not write new data until the reader has read the old data. It will wait and drop new data until the reader reads all the old data, and then it will continue writing.
Set up your real-time application:
  1. Add the ITT APIs 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 writer (instrumented application) and the reader (monitoring application) should have 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);
  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 and the total number of 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)); } }

Product and Performance Information

1

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