summaryrefslogtreecommitdiff
path: root/src/python/pcp/mmv.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/pcp/mmv.py')
-rw-r--r--src/python/pcp/mmv.py332
1 files changed, 332 insertions, 0 deletions
diff --git a/src/python/pcp/mmv.py b/src/python/pcp/mmv.py
new file mode 100644
index 0000000..426c2d8
--- /dev/null
+++ b/src/python/pcp/mmv.py
@@ -0,0 +1,332 @@
+# pylint: disable=C0103
+"""Wrapper module for libpcp_mmv - PCP Memory Mapped Values library
+#
+# Copyright (C) 2013 Red Hat.
+#
+# This file is part of the "pcp" module, the python interfaces for the
+# Performance Co-Pilot toolkit.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+# Example use of this module for instrumenting a python application:
+
+ from pcp import mmv, pmapi
+ from cpmapi import PM_COUNT_ONE, PM_TIME_USEC
+
+ instances = [mmv.mmv_instance(0, "zero"), mmv.mmv_instance(1, "hero")]
+ indoms = [mmv.mmv_indom(serial = 1,
+ shorttext = "We can be heroes",
+ helptext = "Set of instances from zero to hero"),
+ indoms[0].set_instances(instances)
+ metrics = [mmv.mmv_metric(name = "counter",
+ item = 1,
+ typeof = mmv.MMV_TYPE_U32,
+ semantics = mmv.MMV_SEM_COUNTER,
+ dimension = pmapi.pmUnits(0,0,1,0,0,PM_COUNT_ONE),
+ shorttext = "Example counter metric",
+ helptext = "Yep, a test counter metric"),
+ mmv.mmv_metric(name = "instant",
+ item = 2,
+ typeof = mmv.MMV_TYPE_I32,
+ semantics = mmv.MMV_SEM_INSTANT,
+ dimension = pmapi.pmUnits(0,0,0,0,0,0),
+ shorttext = "Example instant metric",
+ helptext = "Yep, a test instantaneous metric"),
+ mmv.mmv_metric(name = "indom",
+ item = 3,
+ typeof = mmv.MMV_TYPE_U32,
+ semantics = mmv.MMV_SEM_DISCRETE,
+ dimension = pmapi.pmUnits(0,0,0,0,0,0),
+ indom = 1)]
+
+ values = mmv.MemoryMappedValues("demo")
+ values.add_indoms(indoms)
+ values.add_metrics(metrics)
+
+ values.start()
+ instant = values.lookup_mapping("instant", None)
+ values.set(instant, 41)
+ values.inc(instant)
+ values.stop()
+"""
+
+from pcp.pmapi import pmUnits, pmAtomValue
+from cmmv import MMV_NAMEMAX
+
+import ctypes
+from ctypes import Structure, POINTER
+from ctypes import c_int, c_uint, c_long, c_char, c_char_p, c_double, c_void_p
+
+# Performance Co-Pilot MMV library (C)
+LIBPCP_MMV = ctypes.CDLL(ctypes.util.find_library("pcp_mmv"))
+
+##############################################################################
+#
+# definition of structures used by libpcp, derived from <pcp/pmapi.h>
+#
+# This section defines the data structures for accessing and manuiplating
+# metric information and values. Detailed information about these data
+# structures can be found in the MMV(4) manual page.
+#
+
+class mmv_instance(Structure):
+ """ Maps internal to external instance identifiers, within an
+ instance domain.
+ """
+ _fields_ = [("internal", c_int),
+ ("external", c_char * MMV_NAMEMAX)]
+
+class mmv_indom(Structure):
+ """ Represents an instance domain (for set valued metrics)
+ Instance domains have associated instances - integer/string pairs.
+ Defines complete indom metadata (instances, count, text and so on)
+ """
+ _fields_ = [("serial", c_uint),
+ ("count", c_uint),
+ ("instances", POINTER(mmv_instance)),
+ ("shorttext", c_char_p),
+ ("helptext", c_char_p)]
+
+ def set_instances(self, instances):
+ """ Update the instances and counts fields for this indom """
+ self.count = len(instances)
+ instance_array = (mmv_instance * self.count)()
+ for i in xrange(self.count):
+ instance_array[i].internal = instances[i].internal
+ instance_array[i].external = instances[i].external
+ self.instances = instance_array
+
+class mmv_metric(Structure):
+ """ Represents an individual metric to be exported by pmdammv
+ Defines complete metric metadata (type, semantics, units and so on)
+ """
+ _fields_ = [("name", c_char * MMV_NAMEMAX),
+ ("item", c_int),
+ ("typeof", c_int),
+ ("semantics", c_int),
+ ("dimension", pmUnits),
+ ("indom", c_uint),
+ ("shorttext", c_char_p),
+ ("helptext", c_char_p)]
+
+##
+# PCP Memory Mapped Value Services
+
+LIBPCP_MMV.mmv_stats_init.restype = c_void_p
+LIBPCP_MMV.mmv_stats_init.argtypes = [
+ c_char_p, c_int, c_int,
+ POINTER(mmv_metric), c_int, POINTER(mmv_indom), c_int]
+
+LIBPCP_MMV.mmv_stats_stop.restype = None
+LIBPCP_MMV.mmv_stats_stop.argtypes = [c_char_p, c_void_p]
+
+LIBPCP_MMV.mmv_lookup_value_desc.restype = pmAtomValue
+LIBPCP_MMV.mmv_lookup_value_desc.argtypes = [c_void_p, c_char_p, c_char_p]
+
+LIBPCP_MMV.mmv_inc_value.restype = None
+LIBPCP_MMV.mmv_inc_value.argtypes = [c_void_p, POINTER(pmAtomValue), c_double]
+
+LIBPCP_MMV.mmv_set_value.restype = None
+LIBPCP_MMV.mmv_set_value.argtypes = [c_void_p, POINTER(pmAtomValue), c_double]
+
+LIBPCP_MMV.mmv_set_string.restype = None
+LIBPCP_MMV.mmv_set_string.argtypes = [
+ c_void_p, POINTER(pmAtomValue), c_char_p, c_int]
+
+LIBPCP_MMV.mmv_stats_add.restype = None
+LIBPCP_MMV.mmv_stats_add.argtypes = [c_void_p, c_char_p, c_char_p, c_double]
+
+LIBPCP_MMV.mmv_stats_inc.restype = None
+LIBPCP_MMV.mmv_stats_inc.argtypes = [c_void_p, c_char_p, c_char_p]
+
+LIBPCP_MMV.mmv_stats_set.restype = None
+LIBPCP_MMV.mmv_stats_set.argtypes = [c_void_p, c_char_p, c_char_p, c_double]
+
+LIBPCP_MMV.mmv_stats_add_fallback.restype = None
+LIBPCP_MMV.mmv_stats_add_fallback.argtypes = [
+ c_void_p, c_char_p, c_char_p, c_char_p, c_double]
+
+LIBPCP_MMV.mmv_stats_inc_fallback.restype = None
+LIBPCP_MMV.mmv_stats_inc_fallback.argtypes = [
+ c_void_p, c_char_p, c_char_p, c_char_p]
+
+LIBPCP_MMV.mmv_stats_interval_start.restype = POINTER(pmAtomValue)
+LIBPCP_MMV.mmv_stats_interval_start.argtypes = [
+ c_void_p, POINTER(pmAtomValue), c_char_p, c_char_p]
+
+LIBPCP_MMV.mmv_stats_interval_end.restype = None
+LIBPCP_MMV.mmv_stats_interval_end.argtypes = [c_void_p, POINTER(pmAtomValue)]
+
+LIBPCP_MMV.mmv_stats_set_strlen.restype = None
+LIBPCP_MMV.mmv_stats_set_strlen.argtypes = [
+ c_void_p, c_char_p, c_char_p, c_char_p, c_long]
+
+
+#
+# class MemoryMappedValues
+#
+# This class wraps the MMV (Memory Mapped Values) library functions
+#
+
+class MemoryMappedValues(object):
+ """ Defines a set of PCP Memory Mapped Value (MMV) metrics
+
+ Creates PCP metrics from an instrumented python script
+ via pmdammv (Performance Metrics Domain Agent for MMV)
+ """
+
+ def __init__(self, name, flags = 0, cluster = 42):
+ self._name = name
+ self._cluster = cluster # PMID cluster number (domain is MMV)
+ self._flags = flags # MMV_FLAGS_* flags
+ self._metrics = []
+ self._indoms = []
+ self._handle = None # pointer to the memory mapped area
+
+ def start(self):
+ """ Initialise the underlying library with metrics/instances.
+ On completion of this call, we're all visible to pmdammv.
+ """
+ count_metrics = len(self._metrics)
+ metrics = (mmv_metric * count_metrics)()
+ for i in xrange(count_metrics):
+ metrics[i] = self._metrics[i]
+ count_indoms = len(self._indoms)
+ indoms = (mmv_indom * count_indoms)()
+ for i in xrange(count_indoms):
+ indoms[i] = self._indoms[i]
+ self._handle = LIBPCP_MMV.mmv_stats_init(
+ self._name,
+ self._cluster,
+ self._flags,
+ metrics, count_metrics,
+ indoms, count_indoms)
+
+ def stop(self):
+ """ Shut down the underlying library with metrics/instances.
+ This closes the mmap file preventing any further updates.
+ """
+ if (self._handle != None):
+ LIBPCP_MMV.mmv_stats_stop(self._name, self._handle)
+ self._handle = None
+
+ def restart(self):
+ """ Cleanly stop-if-running and restart MMV export services. """
+ self.stop()
+ self.start()
+
+ def started(self):
+ """ Property flagging an active memory mapping """
+ if (self._handle == None):
+ return 0
+ return 1
+
+ def add_indoms(self, indoms):
+ """ Make a list of instance domains visible to the MMV export """
+ self._indoms = indoms
+ if (self.started()):
+ self.restart()
+
+ def add_indom(self, indom):
+ """ Make an additional instance domain visible to the MMV export """
+ self._indoms.append(indom)
+ self.add_indoms(self._indoms)
+
+ def add_metrics(self, metrics):
+ """ Make a list of metrics visible to the MMV export """
+ self._metrics = metrics
+ if (self.started()):
+ self.restart()
+
+ def add_metric(self, metric):
+ """ Make an additional metric visible to the MMV export """
+ self._metrics.append(metric)
+ self.add_metrics(self._metrics)
+
+
+ def lookup_mapping(self, name, inst):
+ """ Find the memory mapping for a given metric name and instance
+
+ This handle can be used to directly manipulate metric values
+ by other interfaces in this module. This is the *preferred*
+ technique for manipulating MMV values. It is more efficient
+ and the alternative (name/inst lookups) is made available as
+ a convenience only for situations where performance will not
+ be affected by repeated (linear) name/inst lookups.
+ """
+ return LIBPCP_MMV.mmv_lookup_value_desc(self._handle, name, inst)
+
+ def add(self, mapping, value):
+ """ Increment the mapped metric by a given value """
+ LIBPCP_MMV.mmv_inc_value(self._handle, mapping, value)
+
+ def inc(self, mapping):
+ """ Increment the mapped metric by one """
+ LIBPCP_MMV.mmv_inc_value(self._handle, mapping, 1)
+
+ def set(self, mapping, value):
+ """ Set the mapped metric to a given value """
+ LIBPCP_MMV.mmv_set_value(self._handle, mapping, value)
+
+ def set_string(self, mapping, value):
+ """ Set the string mapped metric to a given value """
+ LIBPCP_MMV.mmv_set_string(self._handle, mapping, value, len(value))
+
+ def interval_start(self, mapping):
+ """ Start a timed interval for the mapped metric
+ The opaque handle (mapping) returned is passed to interval_end().
+ """
+ return LIBPCP_MMV.mmv_stats_interval_start(self._handle, mapping, 0, 0)
+
+ def interval_end(self, mapping):
+ """ End a timed interval, the metrics time is increased by interval """
+ return LIBPCP_MMV.mmv_stats_interval_end(self._handle, mapping)
+
+
+ def lookup_add(self, name, inst, value):
+ """ Lookup the named metric[instance] and add a value to it """
+ LIBPCP_MMV.mmv_stats_add(self._handle, name, inst, value)
+
+ def lookup_inc(self, name, inst):
+ """ Lookup the named metric[instance] and add one to it """
+ LIBPCP_MMV.mmv_stats_inc(self._handle, name, inst)
+
+ def lookup_set(self, name, inst, value):
+ """ Lookup the named metric[instance] and set its value """
+ LIBPCP_MMV.mmv_stats_set(self._handle, name, inst, value)
+
+ def lookup_interval_start(self, name, inst):
+ """ Lookup the named metric[instance] and start an interval
+ The opaque handle returned is passed to interval_end().
+ """
+ return LIBPCP_MMV.mmv_stats_interval_start(self._handle,
+ None, name, inst)
+
+ def lookup_set_string(self, name, inst, s):
+ """ Lookup the named metric[instance] and set its string value """
+ LIBPCP_MMV.mmv_stats_set_strlen(self._handle, name, inst, s, len(s))
+
+ def lookup_add_fallback(self, name, inst, fall, value):
+ """ Lookup the named metric[instance] and set its value if found
+ If instance is not found, fallback to using a second instance
+ One example use is: add value to bucketN else use a catch-all
+ bucket such as "other"
+ """
+ LIBPCP_MMV.mmv_stats_add_fallback(self._handle, name, inst, fall, value)
+
+ def lookup_inc_fallback(self, name, inst, fallback):
+ """ Lookup the named metric[instance] and increment its value if found
+ If instance is not found, fallback to using a second instance
+ One sample use is: inc value of BucketA, else inc a catch-all
+ """
+ LIBPCP_MMV.mmv_stats_inc_fallback(self._handle, name, inst, fallback)
+