pcp
[Top] [All Lists]

[PATCH v2] perfevent_pmda: Add extension for perf derived events

To: pcp@xxxxxxxxxxx
Subject: [PATCH v2] perfevent_pmda: Add extension for perf derived events
From: Hemant Kumar <hemant@xxxxxxxxxxxxxxxxxx>
Date: Tue, 2 Feb 2016 09:29:49 +0530
Cc: nathans@xxxxxxxxxx, jpwhite4@xxxxxxxxxxx, Hemant Kumar <hemant@xxxxxxxxxxxxxxxxxx>
Delivered-to: pcp@xxxxxxxxxxx
This patch gives an ability to perfevent agent to monitor derived
events. Derived events are based on the hardware/perf
counters. An user can now just say that a derived event is based on so
and so basic counters. And, perfevent agent will find the value for the
derived event. For e.g., in perfevent.conf file, we can say :
[bandwidth:derived]
snbep_unc_imc0::UNC_M_CAS_COUNT:RD node
snbep_unc_imc0::UNC_M_CAS_COUNT:WR node
snbep_unc_imc1::UNC_M_CAS_COUNT:RD node
snbep_unc_imc1::UNC_M_CAS_COUNT:WR node
snbep_unc_imc2::UNC_M_CAS_COUNT:RD node
snbep_unc_imc2::UNC_M_CAS_COUNT:WR node
snbep_unc_imc3::UNC_M_CAS_COUNT:RD node
snbep_unc_imc3::UNC_M_CAS_COUNT:WR node

And, do a pmval :
 # pmval perfevent.derived.bandwidth.value

metric:    perfevent.derived.bandwidth.value
host:      ....
semantics: cumulative counter (converting to rate)
units:     count (converting to count / sec)
samples:   all

              cpu0                  cpu8
            4.606E+06             1.303E+06
            4.590E+06             1.763E+06

This will give us the accumulated counters value per node.

The patch extends the syntax of perfevent.conf to add the following
syntax :
 [derived_event:derived]
 event_name [cpu option]

Note that, the event names that are mentioned for derived_event must be
active on that machine and also present in the perfevent.conf
file. Also, the cpu option for all the events listed under derived_event
must match or else, the derived_event won't be activated.

So, the required derived perf event configuration is read and then, a
list of the events needed by the derived event is created. The perf
derived events' values are monitored along with the basic perf
events. the derived events don't open any new counters but will take the
values from the existing counters (perf_get()).

Right now, the perf derived events will only accumulate the values
listed for them. Going forward, we can add more capabilities.

Adding scale to the perf events will be needed for certain events and
will be added to the derived events.

Looking forward for your suggestion/comments.

Signed-off-by: Hemant Kumar <hemant@xxxxxxxxxxxxxxxxxx>
---
 src/pmdas/perfevent/Install         |   1 +
 src/pmdas/perfevent/configparser.h  |  11 +-
 src/pmdas/perfevent/configparser.l  | 126 ++++++++++++++++---
 src/pmdas/perfevent/perfevent.conf  |   4 +
 src/pmdas/perfevent/perfinterface.c | 242 +++++++++++++++++++++++++++++++++++-
 src/pmdas/perfevent/perfinterface.h |  23 +++-
 src/pmdas/perfevent/perfmanager.c   |   4 +-
 src/pmdas/perfevent/perfmanager.h   |   2 +-
 src/pmdas/perfevent/pmda.c          | 101 +++++++++++++--
 src/pmdas/perfevent/pmns            |   4 +-
 10 files changed, 481 insertions(+), 37 deletions(-)
 mode change 100644 => 100755 src/pmdas/perfevent/Install

diff --git a/src/pmdas/perfevent/Install b/src/pmdas/perfevent/Install
old mode 100644
new mode 100755
index dd159c2..e0a3cfd
--- a/src/pmdas/perfevent/Install
+++ b/src/pmdas/perfevent/Install
@@ -28,6 +28,7 @@ perl_opt=false
 python_opt=false
 socket_opt=true
 socket_inet_def=2078
+pmns_dupok=true
 
 pmdaSetup
 pmdaInstall
diff --git a/src/pmdas/perfevent/configparser.h 
b/src/pmdas/perfevent/configparser.h
index 43e722d..b9a4e31 100644
--- a/src/pmdas/perfevent/configparser.h
+++ b/src/pmdas/perfevent/configparser.h
@@ -42,11 +42,21 @@ typedef struct pmcconfiguration {
     pmcsetting_t *pmcSettingList;
 } pmcconfiguration_t;
 
