|
@@ -234,6 +234,74 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void perf_pmu_assign_str(char *name, const char *field, char **old_str,
|
|
|
|
+ char **new_str)
|
|
|
|
+{
|
|
|
|
+ if (!*old_str)
|
|
|
|
+ goto set_new;
|
|
|
|
+
|
|
|
|
+ if (*new_str) { /* Have new string, check with old */
|
|
|
|
+ if (strcasecmp(*old_str, *new_str))
|
|
|
|
+ pr_debug("alias %s differs in field '%s'\n",
|
|
|
|
+ name, field);
|
|
|
|
+ zfree(old_str);
|
|
|
|
+ } else /* Nothing new --> keep old string */
|
|
|
|
+ return;
|
|
|
|
+set_new:
|
|
|
|
+ *old_str = *new_str;
|
|
|
|
+ *new_str = NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void perf_pmu_update_alias(struct perf_pmu_alias *old,
|
|
|
|
+ struct perf_pmu_alias *newalias)
|
|
|
|
+{
|
|
|
|
+ perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc);
|
|
|
|
+ perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
|
|
|
|
+ &newalias->long_desc);
|
|
|
|
+ perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
|
|
|
|
+ perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
|
|
|
|
+ &newalias->metric_expr);
|
|
|
|
+ perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
|
|
|
|
+ &newalias->metric_name);
|
|
|
|
+ perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
|
|
|
|
+ old->scale = newalias->scale;
|
|
|
|
+ old->per_pkg = newalias->per_pkg;
|
|
|
|
+ old->snapshot = newalias->snapshot;
|
|
|
|
+ memcpy(old->unit, newalias->unit, sizeof(old->unit));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Delete an alias entry. */
|
|
|
|
+static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
|
|
|
|
+{
|
|
|
|
+ zfree(&newalias->name);
|
|
|
|
+ zfree(&newalias->desc);
|
|
|
|
+ zfree(&newalias->long_desc);
|
|
|
|
+ zfree(&newalias->topic);
|
|
|
|
+ zfree(&newalias->str);
|
|
|
|
+ zfree(&newalias->metric_expr);
|
|
|
|
+ zfree(&newalias->metric_name);
|
|
|
|
+ parse_events_terms__purge(&newalias->terms);
|
|
|
|
+ free(newalias);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Merge an alias, search in alias list. If this name is already
|
|
|
|
+ * present merge both of them to combine all information.
|
|
|
|
+ */
|
|
|
|
+static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
|
|
|
|
+ struct list_head *alist)
|
|
|
|
+{
|
|
|
|
+ struct perf_pmu_alias *a;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(a, alist, list) {
|
|
|
|
+ if (!strcasecmp(newalias->name, a->name)) {
|
|
|
|
+ perf_pmu_update_alias(a, newalias);
|
|
|
|
+ perf_pmu_free_alias(newalias);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
|
static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
|
char *desc, char *val,
|
|
char *desc, char *val,
|
|
char *long_desc, char *topic,
|
|
char *long_desc, char *topic,
|
|
@@ -241,9 +309,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
|
char *metric_expr,
|
|
char *metric_expr,
|
|
char *metric_name)
|
|
char *metric_name)
|
|
{
|
|
{
|
|
|
|
+ struct parse_events_term *term;
|
|
struct perf_pmu_alias *alias;
|
|
struct perf_pmu_alias *alias;
|
|
int ret;
|
|
int ret;
|
|
int num;
|
|
int num;
|
|
|
|
+ char newval[256];
|
|
|
|
|
|
alias = malloc(sizeof(*alias));
|
|
alias = malloc(sizeof(*alias));
|
|
if (!alias)
|
|
if (!alias)
|
|
@@ -262,6 +332,27 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Scan event and remove leading zeroes, spaces, newlines, some
|
|
|
|
+ * platforms have terms specified as
|
|
|
|
+ * event=0x0091 (read from files ../<PMU>/events/<FILE>
|
|
|
|
+ * and terms specified as event=0x91 (read from JSON files).
|
|
|
|
+ *
|
|
|
|
+ * Rebuild string to make alias->str member comparable.
|
|
|
|
+ */
|
|
|
|
+ memset(newval, 0, sizeof(newval));
|
|
|
|
+ ret = 0;
|
|
|
|
+ list_for_each_entry(term, &alias->terms, list) {
|
|
|
|
+ if (ret)
|
|
|
|
+ ret += scnprintf(newval + ret, sizeof(newval) - ret,
|
|
|
|
+ ",");
|
|
|
|
+ if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
|
|
|
|
+ ret += scnprintf(newval + ret, sizeof(newval) - ret,
|
|
|
|
+ "%s=%#x", term->config, term->val.num);
|
|
|
|
+ else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
|
|
|
|
+ ret += scnprintf(newval + ret, sizeof(newval) - ret,
|
|
|
|
+ "%s=%s", term->config, term->val.str);
|
|
|
|
+ }
|
|
|
|
+
|
|
alias->name = strdup(name);
|
|
alias->name = strdup(name);
|
|
if (dir) {
|
|
if (dir) {
|
|
/*
|
|
/*
|
|
@@ -285,9 +376,10 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
|
snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
|
|
snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
|
|
}
|
|
}
|
|
alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
|
|
alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
|
|
- alias->str = strdup(val);
|
|
|
|
|
|
+ alias->str = strdup(newval);
|
|
|
|
|
|
- list_add_tail(&alias->list, list);
|
|
|
|
|
|
+ if (!perf_pmu_merge_alias(alias, list))
|
|
|
|
+ list_add_tail(&alias->list, list);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -303,6 +395,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
|
|
|
|
|
|
buf[ret] = 0;
|
|
buf[ret] = 0;
|
|
|
|
|
|
|
|
+ /* Remove trailing newline from sysfs file */
|
|
|
|
+ rtrim(buf);
|
|
|
|
+
|
|
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
|
|
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
|
|
NULL, NULL, NULL);
|
|
NULL, NULL, NULL);
|
|
}
|
|
}
|