PMFETCH(3)

πŸ“¦
version 7.2.2 Β· 5 versions
, in arch rolling, centos-stream 10, fedora 43, fedora 44, ubuntu resolute, ubuntu stonking

πŸ’… PMFETCH(3) πŸ’… β€” Library Functions Manual πŸŽ€

so bestie. this is pmFetch, and it lives in the library functions manual, and it is literally the moment you've been waiting for: it's how you actually get metric values out of PCP. no cap. 🫢


✨ NAME ✨

pmFetch β€” get performance metric values πŸ’–


🌈 C SYNOPSIS 🌈

#include <pcp/pmapi.h>

int pmFetch(int numpmid, pmID *pmidlist, pmResult **result);

cc ... -lpcp

πŸ‘‘ DESCRIPTION πŸ‘‘

okay so. you hand over a whole list of Performance Metric Identifiers (PMIDs) β€” like the ones you built with pmLookupName(3) β€” through pmidlist and numpmid, and it goes and fetches the values for all those performance metrics. group chat, but for metrics. πŸ¦‹

a call to pmFetch happens inside a context: a source of metrics, an instance profile, and a collection time, all of which you already set up earlier with the right context and profile calls, namely some of pmNewContext(3), pmDupContext(3), pmUseContext(3), pmAddProfile(3), pmDelProfile(3) and pmSetMode(3). like, you gotta have the vibe established first, iykyk.

the main result comes back through the result argument as a tree, made of these component data structures:

typedef struct {
      unsigned int vtype : 8;        /* value type (same as pmDesc.type) */
      unsigned int vlen : 24;        /* bytes for vtype/vlen + vbuf */
      char         vbuf[1];          /* one or more values */
} pmValueBlock;

typedef struct {
      int      inst;                 /* instance identifier */
      union {
            pmValueBlock *pval;      /* pointer to value-block */
            int          lval;       /* integer value insitu */
      } value;
} pmValue;

typedef struct {
      pmID      pmid;                /* metric identifier */
      int       numval;              /* number of values or error code */
      int       valfmt;              /* value style, insitu or ptr */
      pmValue   vlist[1];            /* set of instances/values */
} pmValueSet;

/* Result returned by pmFetch() */
typedef struct {
      struct timespec timestamp;     /* time stamped by collector */
      int            numpmid;        /* number of PMIDs */
      pmValueSet     *vset[1];       /* set of value sets */
} pmResult;

to make room for metrics with multiple value instances, the numval field tells you how many values came back for each PMID you asked about. and the valfmt field over in the pmValueSet structure is the little tell for whether this metric's values are stored insitu in the lval field β€” that's a 32-bit integer quantity, so either int, unsigned int, long or unsigned long β€” or whether the values are living in associated pmValueBlock structures instead. πŸ’«

the pmValueBlock structure is always the one used for floating point values (float or double), and it also handles arbitrary sized binary data like string-valued metrics and metrics with aggregated or complex data types. the max length of a pmValueBlock buffer is PM_VAL_VLEN_MAX bytes. if the pmValueBlock format is in play, the vtype field tells you the data type of the value, and it means exactly the same thing as the type field in the pmDesc structure β€” see pmLookupDesc(3). πŸ”₯

heads up though: an insitu value can be a signed or unsigned 32 bit integer, a signed or unsigned 32 bit long value (on 32 bit platforms), and in the special cases described below it can also be a 32 bit floating point value. so if your app needs to know the type of an insitu value β€” which is almost always the case, ngl β€” you have to fetch the descriptor for the metric and interpret the type field, exactly like pmLookupDesc(3) describes in detail. and when the pmResult comes from a PCP1.x pmcd, insitu values may also be 32 bit floating point values (of type PM_TYPE_FLOAT). in all cases it's good practice to use pmLookupDesc(3) to fetch the metric's descriptor and interpret the type field in there. also note that PMAPI(3) will automatically translate from the PCP2.0 format to the PCP1.x format when a PCP1.x client asks a PCP2.0 pmcd for 32 bit floating point values β€” but the reverse translation does not happen, because the PCP2.0 pmcd cannot automatically tell arbitrary 32 bit floating point values apart from 32 bit integers. πŸ’€


