From 2251fbdda3b270fa1b1c5f59c83d1e156ff8ea36 Mon Sep 17 00:00:00 2001
From: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Date: Wed, 16 Oct 2019 16:09:04 +0530
Subject: [PATCH] pmdas/perf: Add support for hv_24x7 nest events on mutlinode
 system

Patch-mainline: 5.0.1
Git-commit: 2251fbdda3b270fa1b1c5f59c83d1e156ff8ea36

For dynamic perf events like hv_24x7 nest event, `chip_id` is also an
event parameter. So for multinode systems, same event can be defined for
different nodes(/chips) in the system.

Add support for hv_24x7 nest events in mutinode systems.

Eg:

---> perfevent.conf
[dynamic]
hv_24x7.PM_PB_CYC 4     chip:0
hv_24x7.PM_PB_CYC 13    chip:1
hv_24x7.PM_MBA0_CLK_CYC 4 chip:0
hv_24x7.PM_MBA0_CLK_CYC 14 chip:1

# pminfo | grep PM_PB_CYC
perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_1.dutycycle
perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_1.value
perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_0.dutycycle
perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_0.value

# pmval perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_0.value
metric:    perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_0.value
host:      ####
semantics: cumulative counter (converting to rate)
units:     count (converting to count / sec)
samples:   all

              cpu4
            7.805E+06

# pmval perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_1.value

metric:    perfevent.hwcounters.hv_24x7.PM_PB_CYC_chip_1.value
host:      ####
semantics: cumulative counter (converting to rate)
units:     count (converting to count / sec)
samples:   all

             cpu13
            7.805E+06
            7.805E+06

Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Signed-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com>
---
 src/pmdas/perfevent/parse_events.c | 221 ++++++++++++++++++-----------
 1 file changed, 138 insertions(+), 83 deletions(-)

