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
Programmers 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(4). 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(4). Values for these variables may be
obtained programatically 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(4).
For a complete description of the pcp_pmda library and the PMDA
development process, refer to the Insight book Performance Co-Pilot
Programmers Guide.