if one value (like, the one tied to a particular instance) for a metric you requested is unavailable at the requested time, then there's just no associated pmValue structure in the result. and if there are no available values for a metric at all, then numval will be zero and the associated pmValue[] instance will be empty β€” valfmt is undefined in those circumstances, but pmid will still be correctly set to the PMID of the metric with no values. 🫠

as an extension of this protocol, if the Performance Metrics Collection System (PMCS) is able to provide a reason why no values are available for a particular metric, that reason gets encoded as a standard error code in the corresponding numval. and since the error codes are all negative, values for a requested metric are unavailable if numval is less than, or equal to, zero. a performance metric's value can be unavailable for a bunch of reasons; the following list is illustrative but not exhaustive: of the software for the associated Performance Metric Domain

  • Collection is not currently activated in the software for the associated Performance Metric Domain
  • The associated PMID is not known
  • The current system configuration does not include the associated hardware component and/or the associated software module, e.g. a disk is not installed, or off-line, or Oracle is not installed
  • The metric is one for which an instance profile is required, and none was provided (there are a small number of metrics in this category, typically ones with very large, and/or very dynamic instance domains, and/or expensive metric instantiation methods).
  • If the current context involves fetching metrics from an archive, values may be unavailable in the region around a <mark> record (see pmlogextract(1)) that indicate a temporal discontinuity in the time-series of metric values.

in general, we may not be able to differentiate between the various cases, and if differentiation isn't possible, numval will simply be zero. 🀷


the argument definition and the result specifications have been built so that for each PMID in the requested pmidlist there is exactly one pmValueSet in the result, and on top of that the PMIDs show up in exactly the same sequence in both pmidlist and result. which means the number and order of entries in result is completely deterministic, and that makes your application programming logic after the pmFetch call sooo much simpler. queen behavior, honestly. πŸ‘‘

the result structure that pmFetch returns is dynamically allocated using a combo of malloc(3) calls and specialized allocation strategies, and you should release it once you don't need it anymore by calling pmFreeResult(3) β€” and under no circumstances should free(3) be called directly to release this space. do not do it bestie i am begging πŸ™ˆ

since the common error conditions are encoded right there in the result data structure, we'd expect only cataclysmic events to cause an error value to come back. one example would be if the metrics source context was a remote host, and that host β€” or the PMCS on that host β€” became unreachable. otherwise the value returned by the pmFetch function will be non-negative. πŸ’…

if the current context involves fetching metrics from a Performance Metrics Collector Daemon (PMCD), then the return value may be used to encode out-of-band changes in the state of the PMCD and the associated Performance Metrics Daemon Agents (PMDAs), as a bit-wise or of these values:

  • PMCD_RESTART_AGENT β€” an attempt has been made to restart at least one failed PMDA.
  • PMCD_ADD_AGENT β€” at least one PMDA has been started.
  • PMCD_DROP_AGENT β€” PMCD has noticed the termination of at least one PMDA.
  • PMCD_AGENT_CHANGE β€” a convenience macro for any of the three PMDA changes.
  • PMCD_LABEL_CHANGE β€” PMCD has been informed of changes to global (context) labels, or new metrics have appeared which have associated labels.
  • PMCD_NAMES_CHANGE β€” PMCD has been informed that the namespace has been modified, such that new metrics have appeared or existing metrics have been removed.
  • PMCD_HOSTNAME_CHANGE β€” the hostname on the host where PMCD is running has changed. this may be the result of changes from temporary to permanent hostname after a system reboot or some subsequent explicit change to the system's hostname.

the default is to return zero to indicate no change in state, however the pmResult returned by pmFetch has the same interpretation independent of the return value being zero or greater than zero. ✨


