Arm MAP Metric Plugin Interface
Metric Plugin Interface for MAP
custom1.c

An example metric library using the Arm MAP Metric Plugin API.This implements the functions as defined in Metric Plugin Template and makes calls to the Metric Plugin API. This plugin provides a custom metric showing the number of interrupts handled by the system, as obtained from /proc/interrupts.

It can be compiled using the command:

  gcc -fPIC -I/path/to/arm/metrics/include -shared -o libcustom1.so custom1.c

For the corresponding definition file to enable the libcustom1.so metric library to be used by compatible profilers, see custom1.xml.

/* The following functions are assumed to be async-signal-safe, although not
* required by POSIX:
*
* strchr strstr strtoull
*/
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#define PROC_STAT "/proc/stat"
#define ERROR_NO_PROC_STAT 1000
#define BUFSIZE 256
#define OVERLAP 64
#ifndef min
#define min(x, y) ( ((x) < (y)) ? (x) : (y) )
#endif
static uint64_t previous = 0;
static int have_previous = 0;
int allinea_plugin_initialize(plugin_id_t plugin_id, void *unused)
{
// Check that /proc/interrupts exists.
if (access(PROC_STAT, F_OK) != 0) {
if (errno == ENOENT)
allinea_set_plugin_error_messagef(plugin_id, ERROR_NO_PROC_STAT,
"Not supported (no /proc/interrupts)");
else
"Error accessing %s: %s", PROC_STAT, strerror(errno));
return -1;
}
}
int allinea_plugin_cleanup(plugin_id_t plugin_id, void *unused)
{
}
int sample_interrupts(metric_id_t metric_id, struct timespec *in_out_sample_time, uint64_t *out_value)
{
// Main buffer. Add an extra byte for the '\0' we add below.
char buf[BUFSIZE + 1];
*in_out_sample_time = allinea_get_current_time();
// We must use the allinea_safe variants of open / read / write / close so
// that we are not included in the I/O accounting of the Arm MAP sampler.
const int fd = allinea_safe_open(PROC_STAT, O_RDONLY);
if (fd == -1) {
"Error opening %s: %d", PROC_STAT, strerror(errno));
return -1;
}
for (;;) {
const ssize_t bytes_read = allinea_safe_read_line(fd, buf, BUFSIZE);
if (bytes_read == -1) {
// read failed
"Error opening %s: %d", PROC_STAT, strerror(errno));
break;
}
if (bytes_read == 0) {
// end of file
break;
}
if (strncmp(buf, "intr ", 5)==0) { // Check if this is the interrupts line.
// The format of the line is:
// intr <total> <intr 1 count> <intr 2 count> ...
// Check we have the total by looking for the space after it.
const char *total = buf + /* strlen("intr ") */ 5;
char *space = strchr(total, ' ');
if (space) {
uint64_t current;
// NUL-terminate the total.
*space = '\0';
// total now points to the NUL-terminated total. Convert it to
// an integer.
current = strtoull(total, NULL, 10);
if (have_previous)
*out_value = current - previous;
previous = current;
have_previous = 1;
break;
}
}
}
}