PMDAMAIN(3)
β¨ NAME β¨
hi bestie π«Ά welcome to PMDAMAIN(3), the page about generic PDU processing for a PMDA. it covers:
pmdaMainpmdaGetContextpmdaSetResultCallBackpmdaSetCheckCallBackpmdaSetDoneCallBackpmdaSetEndContextCallBack
β¨ C SYNOPSIS β¨
#include <pcp/pmapi.h>
#include <pcp/pmda.h>
void pmdaMain(pmdaInterface *dispatch);
void pmdaSetCheckCallBack(pmdaInterface *dispatch,
pmdaCheckCallBack callback);
void pmdaSetDoneCallBack(pmdaInterface *dispatch,
pmdaDoneCallBack callback);
void pmdaSetResultCallBack(pmdaInterface *dispatch,
pmdaResultCallBack callback);
void pmdaSetEndContextCallBack(pmdaInterface *dispatch,
pmdaEndContextCallBack callback);
int pmdaGetContext(void);
cc ... -lpcp_pmda -lpcp
β¨ DESCRIPTION β¨
so if you're building a Performance Metric Domain Agent β that's a PMDA(3) β that talks to pmcd(1) using the binary PDU protocols, then pmdaMain is literally your whole main loop, handed to you on a platter. it's a generic implementation of the PDU-driven main loop. iconic behavior, no notes π
dispatch tells it how to process each incoming PDU. it's a vector of function pointers, one per request PDU type, exactly like the DSO interface for a PMDA uses. and it looks like this:
/*
* Interface Definitions for PMDA Methods
*/
typedef struct {
int domain; /* set/return performance metrics domain id here */
struct {
unsigned int pmda_interface: 8; /* PMDA DSO interface version */
unsigned int pmapi_version : 8; /* PMAPI version */
unsigned int flags : 16; /* optional feature flags */
} comm; /* set/return communication and version info */
int status; /* return initialization status here */
union {
struct { /* PMDA_INTERFACE_2 or _3 */
pmdaExt *ext;
int (*profile)(pmProfile *, pmdaExt *);
int (*fetch)(int, pmID *, pmResult **, pmdaExt *);
int (*desc)(pmID, pmDesc *, pmdaExt *);
int (*instance)(pmInDom, int, char *, pmInResult **, pmdaExt *);
int (*text)(int, int, char **, pmdaExt *);
int (*store)(pmResult *, pmdaExt *);
} two, three;
struct { /* PMDA_INTERFACE_4 or _5 */
pmdaExt *ext;
int (*profile)(pmProfile *, pmdaExt *);
int (*fetch)(int, pmID *, pmResult **, pmdaExt *);
int (*desc)(pmID, pmDesc *, pmdaExt *);
int (*instance)(pmInDom, int, char *, pmInResult **, pmdaExt *);
int (*text)(int, int, char **, pmdaExt *);
int (*store)(pmResult *, pmdaExt *);
int (*pmid)(char *, pmID *, pmdaExt *);
int (*name)(pmID, char ***, pmdaExt *);
int (*children)(char *, int, char ***, int **, pmdaExt *);
} four, five;
struct { /* PMDA_INTERFACE_6 */
pmdaExt *ext;
int (*profile)(pmProfile *, pmdaExt *);
int (*fetch)(int, pmID *, pmResult **, pmdaExt *);
int (*desc)(pmID, pmDesc *, pmdaExt *);
int (*instance)(pmInDom, int, char *, pmInResult **, pmdaExt *);
int (*text)(int, int, char **, pmdaExt *);
int (*store)(pmResult *, pmdaExt *);
int (*pmid)(char *, pmID *, pmdaExt *);
int (*name)(pmID, char ***, pmdaExt *);
int (*children)(char *, int, char ***, int **, pmdaExt *);
int (*attribute)(int, int, const char *, int, pmdaExt *);
} six;
} version;
} pmdaInterface;
this struct got extended over time to hold all the multiple interface versions that evolved, so yes it's a little chunky, we love her anyway πΈ
for pmdaMain, both dispatch->domain and dispatch->status are just... ignored. not their moment. the field that actually matters is comm.pmda_interface β that's what decides which interface the PMDA is using:
- set it to
PMDA_INTERFACE_2orPMDA_INTERFACE_3andpmdaMainis forced to use the callbacks in theversion.twoorversion.threestruct. - set it to
PMDA_INTERFACE_4orPMDA_INTERFACE_5andpmdaMainuses the callbacks inversion.fourorversion.five. - set it to
PMDA_INTERFACE_6andpmdaMainuses the callbacks inversion.six.
bestie, any other value = error and pmdaMain just terminates. no vibe check survived, it's over π
ngl the tea here is that using dispatch as the interface between pmcd(1) and the methods of the PMDA means each PMDA can be implemented like it was a DSO all along, with pmdaMain being the convenient little wrapper that converts from the DSO interface to the binary PDU (daemon PMDA) interface. it's giving translator, it's giving bridge π¦
pmdaMain runs as a continuous loop, and it only returns when an end of file shows up on the PDU input file descriptor. that's it. that's the exit condition. periodt.
β¨ CALLBACKS β¨
besides the individual PDU processing callbacks β pmdaProfile(3), pmdaFetch(3), pmdaDesc(3), pmdaInstance(3), pmdaText(3), pmdaStore(3), pmdaPMID(3), pmdaName(3), pmdaChildren(3), and pmdaAttribute(3) β there are three extra ones that can affect or inform all PDU processing inside a PMDA: check, done and end. set them with pmdaSetCheckCallBack, pmdaSetDoneCallBack and pmdaSetEndContextCallBack.
the check callback π
if it's not null, check gets called after each PDU is received β but before it was processed.
if check returns a value less than zero (typically PM_ERR_AGAIN), then the PDU processing gets skipped, and in most cases that function value is sent back to pmcd(1) as an error PDU. this is the move for PMDAs that need some kind of deferred connection or reconnect protocols for their underlying sources of performance metrics β a DBMS, for example.
but heads up: the error indication fromcheckis not passed back topmcd(1)in the cases where no acknowledgment is expected, e.g. for aPDU_PROFILE. π
the done callback π
if it's not null, done gets called after each PDU is sent.
the end callback π
end lets a PMDA keep track of state for individual clients that are asking it to perform actions (aka PDU processing).
using pmdaGetContext, a PMDA can figure out, at any point, an integer identifier that uniquely identifies the client tools at the remote end of PMCD β for local context modes, that identifier is always zero. this is so important for handling event metrics, where each event must be propagated once only to each interested client. it also underlies the mechanism that passes connection information to the PMDA, like the credentials (user and group identifiers) for the client tool. main character energy for real π
the result callback π
one final callback mechanism exists, for handling the pmResult built for a PDU_RESULT in response to a PDU_FETCH request.
by default, pmdaMain will free the pmResult once the result has been sent to pmcd(1). for some PMDAs that's just not the vibe β maybe the pmResult is statically allocated, or it's a hybrid of pinned PDU buffer information and dynamically allocated information. in those cases, use pmdaSetResultCallBack to define an alternative callback from pmdaMain. slay β¨
β¨ DIAGNOSTICS β¨
these messages may be appended to the PMDA's log file:
PMDA interface version interface not supportedβ the interface version is not supported bypmdaMain.Unrecognized pdu typeβ the PMDA received a PDU from pmcd that it does not recognize. this may indicate that the pmcd process is using a more advanced interface thanpmdaMain.
and lowkey a fun one: if the PMAPI(3) debugging control options have the libpmda option set, then every single PDU that is received gets reported in the PMDA's log file. logging girlies stay winning π
β¨ SEE ALSO β¨
pmcd(1), PMAPI(3), PMDA(3), pmdaProfile(3), pmdaFetch(3), pmdaDesc(3), pmdaInstance(3), pmdaText(3), pmdaStore(3), pmdaPMID(3), pmdaName(3), pmdaChildren(3), and pmdaAttribute(3).
okay that's the whole page bestie, go forth and write your PMDA π this was the Performance Co-Pilot PCP PMDAMAIN(3) era, thanks for coming to my ted talk, mwah ππ¦β¨
π¦ where this page comes from
- arch rolling: pcp 7.2.2-2 Β· GPL-2.0-or-later AND LGPL-2.1-or-later AND CC-BY-3.0
- centos-stream 10: pcp-doc 7.1.5-6.el10 Β· GPL-2.0-or-later AND CC-BY-3.0
- fedora 43: pcp-doc 7.0.1-1.fc43 Β· GPL-2.0-or-later AND CC-BY-3.0
- fedora 43: pcp-doc 7.2.1-1.fc43
- fedora 43: pcp-doc 7.2.2-1.fc43
- fedora 43: pcp-doc 7.2.2-2.fc43 Β· GPL-2.0-or-later AND CC-BY-3.0
- fedora 44: pcp-doc 7.1.0-6.fc44 Β· GPL-2.0-or-later AND CC-BY-3.0
- fedora 44: pcp-doc 7.2.1-1.fc44
- fedora 44: pcp-doc 7.2.2-1.fc44
- fedora 44: pcp-doc 7.2.2-2.fc44 Β· GPL-2.0-or-later AND CC-BY-3.0
- ubuntu resolute: libpcp-pmda3-dev 7.1.1-1
- ubuntu stonking: libpcp-pmda3-dev 7.2.1-2build1
- Copyright (c) 2013 Red Hat
- Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms