geopm::PluginFactory(3) – abstract factory for plugins
Namespaces
The PluginFactory
class template is a member of the namespace geopm
, but
the full name, geopm::PluginFactory<class T>
, has been abbreviated in this
manual. Similarly, the std::
namespace specifier has been omitted from the
interface definitions for the following standard types: std::vector
,
std::string
, std::set
, and std::function
, to enable better rendering of
this manual.
Synopsis
#include <geopm/PluginFactory.hpp>
Link with -lgeopm
(MPI) or -lgeopm
(non-MPI)
void PluginFactory<T>::register_plugin(const string &plugin_name,
function<unique_ptr<T>()> make_plugin,
const map<string, string> &dictionary);
unique_ptr<T> PluginFactory<T>::make_plugin(const string &plugin_name) const;
vector<string> PluginFactory<T>::plugin_names(void) const;
const map<string, string>& PluginFactory<T>::dictionary(const string &plugin_name) const;
Description
GEOPM can be extended though Agent
, IOGroup
, and Comm
plugins.
This man page describes the steps for adding a plugin. Refer to
geopm::Agent(3), and geopm::IOGroup(3) for
more details about these interfaces. Any C++ class that derives from
one of these plugin base classes and is compiled into a shared object
file can be loaded at application launch time through the GEOPM plugin
interface. This allows users and system administrators to extend the
features and behavior of the monitor and control process that GEOPM
executes without recompiling the GEOPM runtime.
There are several steps to implementing and integrating a plugin into
GEOPM. First, the base class interface must be completely implemented
by the new class. In addition to the virtual
methods required by the
interface, there are several recommended static
class methods,
described below, that should also be implemented by the derived class
to aid in registration with the plugin factory. Finally, the plugin
must be registered with the appropriate factory at plugin load time.
This process is discussed in more detail in the following sections.
The factory singletons for Agent
, IOGroup
, and Comm
plugins are
available through their respective single accessor functions:
geopm::agent_factory()
, geopm::iogroup_factory()
, and
geopm::comm_factory()
.
A good starting point for implementing a new Agent
or IOGroup
plugin is to modify the examples found in the Agent tutorial and
the IOGroup tutorial.
This code is located in the GEOPM source under tutorial/agent
and
tutorial/iogroup
respectively.
Terms
Below are some definitions of terms that are used to describe different parts of the GEOPM runtime. Understanding these terms will help to interpret the documentation about how to extend the GEOPM runtime. These are arranged from from highest levels of abstraction down to the lowest levels of abstraction.
- launcher:
Wrapper of system application launch (e.g.
srun
oraprun
) that executes the GEOPM runtime with the application.- report:
Text file containing summary of aggregated stats collected during application run.
- trace:
Time series of signals collected over application run in a pipe separated ASCII table.
- agent:
Implementation used by GEOPM to interpret sampled data and enforce the appropriate controls.
- policy:
Array of floating-point settings for
Agent
-specific control parameters in SI units.- sample:
Array of floating-point values providing
Agent
-specific runtime statistics in SI units.- endpoint:
Interface between resource manager and GEOPM runtime. This feature is still under development and is only available when GEOPM is compiled with the
--enable-beta
flag.- profile:
Interface for annotating compute application; provides
PlatformIO
region signals.- controller:
Thread on each compute node that loads plugins and runs GEOPM algorithm.
- level:
Attribute of an
Agent
describing the number of edges between it and the nearest leafAgent
in the communication tree (a leafAgent
is level zero).- signal:
Named parameter in SI units that can be measured using
PlatformIO
.- control:
Named parameter in SI units that can be set using
PlatformIO
.
Factory Class Methods
register_plugin()
Add a plugin to this factory. The plugin_name parameter will be used to request plugins of the registered type. The make_plugin parameter is a function that returns a new object of the registered type. The dictionary is an optional string-to-string dictionary containing static information about the registered type.
make_plugin()
Creates an object of the registered type. If the type was not previously registered, an exception will be thrown. The plugin_name parameter will be used to look up the constructor function used to create the object. Returns a
unique_ptr
to the created object. The caller owns the created object.plugin_names()
Returns a list of all valid plugin names that have been registered with this factory.
dictionary()
Returns an optional dictionary of static metadata about a registered type. If the type was not registered, an exception is thrown. The plugin_name parameter is used to look up the desired dictionary.
Plugin Search Path And Load Order
The GEOPM_PLUGIN_PATH
is a colon-separated list of directories
that contain plugin shared object files to be loaded by the GEOPM
runtime. Any symlink that resides in a directory specified by this
variable will be ignored. See geopm(7) for details
about GEOPM_PLUGIN_PATH
. Note that an Exception will be thrown by
the register_plugin()
method if an attempt is made to register a
plugin with the same name as a previously registered plugin.
In the case of IOGroup
plugins, the most recently loaded plugin to
register a signal or control name provides the implementation at
runtime, even if an earlier IOGroup
plugin had provided a signal or
control with the same name. The plugins in the GEOPM_PLUGIN_PATH
are loaded in reverse (right to left) order so that plugins earlier in
the search path from left to right are preferred when looking up
signal and control implementations. The default search path
(<PREFIX>/lib/geopm
) will have the lowest priority.
For example, if GEOPM_PLUGIN_PATH
is set using the exports below,
the plugins in $HOME/plugin/iogroup
will be used with the highest
priority to provide signal and control names, followed by the plugins
in $GEOPM_HOME/tutorial/iogroup
. Plugins in the default path will
only be used if no higher priority implementation is found. A more
detailed example of plugin load order can be found in
tutorial/plugin_load
.
export GEOPM_PLUGIN_PATH=$GEOPM_HOME/tutorial/iogroup
export GEOPM_PLUGIN_PATH=$HOME/plugin/iogroup:$GEOPM_PLUGIN_PATH
Warning
It is imperative that any dynamically loaded library that is a dependency of a plugin is available in the environment of the systemd initiated geopmd service. If dependent libraries are not available on the root user’s LD_LIBRARY_PATH, the plugin will fail to load. For this reason, it is recommended that any plugins are compiled with system installed gcc/g++ compilers.
Plugin Load Constructor Function
The shared object file must provide a function that is decorated with
the constructor
compiler directive. The __attribute__((constructor))
enables the registration of plugins when the shared object is loaded
by a call to dlopen(3).
Please see the gcc
documentation for the
constructor attribute.
Plugin Class Static Methods
It is recommended that each class deriving from one of the GEOPM
plugin classes implement two static helper methods called
plugin_name()
and make_plugin()
. These functions can be used to
provide the inputs to PluginFactory::register_plugin()
. Note that
the first argument to register_plugin()
is a string
, i.e. the result
of calling plugin_name()
, whereas the make_plugin()
function itself is
passed as the second argument. The make_plugin()
function should take
no arguments and returns a unique_ptr
to an object of the derived
class. The plugin_name()
function should take no arguments and return a
string
specifying the name of the plugin. The process for registering
IOGroup
and Comm
plugins is identical other than the factory singleton
name and is shown in the example below. In the case of Agent
plugins,
additional metadata is passed in the form of a dictionary as the third
argument to register_plugin()
. This dictionary is used by Agent
class helper methods to look up information about the sample and
policy names required by the Agent
.
EXAMPLE: REGISTER IOGROUP PLUGIN
Please see the IOGroup tutorial for more
information. This code is located in the GEOPM source under tutorial/iogroup
.
// This example shows how to register an IOGroup plugin
#include <geopm/IOGroup.hpp> // geopm::IOGroup,
// geopm::iogroup_factory
#include <geopm/Helper.hpp> // geopm::make_unique
// Header providing class ExampleIOGroup interface
#include "ExampleIOGroup.hpp"
// Called during dlopen() to register plugin
static void __attribute__((constructor))
register_plugin_example_iogroup(void)
{
geopm::PluginFactory<geopm::IOGroup> &iof =
geopm::iogroup_factory();
iof.register_plugin(ExampleIOGroup::plugin_name(),
ExampleIOGroup::make_plugin);
}
// Static method used by the factory to create objects
std::unique_ptr<IOGroup> ExampleIOGroup::make_plugin(void)
{
return geopm::make_unique<ExampleIOGroup>();
}
// Static method providing unique plugin name
std::string ExampleIOGroup::plugin_name(void)
{
return "example";
}
EXAMPLE: REGISTER AGENT PLUGIN
Please see the Agent tutorial for more
information. This code is located in the GEOPM source under tutorial/agent
.
// This example shows how to register an Agent plugin
#include <geopm/Agent.hpp> // geopm::Agent,
// geopm::agent_factory
#include <geopm/Helper.hpp> // geopm::make_unique
// Header providing class ExampleAgent interface
#include "ExampleAgent.hpp"
// Called during dlopen() to register plugin
static void __attribute__((constructor))
register_plugin_example_agent(void)
{
geopm::PluginFactory<geopm::Agent> &af =
geopm::agent_factory();
af.register_plugin(ExampleAgent::plugin_name(),
ExampleAgent::make_plugin,
geopm::Agent::make_dictionary(
ExampleAgent::policy_names(),
ExampleAgent::sample_names()));
}
// Static method used by the factory to create objects
std::unique_ptr<geopm::Agent> ExampleAgent::make_plugin(void)
{
return geopm::make_unique<ExampleAgent>();
}
// Static method providing unique plugin name
std::string ExampleAgent::plugin_name(void)
{
return "example";
}