NAME¶
PMDA - introduction to the Performance Metrics Domain Agent support
library
C SYNOPSIS¶
#include <pcp/pmapi.h>
#include <pcp/impl.h>
#include <pcp/pmda.h>
cc ... -lpcp_pmda -lpcp
DESCRIPTION¶
To assist in the development of Performance Metric Domain Agents (
PMDAs)
for the Performance Co-Pilot (PCP), a procedural interface is provided that
extends the Performance Metrics Application Programming Interface (
PMAPI(3)) library. These procedures are designed to enable a programmer
to quickly build a
PMDA which can then be tested and refined. However,
this also implies that a
PMDA has a particular structure which may not
be suitable for all applications.
Once you are familiar with the PCP and
PMDA frameworks, you can quickly
implement a new
PMDA with only a few data structures and functions.
This is covered in far greater detail in the
Performance Co-Pilot
Programmer's Guide.
A
PMDA is responsible for a set of performance metrics, in the sense that
it must respond to requests from
pmcd(1) for information about
performance metrics, instance domains, and instantiated values. The
pmcd(1) process generates requests on behalf of performance tools that
make requests using
PMAPI(3) routines.
This man page contains sections of the
simple PMDA which is located at
$PCP_PMDAS_DIR/simple.
COMMUNICATING WITH PMCD¶
Two approaches may be used for connecting a
PMDA to a
pmcd(1)
process. A Dynamic Shared Object (DSO) can be attached by
pmcd(1) using
dlopen(3) when the
pmcd(1) process is started. A procedural
interface referenced through a shared data structure is used to handle
requests from
pmcd(1) to the
PMDA.
The preferred approach is for a separate process (daemon) to communicate with
pmcd(1) using the Performance Data Units (PDU) Inter-Process
Communication (IPC) protocol.
All
PMDAs are launched and controlled by the
pmcd(1) process on
the local host. The requests from the clients are received by
pmcd(1)
and forwarded to the appropriate
PMDAs. Responses, when required, are
returned through
pmcd(1) to the clients. The requests (PDUs) that may
be sent to a
PMDA from
pmcd(1) are
PDU_FETCH,
PDU_PROFILE,
PDU_INSTANCE_REQ,
PDU_DESC_REQ,
PDU_TEXT_REQ and
PDU_RESULT.
DEFAULT CALLBACKS FOR HANDLING PDUs¶
To allow a consistent framework,
pmdaMain(3) can be used by a daemon
PMDA to handle the communication protocol using the same callbacks as a
DSO
PMDA. The structure
pmdaInterface is used to convey the
common procedural interface and state information that is used by
pmcd(1) and a
PMDA. This state information includes tables
describing the supported metrics and instance domains.
As most of the procedural interface is identical for all
PMDAs, they are
provided as part of this support library (
pmdaProfile(3),
pmdaFetch(3),
pmdaInstance(3),
pmdaDesc(3),
pmdaText(3) and
pmdaStore(3)). However, these routines require
access to the
pmdaInterface state information so it must be correctly
initialized using
pmdaConnect(3),
pmdaDaemon(3),
pmdaOpenLog(3),
pmdaDSO(3),
pmdaGetOpt(3) and
pmdaInit(3).
INSTANCES AND INSTANCE DOMAINS¶
Three structures are declared in
/usr/include/pcp/pmda.h which provide a
framework for declaring the metrics and instances supported by the
PMDA.
Every instance requires a unique integer identifier and a unique name, as
defined by the structure
pmdaInstid:
/*
* Instance description: index and name
*/
typedef struct {
int i_inst; /* internal instance identifier */
char *i_name; /* external instance identifier */
} pmdaInstid;
An instance domain requires its own unique identification (
pmInDom), the
number of instances the domain represents, and a pointer to an array of
instance descriptions. This is defined in the structure
pmdaIndom:
/*
* Instance domain description: unique instance id,
* number of instances in this domain, and the list of
* instances (not null terminated).
*/
typedef struct {
pmInDom it_indom; /* indom, filled in */
int it_numinst; /* number of instances */
pmdaInstid *it_set; /* instance identifiers */
} pmdaIndom;
The
simple PMDA has one instance domain for
simple.
color
with three instances (
red,
green and
blue), and a second
instance domain for
simple.
now with instances which can be
specified at run-time. These instance domains are defined as:
static pmdaInstid _color[] = {
{ 0, "red" }, { 1, "green" }, { 2, "blue" }
};
static pmdaInstid *_timenow = NULL;
static pmdaIndom indomtab[] = {
#define COLOR_INDOM 0
{ COLOR_INDOM, 3, _color },
#define NOW_INDOM 1
{ NOW_INDOM, 0, NULL },
};
The preprocessor macros
COLOR_INDOM and
NOW_INDOM are used in the
metric description table to identify the instance domains of individual
metrics. These correspond to the
serial value in the instance domain
pmInDom structure (the
domain field is set by
pmdaInit(3)
at run-time). The serial value must be unique for each instance domain within
the
PMDA.
The indom table shown above which is usually passed to
pmdaInit(3) does
not need to be created if one wants to write one's own Fetch and Instance
functions. See
pmdaInit(3) for more details.
NAMESPACE¶
Every
PMDA has its own unique
namespace using the format defined
in
pmns(5). In summary, the namespace matches the names of the metrics
to the unique identifier. The
simple PMDA defines five metrics:
simple.
numfetch,
simple.
color,
simple.
time.
user, simple.
time.
sys
and
simple.
now. The namespace for these metrics is defined in
$PCP_PMDAS_DIR/simple/pmns and is installed as:
simple {
numfetch 253:0:0
color 253:0:1
time
now 253:2:4
}
simple.time {
user 253:1:2
sys 253:1:3
}
The domain number of
253 is obtained from
$PCP_VAR_DIR/pmns/stdpmid. New
PMDAs should specify a unique
domain number in this file, and obtain the number during installation. This
allows the domain number to change by modifying only the file
$PCP_VAR_DIR/pmns/stdpmid.
The
simple.time and
simple.now metrics are defined in separate
clusters to the other metrics which allows a
PMDA to support more than
1024 metrics, as well as grouping similar metrics together. Therefore, the
item numbers for a new cluster may be identical to the item numbers in other
clusters. The
simple PMDA continues to increment the item numbers to
permit direct mapping (see
pmdaInit(3)).
The namespace file should be installed and removed with the agent using
pmnsadd(1) and
pmnsdel(1). See the later sections on
INSTALLATION and REMOVAL.
A simple ASCII namespace can be constructed by creating a file similar to
$PCP_PMDAS_DIR/simple/root:
/*
* fake "root" for validating the local PMNS subtree
*/
#include "$PCP_VAR_DIR/pmns/stdpmid"
root { simple }
#include "pmns"
and can be referred to with the
-n option in most PCP tools.
METRIC DESCRIPTIONS¶
Each metric requires a description (
pmDesc), which contains its PMID,
data type specification, instance domain, semantics and units (see
pmLookupDesc(3)). A handle is also provided for application specific
information in the
pmdaMetric structure:
/*
* Metric description: handle for extending description,
* and the description.
*/
typedef struct {
void* m_user; /* for users external use */
pmDesc m_desc; /* metric description */
} pmdaMetric;
The
simple PMDA defines the metrics as:
static pmdaMetric metrictab[] = {
/* numfetch */
{ (void *)0,
{ PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
{ 0,0,0,0,0,0} }, },
/* color */
{ (void *)0,
{ PMDA_PMID(0,1), PM_TYPE_32, COLOR_INDOM, PM_SEM_INSTANT,
{ 0,0,0,0,0,0} }, },
/* time.user */
{ (void*)0,
{ PMDA_PMID(1,2), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER,
{ 0, 1, 0, 0, PM_TIME_SEC, 0 } }, },
/* time.sys */
{ (void*)0,
{ PMDA_PMID(1,3), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER,
{ 0, 1, 0, 0, PM_TIME_SEC, 0 } }, },
/* now */
{ NULL,
{ PMDA_PMID(2,4), PM_TYPE_U32, NOW_INDOM, PM_SEM_INSTANT,
{ 0,0,0,0,0,0 } }, },
};
The macro
PMDA_PMID (defined in
/usr/include/pcp/pmda.h) is used
to specify each metric's
cluster and
unit number in the
__pmID_int structure defined in
/usr/include/pcp/impl.h. As with
instance domains, the
domain field is set by
pmdaInit(3) at
run-time, however, the default domain is assumed to be defined by the
PMDA in the macro
MYDOMAIN.
The metric table shown above which is usually passed to
pmdaInit(3) does
not need to be created if one wants to write one's own Fetch and Descriptor
functions. See
pmdaInit(3) for more details.
DSO PMDA¶
A
PMDA that is run as a DSO is opened by
pmcd(1) with
dlopen(3).
pmcd will call the
PMDA's initialization
function that is specified in
$PCP_PMCDCONF_PATH. This function is
passed a pointer to a
pmdaInterface structure which must be completed.
Any callbacks which are
not the default
PMDA support library
callbacks must be specified in the
pmdaInterface structure.
The
simple PMDA uses its own store and fetch callback.
simple_fetch() calls
pmdaFetch(3) which requires a callback to
be set with
pmdaSetFetchCallBack(3) as can be seen in
$PCP_PMDAS_DIR/simple/simple.c.
The flag
_isDSO is used to determine if the
PMDA is a daemon or a
DSO so that the correct initialization routine,
pmdaDaemon(3) or
pmdaDSO(3), is called.
DAEMON PMDA¶
A
PMDA that is run as a daemon is forked and executed by
pmcd(1).
Therefore, unlike a DSO
PMDA, the starting point for a daemon
PMDA is
main(). The agent should parse the command line
arguments, create a log file and initialize some data structures that
pmcd would initialize for a DSO agent.
The
pmdaInterface structure must be completely defined by the daemon
PMDA. The function
pmdaDaemon(3) can be called at the start of
main() to set most of these fields. Command line parsing can be
simplified by using
pmdaGetOpt(3), which is similar to
getopt(2), but extracts a common set of options into the
pmdaInterface structure.
stderr can be mapped to a log file
using
pmdaOpenLog(3) to simplify debugging and error messages. The
connection to
pmcd can be made with
pmdaConnect(3) and the loop
which handles the incoming PDUs,
pmdaMain(3), should be the last
function called. This can be seen in
$PCP_PMDAS_DIR/simple/simple.c.
The
simple_init() routine is common to an agent that can be run as both a
Daemon and DSO
PMDA.
HELP TEXT¶
Each
PMDA must be able to provide
pmcd with the help text for each
metric. Most
PMDAs use specially created files with indexes to support
efficient retrieval of the help text. Tools are provided with PCP to create
the help text files of appropriate format. See
newhelp(1).
INSTALLATION AND REMOVAL¶
A series of shell procedures are defined in
$PCP_SHARE_DIR/lib/pmdaproc.sh which greatly simplify the installation
and removal of a
PMDA. The
Install scripts for most
PMDAs
should only need to specify the name of the
PMDA in
iam, call
_setup which check licenses and whether the
PMDA has been
previously installed, specify the communication protocols, and finally call
_install. The
Remove scripts are even simpler as the
communication protocols are not required. Further information is contained in
the
$PCP_SHARE_DIR/lib/pmdaproc.sh file.
DIAGNOSTICS¶
Any
PMDA which uses this library can set
PMAPI(3) debug control
variable
pmDebug (with -D on the command line) to
DBG_TRACE_LIBPMDA to enable the display of debugging information which
may be useful during development (see
pmdbg(1)).
The
status field of the
pmdaInterface structure should be zero
after
pmdaDaemon,
pmdaDSO,
pmdaGetOpt,
pmdaConnect
and
pmdaInit are called. A value less than zero indicates that
initialization has failed.
Some error messages that are common to most functions in this library are:
- PMDA interface version interface not supported
- Most of the functions require that the comm.version field of the
pmdaInterface structure be set to PMDA_INTERFACE_2 or later.
PMDA_INTERFACE_2 or PMDA_INTERFACE_3 implies that the
version.two fields are correctly initialized, while
PMDA_INTERFACE_4 implies that the version.four fields are
correctly initialized (see pmdaDaemon(3) and
pmdaDSO(3)).
CAVEAT¶
Failing to complete any of the data structures or calling any of the library
routines out of order may cause unexpected behavior in the
PMDA.
Due to changes to the
PMAPI(3) and
PMDA(3) API in the PCP 2.0
release, as described in the product release notes,
PMDAs built using
PCP 2.0 must specify
PMDA_INTERFACE_2 or later and link with
libpcp_pmda.so.2 and
libpcp.so.2. Pre-existing Daemon PMDAs
specifying
PMDA_PROTOCOL_1 will continue to function using the
backwards compatible
libpcp_pmda.so.1 and
libpcp.so.1 libraries
and may be recompiled using the headers installed in
/usr/include/pcp1.x/ without any modification. These backwards
compatible headers and libraries are contained in the
pcp.sw.compat
subsystem.
FILES¶
- /usr/include/pcp/pmda.h
- Header file for the PMDA support library.
- /usr/lib/libpcp_pmda.so
- Dynamic library containing PMDA support library routines.
- $PCP_PMDAS_DIR/trivial
- The source of the trivial PMDA.
- $PCP_PMDAS_DIR/simple
- The source of the simple PMDA.
- $PCP_PMDAS_DIR/txmon
- The source of the txmon PMDA.
- $PCP_PMCDCONF_PATH
- Configuration file for pmcd(1).
- $PCP_VAR_DIR/pmns
- Location of namespace descriptions for every PMDA.
- $PCP_VAR_DIR/pmns/stdpmid
- The unique domain identifiers for each PMDA.
- $PCP_SHARE_DIR/lib/pmdaproc.sh
- Shell procedures for installing and removing a PMDA.
PCP ENVIRONMENT¶
Environment variables with the prefix
PCP_ are used to parameterize the
file and directory names used by PCP. On each installation, the file
/etc/pcp.conf contains the local values for these variables. The
$PCP_CONF variable may be used to specify an alternative configuration
file, as described in
pcp.conf(5). Values for these variables may be
obtained programmatically using the
pmGetConfig(3) function.
SEE ALSO¶
dbpmda(1),
newhelp(1),
pmcd(1),
pmnsadd(1),
pmnsdel(1),
PMAPI(3),
pmdaConnect(3),
pmdaDaemon(3),
pmdaDesc(3),
pmdaDSO(3),
pmdaFetch(3),
pmdaGetOpt(3),
pmdaInit(3),
pmdaInstance(3),
pmdaMain(3),
pmdaOpenLog(3),
pmdaProfile(3),
pmdaStore(3),
pmdaText(3),
pmLookupDesc(3) and
pmns(5).
For a complete description of the
pcp_pmda library and the PMDA
development process, refer to the Insight book
Performance Co-Pilot
Programmer's Guide.