+typedef struct pmcderived {
+    char *name;
+    int nsettings;
+    pmcsetting_t *derivedSettingList;
+} pmcderived_t;
+
 typedef struct configuration {
     pmcconfiguration_t *configArr;
     size_t nConfigEntries;
+    pmcderived_t *derivedArr;
+    size_t nDerivedEntries;
 } configuration_t;
 
+int context_derived;        /* A flag to check the current pmc */
+
 /* \brief parse the perf event configuration file
  * This function allocates memory. The returned object should be passed to
  * free_configuration() to clean up the memory.
@@ -58,5 +68,4 @@ configuration_t *parse_configfile(const char *filename);
 /* \brief returns the memory allocated by the parse_configfile() function
  */
 void free_configuration(configuration_t *);
-
 #endif 
diff --git a/src/pmdas/perfevent/configparser.l 
b/src/pmdas/perfevent/configparser.l
index 42b21ad..e8a9935 100644
--- a/src/pmdas/perfevent/configparser.l
+++ b/src/pmdas/perfevent/configparser.l
@@ -20,22 +20,45 @@
 %{
 #include "configparser.h"
 
-static void new_pmctype(configuration_t *conf)
+static int is_derived(char *name)
 {
-    if(NULL == conf)
-    {
-        return;
-    }
+    char *str = NULL;
+
+    str = strchr(name, ':');
+    if (!str)
+         return 0;
+    if (!strcmp(str, ":derived"))
+         return 1;
+    return 0;
+}
+
+static void add_derived(configuration_t *config, char *name)
+{
+    pmcderived_t *entry;
+    char *ptr;
+
+    if (!name)
+         return;
+    ++config->nDerivedEntries;
 
-    ++conf->nConfigEntries;
-    conf->configArr = realloc(conf->configArr, conf->nConfigEntries * sizeof 
*conf->configArr);
+    config->derivedArr = realloc(config->derivedArr, config->nDerivedEntries * 
sizeof *config->derivedArr);
 
-    if(NULL == conf->configArr) 
+    if(NULL == config->derivedArr)
     {
-        conf->nConfigEntries = 0;
+        config->nDerivedEntries = 0;
         return;
     }
-    memset(&conf->configArr[conf->nConfigEntries-1], 0, sizeof 
*conf->configArr);
+
+    ptr = strchr(name, ':');
+    *ptr = '\0';
+    memset(&config->derivedArr[config->nDerivedEntries-1], 0, sizeof 
*config->derivedArr);
+
+    entry = &config->derivedArr[config->nDerivedEntries-1];
+
+    entry->name = strdup(name);
+    entry->nsettings = 0;
+    entry->derivedSettingList = NULL;
+    context_derived = 1;
 }
 
 static void add_pmctype(configuration_t *config, char *name)
@@ -47,16 +70,56 @@ static void add_pmctype(configuration_t *config, char *name)
     {
         return;
     }
-    if(0 == config->nConfigEntries) 
+    if (is_derived(name))
+        return add_derived(config, name);
+
+    ++config->nConfigEntries;
+    config->configArr = realloc(config->configArr, config->nConfigEntries * 
sizeof *config->configArr);
+
+    if(NULL == config->configArr)
     {
+        config->nConfigEntries = 0;
         return;
     }
-    entry = &config->configArr[config->nConfigEntries-1];
 
+    memset(&config->configArr[config->nConfigEntries-1], 0, sizeof 
*config->configArr);
+    entry = &config->configArr[config->nConfigEntries-1];
     newpmctype = malloc(sizeof *newpmctype);
     newpmctype->name = strdup(name);
     newpmctype->next = entry->pmcTypeList;
     entry->pmcTypeList = newpmctype;
+    context_derived = 0;
+}
+
+static void add_pmc_setting_name_derived(configuration_t *config, char *name)
+{
+    pmcderived_t *entry;
+    pmcsetting_t *slist, *newpmcderivedsetting;
+
+    if (0 == config->nDerivedEntries)
+    {
+        return;
+    }
+    entry = &config->derivedArr[config->nDerivedEntries - 1];
+    newpmcderivedsetting = calloc(1, sizeof *newpmcderivedsetting);
+    newpmcderivedsetting->name = strdup(name);
+    newpmcderivedsetting->cpuConfig = CPUCONFIG_EACH_CPU;
+    newpmcderivedsetting->next = NULL;
+
+    slist = entry->derivedSettingList;
+    if (slist == NULL)
+    {
+        entry->derivedSettingList = newpmcderivedsetting;
+    }
+    else
+    {
+        while(slist->next)
+        {
+            slist = slist->next;
+        }
+        slist->next = newpmcderivedsetting;
+    }
+    entry->nsettings++;
 }
 
 static void add_pmcsetting_name(configuration_t *config, char *name)
