This patch adds a capability to the perf derived events by giving them
a layer of abstraction. A perf derived event can be generated from a
group of base counters. The derived event can be a generic metric
whereas, the base counters are specific to hardware. For e.g., say a
metric called "memory_bandwidth" is defined as a derived metric. This
is obtained by looking at the base counters. These base counters will
be different for intel and other architectures. This patch gives the
perf derived events a layer of abstraction and ensures freedom in the
naming of the derived event. They can be defined in the perfevent.conf
file as :
...
[derived_perf_event:derived]
counter1_x86
counter2_x86
counter3_x86
counter4_x86
||
counter1_ppc
counter2_ppc
counter3_ppc
||
...
Note that the counters in derived group should have been defined in
perfevent.conf. The first group where all the counters are available
will be activated and rest won't be checked. If any counter in a group
is not available, entire group is discarded and the next group is
checked. Correct syntax has been specified in the perfevent.conf file.
Signed-off-by: Hemant Kumar <hemant@xxxxxxxxxxxxxxxxxx>
---
src/pmdas/perfevent/configparser.h | 10 +++-
src/pmdas/perfevent/configparser.l | 97 +++++++++++++++++++++++++++-----
src/pmdas/perfevent/perfevent.conf | 13 +++++
src/pmdas/perfevent/perfinterface.c | 108 +++++++++++++++++++++++++-----------
4 files changed, 182 insertions(+), 46 deletions(-)
diff --git a/src/pmdas/perfevent/configparser.h
b/src/pmdas/perfevent/configparser.h
index a999828..a614ffc 100644
--- a/src/pmdas/perfevent/configparser.h
+++ b/src/pmdas/perfevent/configparser.h
@@ -42,10 +42,16 @@ typedef struct pmcconfiguration {
pmcsetting_t *pmcSettingList;
} pmcconfiguration_t;
-typedef struct pmcderived {
- char *name;
+typedef struct settingLists {
int nsettings;
pmcsetting_t *derivedSettingList;
+ struct settingLists *next;
+} pmcSettingLists_t;
+
+typedef struct pmcderived {
+ char *name;
+ pmcSettingLists_t *setting_lists;
+ /* pmcsetting_t *derivedSettingList; */
} pmcderived_t;
typedef struct configuration {
diff --git a/src/pmdas/perfevent/configparser.l
b/src/pmdas/perfevent/configparser.l
index 01f089f..13a4bc2 100644
--- a/src/pmdas/perfevent/configparser.l
+++ b/src/pmdas/perfevent/configparser.l
@@ -56,8 +56,7 @@ static void add_derived(configuration_t *config, char *name)
entry = &config->derivedArr[config->nDerivedEntries-1];
entry->name = strdup(name);
- entry->nsettings = 0;
- entry->derivedSettingList = NULL;
+ entry->setting_lists = NULL;
context_derived = 1;
}
@@ -98,6 +97,7 @@ static void add_pmc_setting_name_derived(configuration_t
*config, char *name)
{
pmcderived_t *entry;
pmcsetting_t *slist, *newpmcderivedsetting;
+ pmcSettingLists_t *setting_lists, *new_setting_list;
if (0 == config->nDerivedEntries)
{
@@ -109,10 +109,32 @@ static void add_pmc_setting_name_derived(configuration_t
*config, char *name)
newpmcderivedsetting->cpuConfig = CPUCONFIG_EACH_CPU;
newpmcderivedsetting->next = NULL;
- slist = entry->derivedSettingList;
+ setting_lists = entry->setting_lists;
+
+ if (NULL == setting_lists)
+ {
+ new_setting_list = calloc(1, sizeof *setting_lists);
+ if (NULL == new_setting_list)
+ {
+ fprintf(stderr, "Error in allocating memory\n");
+ return;
+ }
+ new_setting_list->nsettings = 0;
+ new_setting_list->next = NULL;
+ new_setting_list->derivedSettingList = NULL;
+ setting_lists = new_setting_list;
+ entry->setting_lists = setting_lists;
+ }
+ else
+ {
+ while (setting_lists->next)
+ setting_lists = setting_lists->next;
+ }
+
+ slist = setting_lists->derivedSettingList;
if (slist == NULL)
{
- entry->derivedSettingList = newpmcderivedsetting;
+ setting_lists->derivedSettingList = newpmcderivedsetting;
}
else
{
@@ -122,7 +144,40 @@ static void add_pmc_setting_name_derived(configuration_t
*config, char *name)
}
slist->next = newpmcderivedsetting;
}
- entry->nsettings++;
+ setting_lists->nsettings++;
+}
+
+static void start_alternate_pmcsetting(configuration_t *config)
+{
+ pmcderived_t *entry;
+ pmcSettingLists_t *setting_lists, *new_setting_list;
+
+ if (!context_derived)
+ return;
+ if (0 == config->nDerivedEntries)
+ {
+ return;
+ }
+ entry = &config->derivedArr[config->nDerivedEntries - 1];
+
+ if (NULL == entry->setting_lists)
+ return;
+
+ setting_lists = entry->setting_lists;
+ new_setting_list = calloc(1, sizeof(*new_setting_list));
+ if (!new_setting_list)
+ {
+ fprintf(stderr, "Error in allocating memory\n");
+ return;
+ }
+ new_setting_list->nsettings = 0;
+ new_setting_list->derivedSettingList = NULL;
+ new_setting_list->next = NULL;
+
+ while(setting_lists->next)
+ setting_lists = setting_lists->next;
+
+ setting_lists->next = new_setting_list;
}
static void add_pmcsetting_name(configuration_t *config, char *name)
@@ -154,6 +209,7 @@ static void add_pmcsetting_name(configuration_t *config,
char *name)
static void set_pmcsetting_cpuconfig(configuration_t *config, int cpuconfig)
{
pmcsetting_t *pmcsetting;
+ pmcSettingLists_t *setting_lists;
if( (NULL == config) || (0 == config->nConfigEntries) )
{
@@ -162,7 +218,12 @@ static void set_pmcsetting_cpuconfig(configuration_t
*config, int cpuconfig)
if (context_derived)
{
- pmcsetting =
config->derivedArr[config->nDerivedEntries-1].derivedSettingList;
+ setting_lists =
config->derivedArr[config->nDerivedEntries-1].setting_lists;
+ while (setting_lists->next)
+ {
+ setting_lists = setting_lists->next;
+ }
+ pmcsetting = setting_lists->derivedSettingList;
while(pmcsetting->next)
{
pmcsetting = pmcsetting->next;
@@ -227,6 +288,7 @@ void free_configuration(configuration_t *config)
int i;
pmctype_t *pmcTypeDel;
pmcsetting_t *pmcSettingDel, *tmp;
+ pmcSettingLists_t *setting_lists, *tmp_list;
if(NULL == config)
{
@@ -255,16 +317,23 @@ void free_configuration(configuration_t *config)
for(i = 0; i < config->nDerivedEntries; ++i)
{
- tmp = pmcSettingDel = config->derivedArr[i].derivedSettingList;
- while(tmp != NULL)
+ tmp_list = setting_lists = config->derivedArr[i].setting_lists;
+ while(tmp_list != NULL)
{
- tmp = tmp->next;
- free(pmcSettingDel);
- pmcSettingDel = tmp;
+ tmp = pmcSettingDel = tmp_list->derivedSettingList;
+ while(tmp != NULL)
+ {
+ tmp = tmp->next;
+ free(pmcSettingDel);
+ pmcSettingDel = tmp;
+ }
+ tmp_list = tmp_list->next;
+ free(setting_lists);
+ setting_lists = tmp_list;
}
- if (config->derivedArr[i].name)
- free(config->derivedArr[i].name);
+ if (config->derivedArr[i].name)
+ free(config->derivedArr[i].name);
}
free(config->configArr);
free(config->derivedArr);
@@ -297,6 +366,8 @@ void free_configuration(configuration_t *config)
^([[:alpha:]]+[[:alnum:][:punct:]]*) { BEGIN(PMCSETTINGLIST);
add_pmcsetting_name(yyextra, yytext ); }
+"||" { start_alternate_pmcsetting(yyextra); }
+
<PMCSETTINGLIST>{
cpu set_pmcsetting_cpuconfig(yyextra, CPUCONFIG_EACH_CPU);
cpu_rr set_pmcsetting_cpuconfig(yyextra, CPUCONFIG_ROUNDROBIN_CPU);
diff --git a/src/pmdas/perfevent/perfevent.conf
b/src/pmdas/perfevent/perfevent.conf
index 25421a1..9826bef 100644
--- a/src/pmdas/perfevent/perfevent.conf
+++ b/src/pmdas/perfevent/perfevent.conf
@@ -16,6 +16,19 @@
# EVENT_NAME [CPU OPTION]
# where the CPU OPTION must match for all the events in a derived event.
#
+# Derived events also have the capability of alternate event groups.
+# [event:derived]
+# EVENT_NAME1 [CPU OPTION]
+# EVENT_NAME2 [CPU OPTION]
+# ||
+# EVENT_NAME3 [CPU OPTION]
+# EVENT_NAME4 [CPU OPTION]
+# ||
+# ...
+# If specified like above, depending on the availability of the events,
+# only one group will be activated ("||" is the group separator).
+# First group with all the events available will be activated.
+#
[amd64_fam10h_barcelona amd64_fam10h_shanghai amd64_fam10h_istanbul]
diff --git a/src/pmdas/perfevent/perfinterface.c
b/src/pmdas/perfevent/perfinterface.c
index 402f1b1..bf4b0d9 100644
--- a/src/pmdas/perfevent/perfinterface.c
+++ b/src/pmdas/perfevent/perfinterface.c
@@ -164,6 +164,21 @@ static event_t *search_event(perfdata_t *inst, const char
*event_name)
}
/*
+ * Free up the event list "event_list"
+ */
+static void free_event_list(event_list_t *event_list)
+{
+ event_list_t *tmp;
+
+ tmp = event_list;
+ while(tmp) {
+ tmp = tmp->next;
+ free(event_list);
+ event_list = tmp;
+ }
+}
+
+/*
* Setup a derived event
*/
static int perf_setup_derived_event(perfdata_t *inst, pmcderived_t
*derived_pmc)
@@ -172,13 +187,16 @@ static int perf_setup_derived_event(perfdata_t *inst,
pmcderived_t *derived_pmc)
int nderivedevents = inst->nderivedevents;
event_t *event;
pmcsetting_t *derived_setting;
+ pmcSettingLists_t *setting_list;
event_list_t *ptr, *tmp, *event_list;
- int cpuconfig;
+ int cpuconfig, clear_history = 0;
tmp = NULL;
event_list = NULL;
- if (0 == derived_pmc->nsettings)
+ if (NULL == derived_pmc->setting_lists) {
+ fprintf(stderr, "No derived_pmc settings\n");
return -E_PERFEVENT_LOGIC;
+ }
derived_events = realloc(derived_events,
(nderivedevents + 1) * sizeof(*derived_events));
@@ -189,35 +207,63 @@ static int perf_setup_derived_event(perfdata_t *inst,
pmcderived_t *derived_pmc)
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;
- }
+ /*
+ * If a certain setting_list is not available, then we need to check if the
+ * next one is available.
+ */
+ setting_list = derived_pmc->setting_lists;
+
+ while (setting_list) {
+ event_list = NULL;
+ derived_setting = setting_list->derivedSettingList;
+ clear_history = 0;
+ if (derived_setting)
+ cpuconfig = derived_setting->cpuConfig;
+ while (derived_setting) {
+ event = search_event(inst, derived_setting->name);
+ if (NULL == event) {
+ fprintf(stderr, "Derived setting %s not found\n",
derived_setting->name);
+ clear_history = 1;
+ break;
+ }
+
+ if (cpuconfig != derived_setting->cpuConfig) {
+ fprintf(stderr, "Mismatch in cpu configuration\n");
+ free_event_list(event_list);
+ return -E_PERFEVENT_LOGIC;
+ }
+ derived_setting = derived_setting->next;
+
+ tmp = calloc(1, sizeof(*tmp));
+ if (NULL == tmp) {
+ free_event_list(event_list);
+ 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;
+ }
+ }
+ /* There was a event mismatch in the curr list, so, discard this list */
+ if (clear_history)
+ free_event_list(event_list);
+
+ /* All the events in the curr list have been successfully found */
+ if (NULL == derived_setting)
+ break;
+ setting_list = setting_list->next;
+ }
+
+ /* If clear_history is still on, then, none of the events were found */
+ if (clear_history) {
+ fprintf(stderr, "None of the derived settings found\n");
+ return -E_PERFEVENT_LOGIC;
}
tmp = event_list;
--
1.9.3
|