Skip to content

Developing new metrics plugins

It is possible to extend Optimizer Runtime by writing plugins for specific hardware or software applications.

The supplied header file metricsPlugin.h can be used to develop a plugin to Optimizer Runtime for sampling metrics. Optimizer Runtime will call this plugin's sample_*() functions:

  1. sample_system() will be called for sampling system-wide events
  2. sample_socket() will be called for sampling socket-wide events. On a system with several physical chips, this function will be called concurrently for every socket. The calling thread will be affined by Optimizer Runtime to a logical cpu on the respective socket.
  3. sample_cpu() will be called for sampling per-logical-cpu events. This function will be called concurrently for each logical cpu. The calling thread will be affined by Optimizer Runtime to the respective logical cpu.

The sample*() functions will then send their sampled metrics to the MetricsPluginData object by using the ::insert() method of that class. The Metric struct, once passed to Optimizer Runtime, should not be deleted as long as the plugin is alive.

Upon initialization, Optimizer Runtime will pass metrics parameters that were defined in the knobs.yaml file by invoking calls to set_metric_parameter().

An example plugin

Below is an example of a plugin:

/*
 * examplePlugin.h
 *
 * This example plugin returns an aggregated counter normalized by time, 
 * and will appear under "example.my_counter" metric name
 *
 */

#include "metricsPlugin.h"

class examplePlugin : public MetricsPlugin {
public:
  examplePlugin();
  ~examplePlugin();
  void sample_system(MetricsPluginData *current_values, int phase) override;
  std::string get_name();
private:
  int m_counter;
  MetricsPlugin::Metric m_metric;
};

examplePlugin::examplePlugin() {
  m_metric.name="my_counter";
  m_metric.aggregated=true;
  m_metric.normalize_by="duration";
  m_counter=0;
}

void examplePlugin::sample_system(MetricsPluginData *current_values, int phase) {
  current_values->insert(m_metric,m_counter++);
}

std::string examplePlugin::get_name() {
  return "example";
}

examplePlugin::~examplePlugin() {
}

extern "C" MetricsPlugin* create_object() {
  return new examplePlugin;
}

extern "C" void destroy_object( MetricsPlugin* object ) {
  delete (examplePlugin *) object;
}

Compiling a plugin library

To compile the example in examplePlugin.cpp:

$ g++ -fpic -shared -o libexample-metrics.so examplePlugin.cpp

Using a custom plugin

This will create a shared object by the name of libexample-metrics.so In order to load it, it needs to be specified in knobs.yaml:

domains:
  common:
    plugins: [/path/to/libexample-metrics.so]
    include_metrics: [example.my_counter]

On startup, if the library was loaded successfully Optimizer Runtime will report:

Metrics plugin /path/to/libexample-metrics.so loaded successfully with name: example

Passing parameters to a plugin

It is possible to configure a custom plugin via knobs.yaml as follows:

domains:
  common:
    metrics:
      example.my_metric:
        key: value

When the example plugin is loaded, Optimizer Runtime will invoke:

`example_plugin->set_metric_parameter("my_metric","key","value");`

Using the "file" plugin

Metrics can be defined using the included file plugin libfile-metrics. Below is an example of a metric that is read from a file:

domains:
  common:
    metrics:
      mymetric:
        kind: file
        type: plaintext
        path: /tmp/metric
        aggregated: true
        normalize_by: duration
    plugins: [libfile-metrics.so]

The metric names should have at least kind and path parameters. kind specifies the kind of an object, while path specifies the path of file that has the metric value. The optional parameter type can be either plaintext or text. The optional parameter aggregated can be either true or false. The optional parameter normalize_by defines how this metric will be normalized. It can either be by duration, performance, or by any other metric. The defaults for the optional parameters are: aggregated="false", normalize_by="" and type = "plaintext".

Using the "shell" plugin

It is also possible to define metrics using shell scripts using the included plugin libshell-metrics. Below is an example of a metric that is read from a file:

domains:
  common:
    metrics:
      mymetric:
          kind: shell
        sample_script: cat /tmp/metric
        aggregated: true
        normalize_by: duration
    plugins: [libshell-metrics.so]

The metric names should have at least kind and sample_script parameters. kind specifies the kind of an object, while sample_script defines script that returns the value of the metric. The optional parameter aggregated can be either true or false. The optional parameter normalize_by defines how this metric will be normalized. It can either be by duration, performance, or by any other metric.