@@ -72,6 +135,10 @@ static void add_pmcsetting_name(configuration_t *config, 
char *name)
     {
         return;
     }
+
+    if (context_derived)
+         return add_pmc_setting_name_derived(config, name);
+
     entry = &config->configArr[config->nConfigEntries-1];
 
     newpmcsetting = malloc(sizeof *newpmcsetting);
@@ -90,7 +157,19 @@ static void set_pmcsetting_cpuconfig(configuration_t 
*config, int cpuconfig)
         return;
     }
 
-    pmcsetting = config->configArr[config->nConfigEntries-1].pmcSettingList;
+    if (context_derived)
+    {
+        pmcsetting = 
config->derivedArr[config->nDerivedEntries-1].derivedSettingList;
+        while(pmcsetting->next)
+        {
+            pmcsetting = pmcsetting->next;
+        }
+    }
+    else
+    {
+        pmcsetting = 
config->configArr[config->nConfigEntries-1].pmcSettingList;
+    }
+
 
     if( NULL == pmcsetting )
     {
@@ -144,7 +223,7 @@ void free_configuration(configuration_t *config)
 {
     int i;
     pmctype_t *pmcTypeDel;
-    pmcsetting_t *pmcSettingDel;
+    pmcsetting_t *pmcSettingDel, *tmp;
 
     if(NULL == config)
     {
@@ -170,7 +249,22 @@ void free_configuration(configuration_t *config)
             free(pmcSettingDel);
         }
     }
+
+    for(i = 0; i < config->nDerivedEntries; ++i)
+    {
+        tmp = pmcSettingDel = config->derivedArr[i].derivedSettingList;
+       while(tmp != NULL)
+       {
+           tmp = tmp->next;
+           free(pmcSettingDel);
+           pmcSettingDel = tmp;
+       }
+
+       if (config->derivedArr[i].name)
+           free(config->derivedArr[i].name);
+    }
     free(config->configArr);
+    free(config->derivedArr);
     free(config);
 }
 
@@ -190,7 +284,7 @@ void free_configuration(configuration_t *config)
 [ \t\r]                               ; /* ignore whitespace */
 \n                                    BEGIN(INITIAL); /* new-line always 
resets state machine */
 
