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. 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:
- Add the ITT API to your application as described in Instrument the Code.
Set up your monitoring application:
- Create a ring buffer structure to access measurements.struct tcc_measurement_buffer* buffer = NULL;
- Calltcc_measurement_get_buffer_size_from_envand reference the measurement name. Be aware that the instrumented real-time application and the monitoring application should have the sameTCC_MEASUREMENTS_BUFFERSenvironment 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.
- Calltcc_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);
- Calltcc_measurement_buffer_check()to see whether a measurement ring buffer exists in shared memory.while (tcc_measurement_buffer_check(measurement_name)) { sleep(0); }
- Calltcc_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.