summaryrefslogtreecommitdiff
path: root/src/perl/MMV
diff options
context:
space:
mode:
Diffstat (limited to 'src/perl/MMV')
-rw-r--r--src/perl/MMV/Changes12
-rw-r--r--src/perl/MMV/GNUmakefile67
-rw-r--r--src/perl/MMV/MANIFEST9
-rw-r--r--src/perl/MMV/MMV.pm120
-rw-r--r--src/perl/MMV/MMV.xs381
-rw-r--r--src/perl/MMV/Makefile.PL49
-rwxr-xr-xsrc/perl/MMV/server.pl101
-rw-r--r--src/perl/MMV/test.pl25
-rw-r--r--src/perl/MMV/typemap10
9 files changed, 774 insertions, 0 deletions
diff --git a/src/perl/MMV/Changes b/src/perl/MMV/Changes
new file mode 100644
index 0000000..a799519
--- /dev/null
+++ b/src/perl/MMV/Changes
@@ -0,0 +1,12 @@
+Revision history for Perl extension PCP::MMV.
+
+1.00 Mon Aug 24 08:52:36 EST 2009
+ - added stop interface
+ - added stats_set interface
+ - fixed incorrect memory free on init
+ - extend server.pl example to report idle time
+ - fixed use of av_len return codes (off by one)
+
+0.01 Fri Jun 12 16:55:20 EST 2009
+ - original version
+
diff --git a/src/perl/MMV/GNUmakefile b/src/perl/MMV/GNUmakefile
new file mode 100644
index 0000000..1fc485d
--- /dev/null
+++ b/src/perl/MMV/GNUmakefile
@@ -0,0 +1,67 @@
+#!gmake
+#
+# Copyright (c) 2009 Aconex. All Rights Reserved.
+#
+# 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.
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+PERLMOD = MMV.pm
+INTERFACE = MMV.xs typemap
+TESTCODE = test.pl server.pl
+PERLDOCS = Changes MANIFEST
+LSRCFILES = Makefile.PL $(PERLDOCS) $(PERLMOD) $(INTERFACE) $(TESTCODE)
+
+LPKGDIRT = PCP-MMV-* MYMETA.yml MYMETA.json
+LDIRT = Makefile COPYING MMV.bs MMV.c MMV.o pm_to_blib blib \
+ Makefile.old $(LPKGDIRT)
+
+default: dist
+
+MAKEMAKER_OPTIONS = INSTALLDIRS=$(PERL_INSTALLDIRS) INSTALLVENDORMAN3DIR=$(PCP_MAN_DIR)/man3
+INSTALLER_OPTIONS = DESTDIR=$$DIST_ROOT
+
+ifeq ($(TARGET_OS),mingw)
+PERLMAKE = dmake.exe
+else
+PERLMAKE = $(MAKE)
+endif
+
+MMV.o: Makefile MMV.xs
+ $(PERLMAKE) -f Makefile
+
+Makefile: COPYING Makefile.PL
+ $(call PERL_MAKE_MAKEFILE)
+
+COPYING:
+ $(LN_S) $(TOPDIR)/COPYING COPYING
+
+test dist: MMV.o
+ rm -f $(LPKGDIRT)
+ $(PERLMAKE) -f Makefile $@
+
+include $(BUILDRULES)
+
+install: default
+ifneq "$(PACKAGE_DISTRIBUTION)" "debian"
+ $(call PERL_GET_FILELIST,$(TOPDIR)/perl-pcp-mmv.list,MMV)
+ find $$DIST_ROOT -name server.pl -exec chmod 755 '{}' ';'
+endif
+
+install_perl:
+ $(PERLMAKE) -f Makefile pure_install $(INSTALLER_OPTIONS)
+
+default_pcp: default
+
+install_pcp: install
+
diff --git a/src/perl/MMV/MANIFEST b/src/perl/MMV/MANIFEST
new file mode 100644
index 0000000..1551ac8
--- /dev/null
+++ b/src/perl/MMV/MANIFEST
@@ -0,0 +1,9 @@
+Changes
+COPYING
+Makefile.PL
+MANIFEST
+MMV.pm
+MMV.xs
+server.pl
+test.pl
+typemap
diff --git a/src/perl/MMV/MMV.pm b/src/perl/MMV/MMV.pm
new file mode 100644
index 0000000..9f3d7ea
--- /dev/null
+++ b/src/perl/MMV/MMV.pm
@@ -0,0 +1,120 @@
+package PCP::MMV;
+
+use strict;
+use warnings;
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+
+require Exporter;
+require DynaLoader;
+
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw(
+ mmv_stats_init mmv_stats_stop mmv_units
+ mmv_lookup_value_desc
+ mmv_inc_value mmv_set_value mmv_set_string
+ mmv_stats_add mmv_stats_inc mmv_stats_set
+ mmv_stats_add_fallback mmv_stats_inc_fallback
+ mmv_stats_interval_start mmv_stats_interval_end
+ mmv_stats_set_string
+ MMV_FLAG_NOPREFIX MMV_FLAG_PROCESS
+ MMV_INDOM_NULL
+ MMV_TYPE_NOSUPPORT
+ MMV_TYPE_I32 MMV_TYPE_U32
+ MMV_TYPE_I64 MMV_TYPE_U64
+ MMV_TYPE_FLOAT MMV_TYPE_DOUBLE
+ MMV_TYPE_STRING MMV_TYPE_ELAPSED
+ MMV_COUNT_ONE
+ MMV_SEM_COUNTER MMV_SEM_INSTANT MMV_SEM_DISCRETE
+ MMV_SPACE_BYTE MMV_SPACE_KBYTE MMV_SPACE_MBYTE
+ MMV_SPACE_GBYTE MMV_SPACE_TBYTE
+ MMV_TIME_NSEC MMV_TIME_USEC MMV_TIME_MSEC
+ MMV_TIME_SEC MMV_TIME_MIN MMV_TIME_HOUR
+);
+@EXPORT_OK = qw();
+$VERSION = '1.00';
+
+sub MMV_INDOM_NULL { 0xffffffff; }
+
+# flags for pmdammv
+sub MMV_FLAG_NOPREFIX { 0x1; } # metric names not prefixed by file name
+sub MMV_FLAG_PROCESS { 0x2; } # instrumented process must be running
+
+# data type of metric values
+sub MMV_TYPE_NOSUPPORT { 0xffffffff; } # not implemented in this version
+sub MMV_TYPE_I32 { 0; } # 32-bit signed integer
+sub MMV_TYPE_U32 { 1; } # 32-bit unsigned integer
+sub MMV_TYPE_I64 { 2; } # 64-bit signed integer
+sub MMV_TYPE_U64 { 3; } # 64-bit signed integer
+sub MMV_TYPE_FLOAT { 4; } # 32-bit floating point
+sub MMV_TYPE_DOUBLE { 5; } # 64-bit floating point
+sub MMV_TYPE_STRING { 6; } # null-terminated string
+sub MMV_TYPE_ELAPSED { 10; } # 64-bit elapsed time
+
+# units - space scale
+sub MMV_SPACE_BYTE { 0; } # bytes
+sub MMV_SPACE_KBYTE { 1; } # kilobytes
+sub MMV_SPACE_MBYTE { 2; } # megabytes
+sub MMV_SPACE_GBYTE { 3; } # gigabytes
+sub MMV_SPACE_TBYTE { 4; } # terabytes
+
+# units - time scale
+sub MMV_TIME_NSEC { 0; } # nanoseconds
+sub MMV_TIME_USEC { 1; } # microseconds
+sub MMV_TIME_MSEC { 2; } # milliseconds
+sub MMV_TIME_SEC { 3; } # seconds
+sub MMV_TIME_MIN { 4; } # minutes
+sub MMV_TIME_HOUR { 5; } # hours
+
+# units - count scale (for metrics such as count events, syscalls,
+# interrupts, etc - these are simply powers of ten and not enumerated here
+# (e.g. 6 for 10^6, or -3 for 10^-3).
+sub MMV_COUNT_ONE { 0; } # 1
+
+# semantics/interpretation of metric values
+sub MMV_SEM_COUNTER { 1; } # cumulative counter, monotonic increasing
+sub MMV_SEM_INSTANT { 3; } # instantaneous value, continuous domain
+sub MMV_SEM_DISCRETE { 4; } # instantaneous value, discrete domain
+
+
+bootstrap PCP::MMV $VERSION;
+
+1;
+__END__
+
+=head1 NAME
+
+PCP::MMV - Perl module for Memory Mapped Value instrumentation
+
+=head1 SYNOPSIS
+
+ use PCP::MMV;
+
+=head1 DESCRIPTION
+
+The PCP::MMV Perl module contains the language bindings for
+building Perl programs instrumented with the Performance Co-Pilot
+Memory Mapped Value infrastructure - an efficient data transport
+mechanism for making performance data from within a Perl program
+available as PCP metrics using the MMV PMDA.
+
+=head1 SEE ALSO
+
+mmv_stats_init(3), mmv_inc_value(3), mmv_lookup_value_desc(3),
+mmv(4) and pmda(3).
+
+The PCP mailing list pcp@mail.performancecopilot.org can be used for
+questions about this module.
+
+Further details can be found at http://www.performancecopilot.org
+
+=head1 AUTHOR
+
+Nathan Scott, E<lt>nathans@debian.orgE<gt>
+
+Copyright (C) 2009 by Aconex.
+
+This library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License, version 2 (see
+the "COPYING" file in the PCP source tree for further details).
+
+=cut
diff --git a/src/perl/MMV/MMV.xs b/src/perl/MMV/MMV.xs
new file mode 100644
index 0000000..2ee6ff8
--- /dev/null
+++ b/src/perl/MMV/MMV.xs
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2009 Aconex. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#include "pmapi.h"
+#include "mmv_stats.h"
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+static int
+list_to_metric(SV *list, mmv_metric_t *metric)
+{
+ int i, len;
+ SV **entry[8];
+ AV *mlist = (AV *) SvRV(list);
+
+ if (SvTYPE((SV *)mlist) != SVt_PVAV) {
+ warn("metric declaration is not an array reference");
+ return -1;
+ }
+ len = av_len(mlist) + 1;
+ if (len < 6) {
+ warn("too few entries in metric array reference");
+ return -1;
+ }
+ if (len > 8) {
+ warn("too many entries in metric array reference");
+ return -1;
+ }
+ for (i = 0; i < len; i++)
+ entry[i] = av_fetch(mlist, i, 0);
+
+ strncpy(metric->name, SvPV_nolen(*entry[0]), MMV_NAMEMAX);
+ metric->name[MMV_NAMEMAX-1] = '\0';
+ metric->item = SvIV(*entry[1]);
+ metric->type = SvIV(*entry[2]);
+ metric->indom = SvIV(*entry[3]);
+ i = SvIV(*entry[4]);
+ memcpy(&metric->dimension, &i, sizeof(pmUnits));
+ metric->semantics = SvIV(*entry[5]);
+ if (len > 6)
+ metric->shorttext = strdup(SvPV_nolen(*entry[6]));
+ else
+ metric->shorttext = NULL;
+ if (len > 7)
+ metric->helptext = strdup(SvPV_nolen(*entry[7]));
+ else
+ metric->helptext = NULL;
+ return 0;
+}
+
+static int
+list_to_instances(SV *list, mmv_instances_t **insts)
+{
+ mmv_instances_t *instances;
+ int i, len;
+ AV *inlist = (AV *) SvRV(list);
+
+ if (SvTYPE((SV *)inlist) != SVt_PVAV) {
+ warn("instances declaration is not an array reference");
+ return -1;
+ }
+ len = av_len(inlist) + 1;
+ if (len++ % 2) {
+ warn("odd number of entries in instance array reference");
+ return -1;
+ }
+
+ len /= 2;
+ instances = (mmv_instances_t *)calloc(len, sizeof(mmv_instances_t));
+ if (instances == NULL) {
+ warn("insufficient memory for instance array");
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ SV **id = av_fetch(inlist, i*2, 0);
+ SV **name = av_fetch(inlist, i*2+1, 0);
+ instances[i].internal = SvIV(*id);
+ strncpy(instances[i].external, SvPV_nolen(*name), MMV_NAMEMAX);
+ instances[i].external[MMV_NAMEMAX-1] = '\0';
+ }
+ *insts = instances;
+ return len;
+}
+
+static int
+list_to_indom(SV *list, mmv_indom_t *indom)
+{
+ int i, len;
+ SV **entry[4];
+ AV *ilist = (AV *) SvRV(list);
+
+ if (SvTYPE((SV *)ilist) != SVt_PVAV) {
+ warn("indom declaration is not an array reference");
+ return -1;
+ }
+ len = av_len(ilist) + 1;
+ if (len < 2) {
+ warn("too few entries in indom array reference");
+ return -1;
+ }
+ if (len > 4) {
+ warn("too many entries in indom array reference");
+ return -1;
+ }
+ for (i = 0; i < len; i++)
+ entry[i] = av_fetch(ilist, i, 0);
+
+ indom->serial = SvIV(*entry[0]);
+ if ((i = list_to_instances(*entry[1], &indom->instances)) < 0)
+ return -1;
+ indom->count = i;
+ if (len > 2)
+ indom->shorttext = strdup(SvPV_nolen(*entry[2]));
+ else
+ indom->shorttext = NULL;
+ if (len > 3)
+ indom->helptext = strdup(SvPV_nolen(*entry[3]));
+ else
+ indom->helptext = NULL;
+ return 0;
+}
+
+static int
+list_to_metrics(SV *list, mmv_metric_t **metriclist, int *mcount)
+{
+ mmv_metric_t *metrics;
+ int i, len;
+ AV *mlist = (AV *) SvRV(list);
+
+ if (SvTYPE((SV *)mlist) != SVt_PVAV) {
+ warn("metrics list is not an array reference");
+ return -1;
+ }
+ len = av_len(mlist) + 1;
+ metrics = (mmv_metric_t *)calloc(len, sizeof(mmv_metric_t));
+ if (metrics == NULL) {
+ warn("insufficient memory for metrics array");
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ SV **entry = av_fetch(mlist, i, 0);
+ if (list_to_metric(*entry, &metrics[i]) < 0)
+ break;
+ }
+ *metriclist = metrics;
+ *mcount = len;
+ return (i == len);
+}
+
+static int
+list_to_indoms(SV *list, mmv_indom_t **indomlist, int *icount)
+{
+ mmv_indom_t *indoms;
+ int i, len;
+ AV *ilist = (AV *) SvRV(list);
+
+ if (SvTYPE((SV *)ilist) != SVt_PVAV) {
+ warn("indoms list is not an array reference");
+ return -1;
+ }
+ len = av_len(ilist) + 1;
+ indoms = (mmv_indom_t *)calloc(len, sizeof(mmv_indom_t));
+ if (indoms == NULL) {
+ warn("insufficient memory for indoms array");
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ SV **entry = av_fetch(ilist, i, 0);
+ if (list_to_indom(*entry, &indoms[i]) < 0)
+ break;
+ }
+ *indomlist = indoms;
+ *icount = len;
+ return (i == len);
+}
+
+
+MODULE = PCP::MMV PACKAGE = PCP::MMV
+
+void *
+mmv_stats_init(name,cl,fl,metrics,indoms)
+ char * name
+ int cl
+ int fl
+ SV * metrics
+ SV * indoms
+ PREINIT:
+ int i, j;
+ int mcount;
+ int icount;
+ mmv_metric_t * mlist;
+ mmv_indom_t * ilist;
+ CODE:
+ i = list_to_metrics(metrics, &mlist, &mcount);
+ j = list_to_indoms(indoms, &ilist, &icount);
+
+ if (i <= 0 || j <= 0) {
+ warn("mmv_stats_init: bad list conversion: metrics=%d indoms=%d\n", i, j);
+ RETVAL = NULL;
+ }
+ else {
+ RETVAL = mmv_stats_init(name, cl, fl, mlist, mcount, ilist, icount);
+ if (RETVAL == NULL)
+ warn("mmv_stats_init failed: %s\n", osstrerror());
+ }
+
+ for (i = 0; i < icount; i++) {
+ if (ilist[i].shorttext)
+ free(ilist[i].shorttext);
+ if (ilist[i].helptext)
+ free(ilist[i].helptext);
+ free(ilist[i].instances);
+ }
+ if (ilist)
+ free(ilist);
+ for (i = 0; i < mcount; i++) {
+ if (mlist[i].shorttext)
+ free(mlist[i].shorttext);
+ if (mlist[i].helptext)
+ free(mlist[i].helptext);
+ }
+ if (mlist)
+ free(mlist);
+
+ if (!RETVAL)
+ XSRETURN_UNDEF;
+ OUTPUT:
+ RETVAL
+
+void
+mmv_stats_stop(handle,name)
+ void * handle
+ char * name
+ CODE:
+ mmv_stats_stop(handle, name);
+
+int
+mmv_units(dim_space,dim_time,dim_count,scale_space,scale_time,scale_count)
+ unsigned int dim_space
+ unsigned int dim_time
+ unsigned int dim_count
+ unsigned int scale_space
+ unsigned int scale_time
+ unsigned int scale_count
+ PREINIT:
+ pmUnits units;
+ CODE:
+ units.pad = 0;
+ units.dimSpace = dim_space; units.scaleSpace = scale_space;
+ units.dimTime = dim_time; units.scaleTime = scale_time;
+ units.dimCount = dim_count; units.scaleCount = scale_count;
+ RETVAL = *(int *)(&units);
+ OUTPUT:
+ RETVAL
+
+pmAtomValue *
+mmv_lookup_value_desc(handle,metric,instance)
+ void * handle
+ char * metric
+ char * instance
+ CODE:
+ RETVAL = mmv_lookup_value_desc(handle, metric, instance);
+ OUTPUT:
+ RETVAL
+
+void
+mmv_inc_value(handle,atom,value)
+ void * handle
+ pmAtomValue * atom
+ double value
+ CODE:
+ mmv_inc_value(handle, atom, value);
+
+void
+mmv_set_value(handle,atom,value)
+ void * handle
+ pmAtomValue * atom
+ double value
+ CODE:
+ mmv_set_value(handle, atom, value);
+
+void
+mmv_set_string(handle,atom,string)
+ void * handle
+ pmAtomValue * atom
+ SV * string
+ PREINIT:
+ int length;
+ char * data;
+ CODE:
+ data = SvPV_nolen(string);
+ length = strlen(data);
+ mmv_set_string(handle, atom, data, length);
+
+void
+mmv_stats_add(handle,metric,instance,count)
+ void * handle
+ char * metric
+ char * instance
+ double count
+ CODE:
+ mmv_stats_add(handle, metric, instance, count);
+
+void
+mmv_stats_inc(handle,metric,instance)
+ void * handle
+ char * metric
+ char * instance
+ CODE:
+ mmv_stats_inc(handle, metric, instance);
+
+void
+mmv_stats_set(handle,metric,instance, value)
+ void * handle
+ char * metric
+ char * instance
+ double value
+ CODE:
+ mmv_stats_set(handle, metric, instance, value);
+
+void
+mmv_stats_add_fallback(handle,metric,instance,instance2,count)
+ void * handle
+ char * metric
+ char * instance
+ char * instance2
+ double count
+ CODE:
+ mmv_stats_add_fallback(handle, metric, instance, instance2, count);
+
+void
+mmv_stats_inc_fallback(handle,metric,instance,instance2)
+ void * handle
+ char * metric
+ char * instance
+ char * instance2
+ CODE:
+ mmv_stats_inc_fallback(handle, metric, instance, instance2);
+
+void
+mmv_stats_interval_start(handle,value,metric,instance)
+ void * handle
+ pmAtomValue * value
+ char * metric
+ char * instance
+ CODE:
+ mmv_stats_interval_start(handle, value, metric, instance);
+
+void
+mmv_stats_interval_end(handle, value)
+ void * handle
+ pmAtomValue * value
+ CODE:
+ mmv_stats_interval_end(handle, value);
+
+void
+mmv_stats_set_string(handle,metric,instance,string)
+ void * handle
+ char * metric
+ char * instance
+ SV * string
+ PREINIT:
+ int length;
+ char * data;
+ CODE:
+ data = SvPV_nolen(string);
+ length = strlen(data);
+ mmv_stats_set_strlen(handle, metric, instance, data, length);
+
diff --git a/src/perl/MMV/Makefile.PL b/src/perl/MMV/Makefile.PL
new file mode 100644
index 0000000..6a85129
--- /dev/null
+++ b/src/perl/MMV/Makefile.PL
@@ -0,0 +1,49 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+my $ldfrom;
+my $inc;
+my $libs;
+my $lddlflags;
+my $cccdlflags;
+
+if ($ENV{TARGET_OS} eq "mingw") {
+ $ldfrom = "-L$ENV{PCP_TOPDIR}/src/libpcp/src -L$ENV{PCP_TOPDIR}/src/libpcp_mmv/src -L$ENV{PCP_DIR}\\local\\bin -lpcp_mmv -lpcp MMV.o";
+ $inc = "-I$ENV{PCP_TOPDIR}/src/include/pcp -I/usr/include/pcp -I$ENV{PCP_DIR}\\include\\pcp -I$ENV{PCP_DIR}\\c\\include";
+ $libs = ["-L$ENV{PCP_DIR}\\local\\bin", '-lpcp_mmv', '-lpcp'];
+}
+else {
+ $ldfrom = "MMV.o";
+ $inc = "-I$ENV{PCP_TOPDIR}/src/include/pcp -I/usr/include/pcp";
+ $libs = ["-L$ENV{PCP_TOPDIR}/src/libpcp_mmv/src -L$ENV{PCP_TOPDIR}/src/libpcp/src -lpcp_mmv -lpcp"];
+}
+if ($ENV{TARGET_OS} eq "darwin") {
+ # standard ones, minus -arch ppc
+ $lddlflags = "-arch x86_64 -arch i386 -bundle -undefined dynamic_lookup";
+}
+else {
+ $lddlflags = "-shared \$(OPTIMIZE) \$(LDFLAGS)";
+}
+if ($ENV{TARGET_OS} eq "solaris") {
+ # for OpenSolaris Makefile ends up with -KPIC instead of -fPIC otherwise
+ $cccdlflags = "-fPIC"
+}
+
+WriteMakefile(
+ NAME => 'PCP::MMV',
+ AUTHOR => 'Nathan Scott <nathans@debian.org>',
+ VERSION_FROM => 'MMV.pm', # finds $VERSION
+ ABSTRACT_FROM => 'MMV.pm', # retrieve abstract from module
+ C => ['MMV.c'],
+ OPTIMIZE => '-g',
+ XSPROTOARG => '-noprototypes',
+ OBJECT => 'MMV.o',
+ DEFINE => '-DPERLIO_NOT_STDIO=0 -DPCP_VERSION -DPCP_DEBUG',
+ LDFROM => $ldfrom,
+ LDDLFLAGS => $lddlflags,
+ CCCDLFLAGS => $cccdlflags,
+ INC => $inc,
+ LIBS => $libs,
+ CC => $ENV{"CC"},
+ LD => $ENV{"CC"},
+);
diff --git a/src/perl/MMV/server.pl b/src/perl/MMV/server.pl
new file mode 100755
index 0000000..f62f440
--- /dev/null
+++ b/src/perl/MMV/server.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl
+#
+# Example server application that demonstrates use of the
+# Perl PCP MMV module for runtime instrumentation.
+#
+
+use strict;
+use warnings;
+use PCP::MMV;
+use Time::HiRes qw ( usleep );
+
+my @db_instances = ( 0 => "tempdb", 1 => "datadb" );
+
+my $db_indom = 1;
+my @indoms = (
+ [ $db_indom, \@db_instances,
+ 'Database instances',
+ 'An instance domain for each database used by this server.',
+ ],
+);
+
+my @metrics = (
+ [ 'response_time.requests',
+ 1, MMV_TYPE_U64, MMV_INDOM_NULL,
+ mmv_units(0,0,1,0,0,MMV_COUNT_ONE), MMV_SEM_COUNTER,
+ 'Number of server requests processed', ''
+ ],
+ [ 'response_time.total',
+ 2, MMV_TYPE_U64, MMV_INDOM_NULL,
+ mmv_units(0,0,1,0,0,MMV_COUNT_ONE), MMV_SEM_COUNTER,
+ 'Maximum observed response time in milliseconds', ''
+ ],
+ [ 'response_time.maximum',
+ 3, MMV_TYPE_DOUBLE, MMV_INDOM_NULL,
+ mmv_units(0,1,0,0,MMV_TIME_MSEC,0), MMV_SEM_INSTANT,
+ 'Maximum observed response time in milliseconds', ''
+ ],
+ [ 'version',
+ 4, MMV_TYPE_STRING, MMV_INDOM_NULL,
+ mmv_units(0,0,0,0,0,0), MMV_SEM_DISCRETE,
+ 'Version number of the server process', ''
+ ],
+ [ 'database.transactions.count',
+ 5, MMV_TYPE_U64, $db_indom,
+ mmv_units(0,0,1,0,0,MMV_COUNT_ONE), MMV_SEM_COUNTER,
+ 'Number of requests issued to each database', ''
+ ],
+ [ 'database.transactions.time',
+ 6, MMV_TYPE_U64, $db_indom,
+ mmv_units(0,1,0,0,MMV_TIME_MSEC,0), MMV_SEM_COUNTER,
+ 'Total time spent waiting for results from each database', ''
+ ],
+ [ 'idletime',
+ 7, MMV_TYPE_U64, MMV_INDOM_NULL,
+ mmv_units(0,1,0,0,MMV_TIME_USEC,0), MMV_SEM_COUNTER,
+ 'Total time spent asleep, in-between requests', ''
+ ],
+);
+
+my $handle = mmv_stats_init('server', 0, MMV_FLAG_PROCESS, \@metrics, \@indoms);
+die("mmv_stats_init failed\n") unless (defined($handle));
+
+mmv_stats_set_string($handle, 'version', '', '7.4.2-5');
+
+my $maxtime = 0.0; # milliseconds
+
+for (;;) {
+
+ my $idletime = 0.0; # microseconds
+ my $dbtime = 0.0; # milliseconds
+ my $response = 0.0;
+
+
+ # start a request ...
+
+ $dbtime = rand 1000; # milliseconds
+ $response += $dbtime;
+ mmv_stats_inc($handle, 'database.transactions.count', 'tempdb');
+ mmv_stats_add($handle, 'database.transactions.time', 'tempdb', $dbtime);
+
+ # ... more work, involving a second DB request ...
+ $dbtime = rand 1000; # milliseconds
+ $response += $dbtime;
+ mmv_stats_inc($handle, 'database.transactions.count', 'datadb');
+ mmv_stats_add($handle, 'database.transactions.time', 'datadb', $dbtime);
+
+ # ... request completed
+
+
+ $response += rand 42; # milliseconds
+ mmv_stats_inc($handle, 'response_time.requests', '');
+ mmv_stats_add($handle, 'response_time.total', '', $response);
+ if ($response > $maxtime) {
+ $maxtime = $response;
+ mmv_stats_set($handle, 'response_time.maximum', '', $maxtime);
+ }
+
+ $idletime = rand 50000; # microseconds
+ usleep($idletime);
+ mmv_stats_add($handle, 'idletime', '', $idletime);
+}
diff --git a/src/perl/MMV/test.pl b/src/perl/MMV/test.pl
new file mode 100644
index 0000000..15bd1c6
--- /dev/null
+++ b/src/perl/MMV/test.pl
@@ -0,0 +1,25 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+#
+# Copyright (c) 2009 Aconex. All Rights Reserved.
+#
+# 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.
+#
+
+######################### We start with some black magic to print on failure.
+
+BEGIN { $| = 1; print "1..4\n"; }
+END {print "not ok 1\n" unless $loaded;}
+use PCP::MMV;
+$loaded = 1;
+print "ok 1\n";
+
+######################### End of black magic.
diff --git a/src/perl/MMV/typemap b/src/perl/MMV/typemap
new file mode 100644
index 0000000..85f8812
--- /dev/null
+++ b/src/perl/MMV/typemap
@@ -0,0 +1,10 @@
+######################################################################
+# INPUT/OUTPUT maps
+# O_OBJECT -> links an opaque C object to a blessed Perl object.
+#
+TYPEMAP
+pmAtomValue * T_PTROBJ
+mmv_indom_t * T_PTROBJ
+mmv_metric_t * T_PTROBJ
+
+######################################################################