-^\[                                   { BEGIN(PMCTYPELIST); 
new_pmctype(yyextra); /* a '[' char at beginning of line signals start of a 
list of PMC types */ }
+^\[                                   { BEGIN(PMCTYPELIST); /* a '[' char at 
beginning of line signals start of a list of PMC types */ }
 
 <PMCTYPELIST>{
 \"[^\"]*\"                            { /* strip quotes */ 
yytext[strlen(yytext)-1] = '\0'; add_pmctype(yyextra, &yytext[1] ); /* allow 
any char in quotes except the quote char */  }
@@ -233,6 +327,8 @@ configuration_t *parse_configfile(const char *filename)
     config = malloc(sizeof *config);
     config->configArr = NULL;
     config->nConfigEntries = 0;
+    config->derivedArr = NULL;
+    config->nDerivedEntries = 0;
 
     yylex_init(&scanner);
     yyset_extra(config, scanner);
diff --git a/src/pmdas/perfevent/perfevent.conf 
b/src/pmdas/perfevent/perfevent.conf
index f955d8e..68de4ef 100644
--- a/src/pmdas/perfevent/perfevent.conf
+++ b/src/pmdas/perfevent/perfevent.conf
@@ -11,6 +11,10 @@
 #
 # if the CPU option is absent it defaults to all cpus.
 #
+# For derived events :
+# [event:derived]
+#   EVENT_NAME [CPU OPTION]
+# where the CPU OPTION must match for all the events in a derived event.
 
 [amd64_fam10h_barcelona amd64_fam10h_shanghai amd64_fam10h_istanbul]
 
diff --git a/src/pmdas/perfevent/perfinterface.c 
b/src/pmdas/perfevent/perfinterface.c
index 989c20c..1411d32 100644
--- a/src/pmdas/perfevent/perfinterface.c
+++ b/src/pmdas/perfevent/perfinterface.c
@@ -53,11 +53,24 @@ typedef struct event_t_ {
     int ncpus;
 } event_t;
 
+typedef struct event_list_t_ {
+    event_t *event;
+    struct event_list_t_ *next;
+} event_list_t;
+
+typedef struct derived_event_t_ {
+    char *name;
+    event_list_t *event_list;
+} derived_event_t;
+
 typedef struct perfdata_t_
 {
     int nevents;
     event_t *events;
 
+    int nderivedevents;
+    derived_event_t *derived_events;
+
     /* information about the architecture (number of cpus, numa nodes etc) */
     archinfo_t *archinfo;
 
@@ -134,6 +147,91 @@ static void free_perfdata(perfdata_t *del)
     pfm_terminate();
 }
 
+/*
+ * Search an event from the event list
+ */
+static event_t *search_event(perfdata_t *inst, const char *event_name)
+{
+    int i;
+
+    for (i = 0; i < inst->nevents; i++) {
+       if (!strcmp(event_name, inst->events[i].name)) {
+           return ((inst->events) + i);
+       }
+    }
+
+    return NULL;
+}
+
+/*
+ * Setup a derived event
+ */
+static int perf_setup_derived_event(perfdata_t *inst, pmcderived_t 
*derived_pmc)
+{
+    derived_event_t *curr, *derived_events = inst->derived_events;
+    int nderivedevents = inst->nderivedevents;
+    event_t *event;
+    pmcsetting_t *derived_setting;
+    event_list_t *ptr, *tmp, *event_list;
+    int cpuconfig;
+
+    tmp = NULL;
+    event_list = NULL;
+    if (0 == derived_pmc->nsettings)
+       return -E_PERFEVENT_LOGIC;
+
+    derived_events = realloc(derived_events,
+                            (nderivedevents + 1) * sizeof(*derived_events));
+    if (NULL == derived_events) {
+       free(inst->derived_events);
+       inst->nderivedevents = 0;
+       inst->derived_events = NULL;
+       return -E_PERFEVENT_REALLOC;
+    }
+
+    derived_setting = derived_pmc->derivedSettingList;
+    if (derived_setting)
+       cpuconfig = derived_setting->cpuConfig;
+    while (derived_setting) {
+       if (cpuconfig != derived_setting->cpuConfig) {
+           fprintf(stderr, "Mismatch in cpu configuration\n");
+           return -E_PERFEVENT_LOGIC;
+       }
+       event = search_event(inst, derived_setting->name);
+       if (NULL == event) {
+           fprintf(stderr, "Derived setting %s not found\n", 
derived_setting->name);
+           return -E_PERFEVENT_LOGIC;
+       }
+       derived_setting = derived_setting->next;
+
+       tmp = calloc(1, sizeof(*tmp));
+       if (NULL == tmp) {
+           return -E_PERFEVENT_REALLOC;
+       }
+       tmp->event = event;
+       tmp->next = NULL;
+
+       if (NULL == event_list) {
+           event_list = tmp;
+           ptr = event_list;
+       } else {
+           ptr->next = tmp;
+           ptr = ptr->next;
+       }
+    }
+
+    tmp = event_list;
+
+    curr = derived_events + nderivedevents;
+    curr->name = strdup(derived_pmc->name);
+    curr->event_list = event_list;
+    (inst->nderivedevents)++;
+    inst->derived_events = derived_events;
+
+    return 0;
+}
+
+
 /* Setup an event
  */
 static int perf_setup_event(perfdata_t *inst, const char *eventname, const int 
cpuSetting)
@@ -483,7 +581,116 @@ int perf_counter_enable(perfhandle_t *inst, int enable)
     return n;
 }
 
-int perf_get(perfhandle_t *inst, perf_counter **counters, int *size)
+static perf_counter *get_counter(perf_counter **counters, int size, const char 
*str)
+{
+    perf_counter *pcounter = *counters;
+    int idx, ncounters = size;
+
+    for (idx = 0; idx < ncounters; idx++) {
+       if (!strcmp(pcounter[idx].name, str)) {
+           return (pcounter + idx);
+       }
+    }
+    return NULL;
+}
+
+static void print_derived_counters(perf_derived_counter *pdcounter, int n)
+{
+    int i;
+    perf_counter_list *clist = NULL;
+
+    for (i = 0; i < n; i++)
+    {
+       clist = pdcounter[i].counter_list;
+       while(clist)
+       {
+           clist = clist->next;
+       }
+    }
+}
+
+static int perf_derived_get(perf_derived_counter **derived_counters,
+                           int *derived_size, perfdata_t *pdata,
+                           perf_counter **counters, int *size)
+{
+    int idx, cpuidx;
+
+    perf_derived_counter *pdcounter = *derived_counters;
+    int nderivedcounters = *derived_size;
+
+    if(NULL == pdcounter || nderivedcounters != pdata->nderivedevents)
+    {
+        pdcounter = malloc(pdata->nderivedevents * sizeof *pdcounter);
+       if (NULL == pdcounter) {
+           return -E_PERFEVENT_REALLOC;
+       }
+        memset(pdcounter, 0, pdata->nderivedevents * sizeof *pdcounter);
+        nderivedcounters = pdata->nderivedevents;
+
+       for (idx = 0; idx < pdata->nderivedevents; idx++) {
+           derived_event_t *derived_event = &pdata->derived_events[idx];
+           event_list_t *event_list = derived_event->event_list;
+           perf_counter_list *counter_list, *ptr, *curr;
+           perf_counter *counter;
+
+           counter_list = ptr =curr = NULL;
+           pdcounter[idx].name = derived_event->name;
+
+           while (event_list != NULL) {
+               counter = get_counter(counters, *size, event_list->event->name);
+               if (counter != NULL) {
+                   ptr = calloc(1, sizeof(*ptr));
+                   if (!ptr)
+                       return -E_PERFEVENT_REALLOC;
+                   ptr->counter = counter;
+                   ptr->next = NULL;
+                   if (counter_list == NULL) {
+                       counter_list = ptr;
+                       curr = ptr;
+                   } else {
+                       curr->next = ptr;
+                       curr = curr->next;
+                   }
+               }
+               event_list = event_list->next;
+           }
+           /*
+            * For every counter in a derived_event, we have ninstances and
+            * they should match
+            */
+           pdcounter[idx].counter_list = counter_list;
+           pdcounter[idx].ninstances = 
(pdcounter[idx].counter_list)->counter->ninstances;
+           pdcounter[idx].data = calloc(pdcounter[idx].ninstances, 
sizeof(uint64_t));
+       }
+       *derived_counters = pdcounter;
+       *derived_size = nderivedcounters;
+    }
+
+    if (pdcounter) {
+       print_derived_counters(pdcounter, nderivedcounters);
+       nderivedcounters = *derived_size;
+
+       for (idx = 0; idx < nderivedcounters; idx++) {
+           perf_counter_list *clist;
+           perf_counter *ctr;
+
+           for (cpuidx = 0; cpuidx < pdcounter[idx].ninstances; cpuidx++) {
+               pdcounter[idx].data[cpuidx].value = 0;
+               clist = pdcounter[idx].counter_list;
+               while(clist) {
+                   ctr = clist->counter;
+                   pdcounter[idx].data[cpuidx].value += 
ctr->data[cpuidx].value;
+                   clist = clist->next;
+               }
+           }
+       }
+    }
+
+    return 0;
+}
+
+int perf_get(perfhandle_t *inst, perf_counter **counters, int *size,
+            perf_derived_counter **derived_counters, int *derived_size)
 {
     int cpuidx, idx, events_read;
 
@@ -565,16 +772,20 @@ int perf_get(perfhandle_t *inst, perf_counter **counters, 
int *size)
     *counters = pcounter;
     *size = ncounters;
 
+
+    perf_derived_get(derived_counters, derived_size, pdata, counters, size);
+
+
     return events_read;
 }
 
-
 perfhandle_t *perf_event_create(const char *config_file)
 {
-    int ret;
+    int ret, i;
     perfdata_t *inst = 0;
     configuration_t *perfconfig = 0;
     pmcsetting_t *pmcsetting = 0;
+    pmcderived_t *derivedpmc = 0;
 
     ret = pfm_initialize();
     if (ret != PFM_SUCCESS)
@@ -614,6 +825,15 @@ perfhandle_t *perf_event_create(const char *config_file)
         pmcsetting = pmcsetting->next;
     }
 
+    /* Setup the derived events */
+    if (inst && perfconfig && perfconfig->nDerivedEntries)
+    {
+       for (i = 0; i < perfconfig->nDerivedEntries; i++) {
+           derivedpmc = &(perfconfig->derivedArr[i]);
+           perf_setup_derived_event(inst, derivedpmc);
+       }
+    }
+
     free_configuration(perfconfig);
 
 out:
@@ -628,7 +848,7 @@ out:
     return (perfhandle_t *)inst;
 }
 
