From: Kan Liang <[email protected]>

There are duplicate codes implemented to support different scopes of
counters. Apply the new concept, "domain", for cstate to reduce the
redundancy.

Add struct cstate_pmus to store the PMU related information. Each
available type needs a dedicated cstate_pmus, which is allocated
in cstate_probe_msr().
Remove hardcode cstate_core_pmu and cstate_pkg_pmu. The PMU information
can be found via domain type now.
Cleanup the codes in cstate_pmu_event_init(), cstate_get_attr_cpumask()
and cstate_init().

The format attrs are the same for PACKAGE_DOMAIN and CORE_DOMAIN.
Remove the duplicate codes.

The cpu_mask of a domain type can be retrieved from the common
functions. Cleanup cstate_cpu_init/exit, and remove duplicate codes.

Signed-off-by: Kan Liang <[email protected]>
---
 arch/x86/events/intel/cstate.c | 341 ++++++++++++++++++++++-------------------
 1 file changed, 184 insertions(+), 157 deletions(-)

diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c
index d2e7807..5f71606 100644
--- a/arch/x86/events/intel/cstate.c
+++ b/arch/x86/events/intel/cstate.c
@@ -96,6 +96,7 @@
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
 #include "../perf_event.h"
+#include "../domain.h"
 
 MODULE_LICENSE("GPL");
 