πŸ¦‹ COMPATIBILITY πŸ¦‹

before PCP 7.0, the timestamp field in the pmResult struct was a struct timeval. to support PMAPI transition, the old interface and semantics can be used if applications are recompiled with -DPMAPI_VERSION=2. πŸ•°οΈ

and for a time in PCP 6.x there was a routine with the same semantics as the current pmFetch called pmFetchHighRes, plus a struct with the same definition as the current pmResult struct called pmResultHighRes β€” although both are now deprecated, and compile-time support for pmFetchHighRes (and the historically misnamed alias pmHighResFetch) and pmResultHighRes will be removed in a future release. so don't get attached, bestie. 😭


πŸ’œ SEE ALSO πŸ’œ

pmcd(1), pmAddProfile(3), PMAPI(3), pmDelProfile(3), pmDupContext(3), pmExtractValue(3), pmFetchArchive(3), pmFreeResult(3), pmGetInDom(3), pmLookupDesc(3), pmLookupLabels(3), pmLookupName(3), pmNewContext(3), pmSetMode(3), pmUseContext(3) and pmWhichContext(3).

note that pmFetch is the most primitive method for fetching metric values from the PMCS. see the pmFetchGroup(3) API for a higher level method that insulates the user from the intricacies of looking up metric names and metadata, setting up instance profiles, pmResult traversal, conversions, and scaling. 🌈


πŸ’€ DIAGNOSTICS πŸ’€

ok so bestie, quick reminder from earlier: pmFetch drops its error codes right insitu in the argument result. but if there's like, no result at all β€” say the IPC went sideways using the current PMAPI context, or you hit end of file on an archive β€” then these routines hand you back a negative error code instead, and you go peek at it with pmErrStr(3). 🫢


🚨 PM_ERR_EOL

When you're fetching records from an archive, pmFetch throws this error code at you to say the end of the archive has been passed. (Or the start of the archive has been passed, if the direction of traversal is backwards in time. Time is a flat circle, iykyk. πŸ¦‹)

If the ``mode'' for the current PMAPI context (see pmSetMode(3)) is PM_MODE_INTERP, then the time origin is advanced β€” even when this error code is returned. which is actually iconic behavior because it means:

apps that position the time outside the range defined by the records in the archive, and then commence to pmFetch, will eventually see valid results once the time origin moves inside the temporal span of the archive. manifesting ✨

😀 -EAGAIN

If the current context involves fetching metrics from pmcd, then a return value of -EAGAIN means the caller has created too many contexts. that's it. that's the whole thing. no cap, you're just being greedy with contexts bestie πŸ’€


🌈 ENVIRONMENT 🌈

ok so a lot of the performance metrics exported from PCP agents have the semantics of a counter, meaning they're expected to be monotonically increasing. πŸ“ˆ

but under some circumstances, one value of these metrics may be smaller than the previously fetched value. this can happen when:

  • a counter of finite precision overflows, or
  • the PCP agent has been reset or restarted, or
  • the PCP agent is exporting values from some underlying instrumentation that is subject to some asynchronous discontinuity.

the environment variable PCP_COUNTER_WRAP may be set to indicate that all such cases of a decreasing ``counter'' should be treated as a counter overflow β€” and hence the values are assumed to have wrapped once in the interval between consecutive samples. πŸŽ€

⚠️ heads up: this ``wrapping'' behavior was the default in earlier PCP versions, but by default has been disabled in PCP version 1.3 and later. so if you're out here expecting the old wrap-around vibe and you're on 1.3+, that's on you bestie, set the variable. πŸ™ˆ

and that's the whole page, you made it to the end πŸŽ‰ this one's a Performance Co-Pilot joint, from the PCP collection, filed under PMFETCH(3) β€” go forth and fetch, bestie, you're literally the main character of your own metrics pipeline now πŸ’…πŸ‘‘

πŸ“¦ where this page comes from