-void perf_counter_destroy(perf_counter *data, int size)
+void perf_counter_destroy(perf_counter *data, int size, perf_derived_counter 
*derived_counters, int derived_size)
 {
     if(NULL == data)
     {
@@ -641,6 +861,20 @@ void perf_counter_destroy(perf_counter *data, int size)
         free(data[i].data);
     }
 
+    for (i = 0; i < derived_size; ++i)
+       {
+           perf_counter_list *tmp, *clist = NULL;
+
+           free(derived_counters[i].name);
+           free(derived_counters[i].data);
+           tmp = clist = derived_counters[i].counter_list;
+           while (clist) {
+               clist = clist->next;
+               free(tmp);
+               tmp = clist;
+           }
+       }
+
     free(data);
 }
 
diff --git a/src/pmdas/perfevent/perfinterface.h 
b/src/pmdas/perfevent/perfinterface.h
index 444c972..1fc6223 100644
--- a/src/pmdas/perfevent/perfinterface.h
+++ b/src/pmdas/perfevent/perfinterface.h
@@ -33,11 +33,30 @@ typedef struct perf_counter_t_
     int ninstances;
 } perf_counter;
 
+typedef struct perf_derived_data_t_
+{
+    uint64_t value;
+} perf_derived_data;
+
+typedef struct perf_counter_list_t_
+{
+    perf_counter *counter;
+    struct perf_counter_list_t_ *next;
+} perf_counter_list;
+
+typedef struct perf_derived_counter_t_
+{
+    char *name;
+    perf_derived_data *data;
+    int ninstances;
+    perf_counter_list *counter_list;
+} perf_derived_counter;
+
 typedef intptr_t perfhandle_t;
 
 perfhandle_t *perf_event_create(const char *configfile);
 