@@ -110,14 +111,15 @@ static ssize_t __cstate_##_var##_show(struct kobject 
*kobj,       \
 static struct kobj_attribute format_attr_##_var =              \
        __ATTR(_name, 0444, __cstate_##_var##_show, NULL)
 
-static ssize_t cstate_get_attr_cpumask(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf);
-
 /* Model -> events mapping */
 struct cstate_model {
-       unsigned long           core_events;
-       unsigned long           pkg_events;
+       union {
+               unsigned long   events[DOMAIN_TYPE_MAX];
+               struct {
+                       unsigned long   pkg_events;
+                       unsigned long   core_events;
+               };
+       };
        unsigned long           quirks;
 };
 
@@ -130,10 +132,17 @@ struct perf_cstate_msr {
        struct  perf_pmu_events_attr *attr;
 };
 
+struct cstate_pmus {
+       struct pmu              pmu;
+       struct domain_type      type;
+       int                     event_max;
+       struct perf_cstate_msr  *msrs;
+       struct attribute        **attrs;
+       cpumask_t               cpu_mask;
+};
+static struct cstate_pmus *cstate_pmus[DOMAIN_TYPE_MAX];
 
 /* cstate_core PMU */
-static struct pmu cstate_core_pmu;
-static bool has_cstate_core;
 
 enum perf_cstate_core_events {
        PERF_CSTATE_CORE_C1_RES = 0,
@@ -166,17 +175,33 @@ static struct attribute_group core_events_attr_group = {
 };
 
 DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63");
-static struct attribute *core_format_attrs[] = {
+static struct attribute *format_attrs[] = {
        &format_attr_core_event.attr,
        NULL,
 };
 
-static struct attribute_group core_format_attr_group = {
+static struct attribute_group format_attr_group = {
        .name = "format",
-       .attrs = core_format_attrs,
+       .attrs = format_attrs,
 };
 
-static cpumask_t cstate_core_cpu_mask;
+static ssize_t cstate_get_attr_cpumask(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct pmu *pmu = dev_get_drvdata(dev);
+       struct cstate_pmus *pmus;
+       int i;
+
+       for (i = 0; i < DOMAIN_TYPE_MAX; i++) {
+               pmus = cstate_pmus[i];
+               if (!pmus || &pmus->pmu != pmu)
+                       continue;
+               return cpumap_print_to_pagebuf(true, buf, &pmus->cpu_mask);
+       }
+       return 0;
+}
+
 static DEVICE_ATTR(cpumask, S_IRUGO, cstate_get_attr_cpumask, NULL);
 
 static struct attribute *cstate_cpumask_attrs[] = {
@@ -190,15 +215,12 @@ static struct attribute_group cpumask_attr_group = {
 
 static const struct attribute_group *core_attr_groups[] = {
        &core_events_attr_group,
-       &core_format_attr_group,
+       &format_attr_group,
        &cpumask_attr_group,
        NULL,
 };
 
 /* cstate_pkg PMU */
-static struct pmu cstate_pkg_pmu;
-static bool has_cstate_pkg;
-
 enum perf_cstate_pkg_events {
        PERF_CSTATE_PKG_C2_RES = 0,
        PERF_CSTATE_PKG_C3_RES,
@@ -238,44 +260,24 @@ static struct attribute_group pkg_events_attr_group = {
        .attrs = pkg_events_attrs,
 };
 
-DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63");
-static struct attribute *pkg_format_attrs[] = {
-       &format_attr_pkg_event.attr,
-       NULL,
-};
-static struct attribute_group pkg_format_attr_group = {
-       .name = "format",
-       .attrs = pkg_format_attrs,
-};
-
-static cpumask_t cstate_pkg_cpu_mask;
-
 static const struct attribute_group *pkg_attr_groups[] = {
        &pkg_events_attr_group,
-       &pkg_format_attr_group,
+       &format_attr_group,
        &cpumask_attr_group,
        NULL,
 };
 
-static ssize_t cstate_get_attr_cpumask(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf)
-{
-       struct pmu *pmu = dev_get_drvdata(dev);
-
-       if (pmu == &cstate_core_pmu)
-               return cpumap_print_to_pagebuf(true, buf, 
&cstate_core_cpu_mask);
-       else if (pmu == &cstate_pkg_pmu)
-               return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask);
-       else
-               return 0;
-}
-
 static int cstate_pmu_event_init(struct perf_event *event)
 {
+       const struct cpumask *cpu_mask;
        u64 cfg = event->attr.config;
+       struct cstate_pmus *pmus;
        int cpu;
 
+       pmus = container_of(event->pmu, struct cstate_pmus, pmu);
+       if (!pmus)
+               return -ENOENT;
+
        if (event->attr.type != event->pmu->type)
                return -ENOENT;
 
@@ -292,26 +294,19 @@ static int cstate_pmu_event_init(struct perf_event *event)
        if (event->cpu < 0)
                return -EINVAL;
 
-       if (event->pmu == &cstate_core_pmu) {
-               if (cfg >= PERF_CSTATE_CORE_EVENT_MAX)
-                       return -EINVAL;
-               if (!core_msr[cfg].attr)
-                       return -EINVAL;
-               event->hw.event_base = core_msr[cfg].msr;
-               cpu = cpumask_any_and(&cstate_core_cpu_mask,
-                                     topology_sibling_cpumask(event->cpu));
-       } else if (event->pmu == &cstate_pkg_pmu) {
-               if (cfg >= PERF_CSTATE_PKG_EVENT_MAX)
-                       return -EINVAL;
-               cfg = array_index_nospec((unsigned long)cfg, 
PERF_CSTATE_PKG_EVENT_MAX);
-               if (!pkg_msr[cfg].attr)
-                       return -EINVAL;
-               event->hw.event_base = pkg_msr[cfg].msr;
-               cpu = cpumask_any_and(&cstate_pkg_cpu_mask,
-                                     topology_core_cpumask(event->cpu));
-       } else {
-               return -ENOENT;
-       }
+       if (cfg >= pmus->event_max)
+               return -EINVAL;
+
+       cfg = array_index_nospec((unsigned long)cfg, pmus->event_max);
+       if (!pmus->msrs[cfg].attr)
+               return -EINVAL;
+
+       event->hw.event_base = pmus->msrs[cfg].msr;
+
+       cpu_mask = get_domain_cpu_mask(event->cpu, &pmus->type);
+       if (!cpu_mask)
+               return -ENODEV;
+       cpu = cpumask_any_and(&pmus->cpu_mask, cpu_mask);
 
        if (cpu >= nr_cpu_ids)
                return -ENODEV;
@@ -375,85 +370,61 @@ static int cstate_pmu_event_add(struct perf_event *event, 
int mode)
  */
 static int cstate_cpu_exit(unsigned int cpu)
 {
+       const struct cpumask *cpu_mask;
+       struct cstate_pmus *pmus;
        unsigned int target;
+       int i;
 
-       if (has_cstate_core &&
-           cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask)) {
+       for (i = 0; i < DOMAIN_TYPE_MAX; i++) {
+               if (!cstate_pmus[i])
+                       continue;
 
-               target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
-               /* Migrate events if there is a valid target */
-               if (target < nr_cpu_ids) {
-                       cpumask_set_cpu(target, &cstate_core_cpu_mask);
-                       perf_pmu_migrate_context(&cstate_core_pmu, cpu, target);
-               }
-       }
+               cpu_mask = get_domain_cpu_mask(cpu, &cstate_pmus[i]->type);
+               if (!cpu_mask)
+                       continue;
 
-       if (has_cstate_pkg &&
-           cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask)) {
+               pmus = cstate_pmus[i];
+               if (!cpumask_test_and_clear_cpu(cpu, &pmus->cpu_mask))
+                       continue;
 
-               target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
+               target = cpumask_any_but(cpu_mask, cpu);
                /* Migrate events if there is a valid target */
                if (target < nr_cpu_ids) {
-                       cpumask_set_cpu(target, &cstate_pkg_cpu_mask);
-                       perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
+                       cpumask_set_cpu(target, &pmus->cpu_mask);
+                       perf_pmu_migrate_context(&pmus->pmu, cpu, target);
                }
        }
+
        return 0;
 }
 
 static int cstate_cpu_init(unsigned int cpu)
 {
+       const struct cpumask *cpu_mask;
+       struct cstate_pmus *pmus;
        unsigned int target;
+       int i;
 
-       /*
-        * If this is the first online thread of that core, set it in
-        * the core cpu mask as the designated reader.
-        */
-       target = cpumask_any_and(&cstate_core_cpu_mask,
-                                topology_sibling_cpumask(cpu));
-
-       if (has_cstate_core && target >= nr_cpu_ids)
-               cpumask_set_cpu(cpu, &cstate_core_cpu_mask);
-
-       /*
-        * If this is the first online thread of that package, set it
-        * in the package cpu mask as the designated reader.
-        */
-       target = cpumask_any_and(&cstate_pkg_cpu_mask,
-                                topology_core_cpumask(cpu));
-       if (has_cstate_pkg && target >= nr_cpu_ids)
-               cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
+       for (i = 0; i < DOMAIN_TYPE_MAX; i++) {
+               if (!cstate_pmus[i])
+                       continue;
 
-       return 0;
-}
+               cpu_mask = get_domain_cpu_mask(cpu, &cstate_pmus[i]->type);
+               if (!cpu_mask)
+                       continue;
 
-static struct pmu cstate_core_pmu = {
-       .attr_groups    = core_attr_groups,
-       .name           = "cstate_core",
-       .task_ctx_nr    = perf_invalid_context,
-       .event_init     = cstate_pmu_event_init,
-       .add            = cstate_pmu_event_add,
-       .del            = cstate_pmu_event_del,
-       .start          = cstate_pmu_event_start,
-       .stop           = cstate_pmu_event_stop,
-       .read           = cstate_pmu_event_update,
-       .capabilities   = PERF_PMU_CAP_NO_INTERRUPT,
-       .module         = THIS_MODULE,
-};
+               pmus = cstate_pmus[i];
+               /*
+                * If this is the first online thread of that core, set it in
+                * the core cpu mask as the designated reader.
+                */
+               target = cpumask_any_and(&pmus->cpu_mask, cpu_mask);
 
-static struct pmu cstate_pkg_pmu = {
-       .attr_groups    = pkg_attr_groups,
-       .name           = "cstate_pkg",
-       .task_ctx_nr    = perf_invalid_context,
-       .event_init     = cstate_pmu_event_init,
-       .add            = cstate_pmu_event_add,
-       .del            = cstate_pmu_event_del,
-       .start          = cstate_pmu_event_start,
-       .stop           = cstate_pmu_event_stop,
-       .read           = cstate_pmu_event_update,
-       .capabilities   = PERF_PMU_CAP_NO_INTERRUPT,
-       .module         = THIS_MODULE,
-};
+               if (target >= nr_cpu_ids)
+                       cpumask_set_cpu(cpu, &pmus->cpu_mask);
+       }
+       return 0;
+}
 
 static const struct cstate_model nhm_cstates __initconst = {
        .core_events            = BIT(PERF_CSTATE_CORE_C3_RES) |
@@ -592,14 +563,28 @@ MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
  * Probe the cstate events and insert the available one into sysfs attrs
  * Return false if there are no available events.
  */
-static bool __init cstate_probe_msr(const unsigned long evmsk, int max,
-                                   struct perf_cstate_msr *msr,
-                                   struct attribute **attrs)
+static bool __init cstate_probe_msr(const unsigned long evmsk,
+                                   enum domain_types type)
 {
+       struct perf_cstate_msr *msr;
+       struct attribute **attrs;
+       struct cstate_pmus *pmus;
        bool found = false;
        unsigned int bit;
+       int max;
        u64 val;
 
+       if (type == PACKAGE_DOMAIN) {
+               max = PERF_CSTATE_PKG_EVENT_MAX;
+               msr = pkg_msr;
+               attrs = pkg_events_attrs;
+       } else if (type == CORE_DOMAIN) {
+               max = PERF_CSTATE_CORE_EVENT_MAX;
+               msr = core_msr;
+               attrs = core_events_attrs;
+       } else
+               return false;
+
        for (bit = 0; bit < max; bit++) {
                if (test_bit(bit, &evmsk) && !rdmsrl_safe(msr[bit].msr, &val)) {
                        *attrs++ = &msr[bit].attr->attr.attr;
@@ -610,11 +595,32 @@ static bool __init cstate_probe_msr(const unsigned long 
evmsk, int max,
        }
        *attrs = NULL;
 
-       return found;
+       if (!found)
+               return false;
+
+       pmus = kzalloc(sizeof(struct cstate_pmus), GFP_KERNEL);
+       if (!pmus)
+               return false;
+
+       pmus->type.type = type;
+       if (domain_type_init(&pmus->type)) {
+               kfree(pmus);
+               return false;
+       }
+       pmus->event_max = max;
+       pmus->msrs = msr;
+       pmus->attrs = attrs;
+
+       cstate_pmus[type] = pmus;
+
+       return true;
 }
 
 static int __init cstate_probe(const struct cstate_model *cm)
 {
+       bool found = false;
+       enum domain_types i;
+
        /* SLM has different MSR for PKG C6 */
        if (cm->quirks & SLM_PKG_C6_USE_C7_MSR)
                pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY;
@@ -624,58 +630,79 @@ static int __init cstate_probe(const struct cstate_model 
*cm)
                pkg_msr[PERF_CSTATE_CORE_C6_RES].msr = 
MSR_KNL_CORE_C6_RESIDENCY;
 
 
-       has_cstate_core = cstate_probe_msr(cm->core_events,
-                                          PERF_CSTATE_CORE_EVENT_MAX,
-                                          core_msr, core_events_attrs);
+       for (i = 0; i < DOMAIN_TYPE_MAX; i++) {
+               if (!cm->events[i])
+                       continue;
 
-       has_cstate_pkg = cstate_probe_msr(cm->pkg_events,
-                                         PERF_CSTATE_PKG_EVENT_MAX,
-                                         pkg_msr, pkg_events_attrs);
-
-       return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV;
+               if (cstate_probe_msr(cm->events[i], i))
+                       found = true;
+       }
+       return found ? 0 : -ENODEV;
 }
 
 static inline void cstate_cleanup(void)
 {
+       int i;
+
        cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_ONLINE);
        cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_STARTING);
 
-       if (has_cstate_core)
-               perf_pmu_unregister(&cstate_core_pmu);
-
-       if (has_cstate_pkg)
-               perf_pmu_unregister(&cstate_pkg_pmu);
+       for (i = 0; i < DOMAIN_TYPE_MAX; i++) {
+               if (!cstate_pmus[i])
+                       continue;
+               perf_pmu_unregister(&cstate_pmus[i]->pmu);
+               kfree(cstate_pmus[i]);
+               cstate_pmus[i] = NULL;
+       }
 }
 
 static int __init cstate_init(void)
 {
-       int err;
+       struct pmu *pmu;
+       char name[DOMAIN_NAME_LEN];
+       int i, err = 0;
 
        cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_STARTING,
                          "perf/x86/cstate:starting", cstate_cpu_init, NULL);
        cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_ONLINE,
                          "perf/x86/cstate:online", NULL, cstate_cpu_exit);
 
-       if (has_cstate_core) {
-               err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, 
-1);
-               if (err) {
-                       has_cstate_core = false;
-                       pr_info("Failed to register cstate core pmu\n");
-                       cstate_cleanup();
-                       return err;
+       for (i = 0; i < DOMAIN_TYPE_MAX; i++) {
+               if (!cstate_pmus[i])
+                       continue;
+               pmu = &cstate_pmus[i]->pmu;
+
+               if (i == PACKAGE_DOMAIN)
+                       pmu->attr_groups = pkg_attr_groups;
+               else if (i == CORE_DOMAIN)
+                       pmu->attr_groups = core_attr_groups;
+
+               pmu->task_ctx_nr = perf_invalid_context;
+               pmu->event_init = cstate_pmu_event_init;
+               pmu->add = cstate_pmu_event_add;
+               pmu->del = cstate_pmu_event_del;
+               pmu->start = cstate_pmu_event_start;
+               pmu->stop = cstate_pmu_event_stop;
+               pmu->read = cstate_pmu_event_update;
+               pmu->capabilities = PERF_PMU_CAP_NO_INTERRUPT;
+               pmu->module = THIS_MODULE;
+
+               err = snprintf(name, DOMAIN_NAME_LEN, "cstate_%s",
+                              cstate_pmus[i]->type.postfix);
+               if (err < 0) {
+                       kfree(cstate_pmus[i]);
+                       cstate_pmus[i] = NULL;
+                       continue;
                }
-       }
-
-       if (has_cstate_pkg) {
-               err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, 
-1);
+               err = perf_pmu_register(pmu, name, -1);
                if (err) {
-                       has_cstate_pkg = false;
-                       pr_info("Failed to register cstate pkg pmu\n");
-                       cstate_cleanup();
-                       return err;
+                       kfree(cstate_pmus[i]);
+                       cstate_pmus[i] = NULL;
+                       pr_info("Failed to register %s pmu\n", name);
                }
        }
-       return 0;
+
+       return err;
 }
 
 static int __init cstate_pmu_init(void)
-- 
2.7.4

Reply via email to