diff --git a/src/pmdas/perfevent/parse_events.c b/src/pmdas/perfevent/parse_events.c
index 1632f09b1f32..27fb37df3fb7 100644
--- a/src/pmdas/perfevent/parse_events.c
+++ b/src/pmdas/perfevent/parse_events.c
@@ -412,89 +412,138 @@ static void cleanup_property_info(struct property_info *pi)
  */
 static int parse_event_string(char *buf, struct pmu_event *event,
                               struct pmu *pmu, struct pmcsetting *dynamicpmc,
-			       char *pmu_name)
+			       char *pmu_name, int *new_events)
 {
     struct property_info *pi, *head = NULL, *tmp;
-    char *start, *ptr, *nptr, **endptr, *str, eventname[BUF_SIZE];
+    char *start, *ptr, *nptr, **endptr, *str, eventname[BUF_SIZE], ev_str[BUF_SIZE], pmc_str[BUF_SIZE], *tmp_buf_str;
     struct pmcsetting *pmctmp;
+    int i, ret, sub_ev_cnt = 0;
+    struct pmu_event *sub_event = NULL, *ev_tmp= NULL, *ev_head = NULL;
+
+    pmsprintf(ev_str, sizeof(ev_str), "%s.%s", pmu_name, event->name);
+    for (pmctmp = dynamicpmc; pmctmp; pmctmp = pmctmp->next)
+	if (!strncmp(ev_str, pmctmp->name, strlen(ev_str)))
+		sub_ev_cnt++;
+
+    if (sub_ev_cnt > 1)
+	*new_events = sub_ev_cnt;
+
+    for (i = 0; i < (sub_ev_cnt - 1); i++) {
+	ev_tmp = calloc(1, sizeof(*ev_tmp));
+	if (!ev_tmp) {
+		sub_ev_cnt = 0;
+		break;
+	}
+
+	if (!sub_event) {
+		sub_event = ev_tmp;
+		ev_head = sub_event;
+		event->next = ev_head;
+		sub_event->name = strdup(event->name);
+	} else {
+		sub_event->next = ev_tmp;
+		sub_event = sub_event->next;
+		sub_event->name = strdup(event->name);
+	}
+    }
 
-    start = buf;
-
-    while (1) {
-        ptr = strchr(start, '=');
-        if (!ptr)
-            break;
-
-        /* Found a property */
-        *ptr = '\0';
-        ptr++;   /* ptr now points to the value */
-        pi = calloc(1, sizeof(*pi));
-        if (!pi) {
-            cleanup_property_info(head);
-            return -E_PERFEVENT_REALLOC;
-        }
-        pi->next = NULL;
-
-        pi->name = strdup(start);
-        if (!pi->name) {
-            free(pi);
-            cleanup_property_info(head);
-            return -E_PERFEVENT_REALLOC;
-        }
-
-	pmsprintf(eventname, sizeof(eventname), "%s.%s", pmu_name, event->name);
-
-        /* Find next property */
-        start = strchr(ptr, ',');
-        if (!start) {
-            str = buf + strlen(buf) - 1;
-            endptr = &str;
-            nptr = ptr;
-	    if ((!strcmp(nptr, "?")) && (!strcmp(pi->name, "chip"))) {
-		for (pmctmp = dynamicpmc; pmctmp; pmctmp = pmctmp->next) {
-			if (!strncmp(eventname, pmctmp->name, strlen(eventname)))
+    ev_head = event;
+
+    for (i=0; i < sub_ev_cnt; i++) {
+        head = NULL;
+        tmp_buf_str = strdup(buf);
+        start = tmp_buf_str;
+
+	while (1) {
+	    ptr = strchr(start, '=');
+	    if (!ptr)
+	        break;
+
+	    /* Found a property */
+	    *ptr = '\0';
+	    ptr++;   /* ptr now points to the value */
+	    pi = calloc(1, sizeof(*pi));
+	    if (!pi) {
+	        cleanup_property_info(head);
+	        return -E_PERFEVENT_REALLOC;
+	    }
+
+	    pi->next = NULL;
+	    pi->name = strdup(start);
+	    if (!pi->name) {
+	       free(pi);
+	       cleanup_property_info(head);
+	       return -E_PERFEVENT_REALLOC;
+	    }
+
+	    pmsprintf(eventname, sizeof(eventname), "%s.%s", pmu_name, event->name);
+
+	    /* Find next property */
+	    start = strchr(ptr, ',');
+	    if (!start) {
+	        str = buf + strlen(buf) - 1;
+		endptr = &str;
+		nptr = ptr;
+		if ((!strcmp(nptr, "?")) && (!strcmp(pi->name, "chip"))) {
+		    for (pmctmp = dynamicpmc; pmctmp; pmctmp = pmctmp->next) {
+		        if (!strncmp(eventname, pmctmp->name, strlen(pmctmp->name)))
 			{
-			     pi->value = pmctmp->chip;
+			    pmsprintf(ev_str, sizeof(ev_str), "%s_chip_%d", event->name,pmctmp->chip);
+			    event->name = strdup(ev_str);
+			    pmsprintf(pmc_str, sizeof(pmc_str), "%s_chip_%d", pmctmp->name,pmctmp->chip);
+			    pmctmp->name = strdup(pmc_str);
+			    pi->value = pmctmp->chip;
+			    break;
 			}
+		    }
+		} else
+		    pi->value = strtoull(nptr, endptr, 16);
+		if (!head) {
+		    head = pi;
+		    pi = pi->next;
+		} else {
+		    tmp->next = pi;
+		    tmp = tmp->next;
 		}
-            } else
-		pi->value = strtoull(nptr, endptr, 16);
-            if (!head) {
-                head = pi;
-                pi = pi->next;
-            } else {
-                tmp->next = pi;
-                tmp = tmp->next;
-            }
-            break;
-        } else {
-            /* We found the next property */
-            *start = '\0';
-            str = buf + strlen(buf) - 1;
-            endptr = &str;
-            start++;
-            nptr = ptr;
-	    if ((!strcmp(nptr, "?")) && (!strcmp(pi->name, "chip"))) {
-		for (pmctmp = dynamicpmc; pmctmp; pmctmp = pmctmp->next) {
-			if (!strncmp(eventname, pmctmp->name, strlen(eventname)))
+		break;
+	    } else {
+	        /* We found the next property */
+		*start = '\0';
+		str = buf + strlen(buf) - 1;
+		endptr = &str;
+		start++;
+		nptr = ptr;
+		if ((!strcmp(nptr, "?")) && (!strcmp(pi->name, "chip"))) {
+	            for (pmctmp = dynamicpmc; pmctmp; pmctmp = pmctmp->next) {
+		        if (!strncmp(eventname, pmctmp->name, strlen(pmctmp->name)))
 			{
-			     pi->value = pmctmp->chip;
+		            pmsprintf(ev_str, sizeof(ev_str), "%s_chip_%d", event->name,pmctmp->chip);
+			    event->name = strdup(ev_str);
+			    pmsprintf(pmc_str, sizeof(pmc_str), "%s_chip_%d", pmctmp->name,pmctmp->chip);
+			    pmctmp->name = strdup(pmc_str);
+			    pi->value = pmctmp->chip;
+			    break;
 			}
-		}
-	    } else
-		pi->value = strtoul(nptr, endptr, 16);
-        }
-
-        if (!head) {
-            head = pi;
-            tmp = head;
-        } else {
-            tmp->next = pi;
-            tmp = tmp->next;
-        }
+		    }
+		} else
+		    pi->value = strtoul(nptr, endptr, 16);
+	    }
+	    if (!head) {
+	        head = pi;
+		tmp = head;
+	    } else {
+		tmp->next = pi;
+		tmp = tmp->next;
+	    }
+	}
+	ret = fetch_event_config(head, event, pmu);
+	if (ret)
+	    return ret;
+
+	event->pmu = pmu;
+	event = event->next;
     }
-
-    return fetch_event_config(head, event, pmu);
+    return 0;
 }
 
 /*
@@ -509,7 +558,7 @@ static int fetch_events(DIR *events_dir, struct pmu_event **events,
     struct dirent *dir;
     struct pmu_event *ev = NULL, *tmp, *head = NULL;
     char event_path[PATH_MAX], *buf;
-    int ret = 0;
+    int ret = 0, sub_events, i;
 
     if (!events_dir)
         return -1;
@@ -551,21 +600,27 @@ static int fetch_events(DIR *events_dir, struct pmu_event **events,
             goto free_buf;
         }
 
-        ret = parse_event_string(buf, tmp, pmu, dynamicpmc, pmu_name);
+        ret = parse_event_string(buf, tmp, pmu, dynamicpmc, pmu_name, &sub_events);
         if (ret) {
             ret = -E_PERFEVENT_RUNTIME;
             goto free_buf;
         }
 
-        tmp->pmu = pmu;
+	i = 0;
+	do {
+	    tmp->pmu = pmu;
+	    if (!ev) {
+	         ev = tmp;
+	         head = ev;
+	    } else {
+	         ev->next = tmp;
+	         ev = ev->next;
+            }
+	    tmp = tmp->next;
+	    i++;
+	} while(i < sub_events);
 
-        if (!ev) {
-            ev = tmp;
-            head = ev;
-        } else {
-            ev->next = tmp;
-            ev = ev->next;
-        }
+	sub_events = 0;
     }
 
     *events = head;
-- 
2.23.0