-void perf_counter_destroy(perf_counter *data, int size);
+void perf_counter_destroy(perf_counter *data, int size, perf_derived_counter 
*derived_counter, int derived_size);
 
 void perf_event_destroy(perfhandle_t *inst);
 
@@ -45,7 +64,7 @@ void perf_event_destroy(perfhandle_t *inst);
 #define PERF_COUNTER_DISABLE 1
 int perf_counter_enable(perfhandle_t *inst, int enable);
 
-int perf_get(perfhandle_t *inst, perf_counter **data, int *size);
+int perf_get(perfhandle_t *inst, perf_counter **data, int *size, 
perf_derived_counter **derived_counter, int *derived_size);
 
 #define E_PERFEVENT_LOGIC 1
 #define E_PERFEVENT_REALLOC 2
diff --git a/src/pmdas/perfevent/perfmanager.c 
b/src/pmdas/perfevent/perfmanager.c
index 14d7dee..c2a51a2 100644
--- a/src/pmdas/perfevent/perfmanager.c
+++ b/src/pmdas/perfevent/perfmanager.c
@@ -126,7 +126,7 @@ static void monitor_destroy(monitor_t *del)
     free(del);
 }
 
-int perf_get_r(perfmanagerhandle_t *inst, perf_counter **data, int *size)
+int perf_get_r(perfmanagerhandle_t *inst, perf_counter **data, int *size, 
perf_derived_counter **derived_counter, int *derived_size)
 {
     monitor_t *m = ((manager_t *)inst)->monitor;
     int res = 0;
@@ -137,7 +137,7 @@ int perf_get_r(perfmanagerhandle_t *inst, perf_counter 
**data, int *size)
      * first call regardless of the enable/disable state */
     if(m->counter_state == PERF_COUNTER_ENABLE || m->first_time) 
     {
-        res = perf_get(m->perf, data, size);
+        res = perf_get(m->perf, data, size, derived_counter, derived_size);
         m->first_time = 0;
 
         if(m->has_been_disabled)
diff --git a/src/pmdas/perfevent/perfmanager.h 
b/src/pmdas/perfevent/perfmanager.h
index ed7918d..a40ed79 100644
--- a/src/pmdas/perfevent/perfmanager.h
+++ b/src/pmdas/perfevent/perfmanager.h
@@ -26,7 +26,7 @@ perfmanagerhandle_t *manager_init(const char *configfilename);
 
 void manager_destroy(perfmanagerhandle_t *mgr);
 
-int perf_get_r(perfmanagerhandle_t *inst, perf_counter **data, int *size);
+int perf_get_r(perfmanagerhandle_t *inst, perf_counter **data, int *size, 
perf_derived_counter **derived_counter, int *derived_size);
 
 int perf_enabled(perfmanagerhandle_t *inst);
 
diff --git a/src/pmdas/perfevent/pmda.c b/src/pmdas/perfevent/pmda.c
index 650914b..a8ec5ae 100644
--- a/src/pmdas/perfevent/pmda.c
+++ b/src/pmdas/perfevent/pmda.c
@@ -57,6 +57,8 @@
 static perfmanagerhandle_t *perfif;
 static perf_counter *hwcounters;
 static int nhwcounters;
+static perf_derived_counter *derived_counters;
+static int nderivedcounters;
 static int activecounters;
 
 /*
@@ -79,6 +81,7 @@ static __pmnsTree *pmns;
 typedef struct dynamic_metric_info
 {
     perf_counter *hwcounter;
+    perf_derived_counter *derived_counter;
     int                pmid_index;
     const char *help_text;
 } dynamic_metric_info_t;
@@ -118,11 +121,21 @@ static pmdaMetric default_metric_settings[] =
     },
 };
 
+static pmdaMetric derived_metric_settings[] =
+    {
+       /* perfevent.derived.{DERIVEDCOUNTER} */
+       {   NULL, /* m_user */ { 0 /*pmid */, PM_TYPE_DOUBLE, 0 /* instance 
domain */,
+                                PM_SEM_COUNTER, 
PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)
+           },
+       },
+    };
+
 #define METRICSPERCOUNTER 
(sizeof(default_metric_settings)/sizeof(default_metric_settings[0]))
+#define METRICSPERDERIVED 
(sizeof(derived_metric_settings)/sizeof(derived_metric_settings[0]))
 
 static const char *dynamic_nametab[] =
 {
-    /* perfevent.hwcounters.{HWCOUNTER}.value */
+    /* perfevent.hwcounters.{HWCOUNTER,DERIVED}.value */
     "value",
     /* perfevent.hwcounters.{HWCOUNTER}.dutycycle */
     "dutycycle"
@@ -136,6 +149,12 @@ static const char *dynamic_helptab[] =
     "The ratio of the time that the hardware counter was enabled to the total 
run time"
 };
 
+static const char *dynamic_derived_helptab[] =
+{
+    /* perfevent.hwcounters.{DERIVED}.value */
+    "The values of the derived events"
+};
+
 static char mypath[MAXPATHLEN];
 static int     isDSO = 1;              /* =0 I am a daemon */
 static char    *username;
@@ -172,7 +191,7 @@ static int perfevent_fetchCallBack(pmdaMetric *mdesc, 
unsigned int inst, pmAtomV
             return PM_ERR_PMID;
         }
     }
-    else if(idp->cluster >= (nhwcounters + NUM_STATIC_CLUSTERS)  )
+    else if(idp->cluster >= (nderivedcounters + nhwcounters + 
NUM_STATIC_CLUSTERS)  )
     {
         return PM_ERR_PMID;
     }
@@ -184,12 +203,22 @@ static int perfevent_fetchCallBack(pmdaMetric *mdesc, 
unsigned int inst, pmAtomV
         return PM_ERR_PMID;
     }
 
-    const perf_data *pdata = &(pinfo->hwcounter->data[inst]);
+    const perf_data *pdata = NULL;
+    const perf_derived_data *pddata = NULL;
+
+    if (idp->cluster >= NUM_STATIC_CLUSTERS + nhwcounters) {
+       pddata = &(pinfo->derived_counter->data[inst]);
+    } else {
+       pdata = &(pinfo->hwcounter->data[inst]);
+    }
 
     switch(pinfo->pmid_index)
     {
     case 0:
-        atom->ll = pdata->value;
+       if (idp->cluster >= nhwcounters + NUM_STATIC_CLUSTERS)
+           atom->d = pddata->value;
+       else
+           atom->ll = pdata->value;
         break;
     case 1:
         if(pdata->time_enabled > 0)
@@ -219,7 +248,7 @@ static int perfevent_profile(__pmProfile *prof, pmdaExt 
*pmda)
  */
 static int perfevent_fetch(int numpmid, pmID pmidlist[], pmResult **resp, 
pmdaExt *pmda)
 {
-    activecounters = perf_get_r(perfif, &hwcounters, &nhwcounters);
+    activecounters = perf_get_r(perfif, &hwcounters, &nhwcounters, 
&derived_counters, &nderivedcounters);
 
     pmdaEventNewClient(pmda->e_context);
     return pmdaFetch(numpmid, pmidlist, resp, pmda);
@@ -299,6 +328,23 @@ static void config_indom(pmdaIndom *pindom, int index, 
perf_counter *counter)
     }
 }
 
+static void config_indom_derived(pmdaIndom *pindom, int index, 
perf_derived_counter *derived_counter)
+{
+    int i;
+    char cpuname[32];
+
+    pindom->it_indom = index;
+    pindom->it_numinst = derived_counter->ninstances;
+    pindom->it_set = calloc(derived_counter->ninstances, sizeof(pmdaInstid) );
+
+    for(i = 0; i < derived_counter->ninstances; ++i)
+    {
+        sprintf(cpuname, "cpu%d", 
derived_counter->counter_list->counter->data[i].id);
+        pindom->it_set[i].i_inst = i;
+        pindom->it_set[i].i_name = strdup(cpuname);
+    }
+}
+
 /* \brief Initialise the perf events interface and read the counters
  *
  * Note this function needs the correct OS permissions to succeed. Either
@@ -321,7 +367,7 @@ static int setup_perfevents()
         return -1;
     }
 
-    ret = perf_get_r(perfif, &hwcounters, &nhwcounters);
+    ret = perf_get_r(perfif, &hwcounters, &nhwcounters, &derived_counters, 
&nderivedcounters);
     if( ret < 0 )
     {
         err_desc = perf_strerror(ret);
@@ -336,7 +382,7 @@ static void teardown_perfevents()
 {
     manager_destroy(perfif);
     perfif = 0;
-    perf_counter_destroy(hwcounters, nhwcounters);
+    perf_counter_destroy(hwcounters, nhwcounters, derived_counters, 
nderivedcounters);
     hwcounters = 0;
     nhwcounters = 0;
 }
@@ -355,9 +401,12 @@ static int setup_metrics()
     int index;
 
     nummetrics = (nhwcounters * METRICSPERCOUNTER) + NUM_STATIC_METRICS;
-    numindoms = nhwcounters + NUM_STATIC_INDOMS;
+    nummetrics += (nderivedcounters * METRICSPERDERIVED);
+    numindoms = nderivedcounters + nhwcounters + NUM_STATIC_INDOMS;
 
-    dynamic_metric_infotab = malloc( nhwcounters * METRICSPERCOUNTER * 
sizeof(*dynamic_metric_infotab) );
+    dynamic_metric_infotab = malloc( ((nhwcounters * METRICSPERCOUNTER)
+                                     + (nderivedcounters * METRICSPERDERIVED))
+                                    * sizeof(*dynamic_metric_infotab) );
     metrictab              = malloc( nummetrics * sizeof(*metrictab) );
     indomtab               = malloc( numindoms * sizeof(*indomtab) );
 
@@ -406,6 +455,27 @@ static int setup_metrics()
         }
     }
 
+    for (i = 0; i < nderivedcounters; i++) {
+        cluster = i + nhwcounters + NUM_STATIC_CLUSTERS;
+        indom = i + nhwcounters + NUM_STATIC_INDOMS;
+
+        config_indom_derived( &indomtab[indom], indom, &derived_counters[i]);
+
+        memcpy(pmetric, derived_metric_settings, 
sizeof(derived_metric_settings));
+       for(index = 0; index < METRICSPERDERIVED; index++) {
+            /* Setup metrics info (used within this PMDA) */
+            pinfo->derived_counter = &derived_counters[i];
+            pinfo->pmid_index = index;
+            pinfo->help_text = dynamic_derived_helptab[index];
+            /* Initialize pmdaMetric settings (required by API) */
+            pmetric->m_desc.pmid = PMDA_PMID( cluster, index);
+            pmetric->m_desc.indom = indom;
+            pmetric->m_user = pinfo;
+            ++pinfo;
+            ++pmetric;
+        }
+    }
+
     return 0;
 }
 
@@ -479,6 +549,17 @@ static int setup_pmns()
         free(id);
     }
 
+    for (i = 0; i < nderivedcounters; ++i) {
+        char *id = normalize_metric_name(derived_counters[i].name);
+        for(j = 0; j < METRICSPERDERIVED; j++) {
+            snprintf(name, sizeof(name),
+                     PMDANAME ".derived.%s.%s", id, dynamic_nametab[j]);
+            __pmAddPMNSNode(pmns, pmetric[j].m_desc.pmid, name);
+        }
+        pmetric += METRICSPERDERIVED;
+        free(id);
+    }
+
     /* for reverse (pmid->name) lookups */
     pmdaTreeRebuildHash(pmns, nummetrics);
 
@@ -530,7 +611,7 @@ perfevent_init(pmdaInterface *dp)
     pmdaSetFetchCallBack(dp, perfevent_fetchCallBack);
     pmdaSetEndContextCallBack(dp, perfevent_end_contextCallBack);
 
-    pmdaInit(dp, indomtab, nhwcounters, metrictab, nummetrics);
+    pmdaInit(dp, indomtab, nhwcounters + nderivedcounters, metrictab, 
nummetrics);
 
     if(setup_pmns() < 0)
     {
diff --git a/src/pmdas/perfevent/pmns b/src/pmdas/perfevent/pmns
index 17c6d11..46425e9 100644
--- a/src/pmdas/perfevent/pmns
+++ b/src/pmdas/perfevent/pmns
@@ -18,5 +18,5 @@ perfevent {
     version    PERFEVENT:0:0
     active     PERFEVENT:0:1
     hwcounters PERFEVENT:*:*
-}
-
+    derived    PERFEVENT:*:*
+}
\ No newline at end of file
-- 
1.9.3

<Prev in Thread] Current Thread [Next in Thread>