Re: [PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-09-06 Thread Dietmar Eggemann

On 09/06/2018 07:09 AM, Quentin Perret wrote:

Hi Dietmar,

On Wednesday 05 Sep 2018 at 23:56:43 (-0700), Dietmar Eggemann wrote:

On 08/20/2018 02:44 AM, Quentin Perret wrote:

Expose the Energy Model (read-only) of all performance domains in sysfs
for convenience. To do so, add a kobject to the CPU subsystem under the
umbrella of which a kobject for each performance domain is attached.

The resulting hierarchy is as follows for a platform with two
performance domains for example:

 /sys/devices/system/cpu/energy_model
 ├── pd0
 │   ├── cost
 │   ├── cpus
 │   ├── frequency
 │   └── power


cpus (cpumask of the perf domain), frequency (OPP's of the perf domain) and
power (values at those OPP's) are somehow easy to grasp, cost is definitely
not.

You have this nice description in em_pd_energy() what cost actually is.
IMHO, might be worth repeating this at least in the patch header here.


Hmm, this patch introduces the sysfs interface, not the 'cost' field
itself. As long as 'cost' is documented in the patch that introduces it
we should be good no ? I mean this patch header tells you _where_ the
fields of the structure are exposed. _What_ the structure is all about
is a different story.


Mmmh, so maybe a EAS related documentation file explaining this 
interface as well, which can be introduced later is the solution here?


I'm just not 100% convinced that those cost values are self-explanatory 
like the other three items:


root@h960:~# ls /sys/devices/system/cpu/energy_model/pd0/
cost
cpus
frequency
power

root@h960:~# cat /sys/devices/system/cpu/energy_model/pd0/*
96 129 163 201 245
0-3
533000 999000 1402000 1709000 1844000
28 70 124 187 245


But yeah, in any case, a reminder shouldn't hurt I guess, if you really
want one :-)


Nothing which should hold this patch-set back though.


Re: [PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-09-06 Thread Dietmar Eggemann

On 09/06/2018 07:09 AM, Quentin Perret wrote:

Hi Dietmar,

On Wednesday 05 Sep 2018 at 23:56:43 (-0700), Dietmar Eggemann wrote:

On 08/20/2018 02:44 AM, Quentin Perret wrote:

Expose the Energy Model (read-only) of all performance domains in sysfs
for convenience. To do so, add a kobject to the CPU subsystem under the
umbrella of which a kobject for each performance domain is attached.

The resulting hierarchy is as follows for a platform with two
performance domains for example:

 /sys/devices/system/cpu/energy_model
 ├── pd0
 │   ├── cost
 │   ├── cpus
 │   ├── frequency
 │   └── power


cpus (cpumask of the perf domain), frequency (OPP's of the perf domain) and
power (values at those OPP's) are somehow easy to grasp, cost is definitely
not.

You have this nice description in em_pd_energy() what cost actually is.
IMHO, might be worth repeating this at least in the patch header here.


Hmm, this patch introduces the sysfs interface, not the 'cost' field
itself. As long as 'cost' is documented in the patch that introduces it
we should be good no ? I mean this patch header tells you _where_ the
fields of the structure are exposed. _What_ the structure is all about
is a different story.


Mmmh, so maybe a EAS related documentation file explaining this 
interface as well, which can be introduced later is the solution here?


I'm just not 100% convinced that those cost values are self-explanatory 
like the other three items:


root@h960:~# ls /sys/devices/system/cpu/energy_model/pd0/
cost
cpus
frequency
power

root@h960:~# cat /sys/devices/system/cpu/energy_model/pd0/*
96 129 163 201 245
0-3
533000 999000 1402000 1709000 1844000
28 70 124 187 245


But yeah, in any case, a reminder shouldn't hurt I guess, if you really
want one :-)


Nothing which should hold this patch-set back though.


Re: [PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-09-06 Thread Quentin Perret
Hi Dietmar,

On Wednesday 05 Sep 2018 at 23:56:43 (-0700), Dietmar Eggemann wrote:
> On 08/20/2018 02:44 AM, Quentin Perret wrote:
> > Expose the Energy Model (read-only) of all performance domains in sysfs
> > for convenience. To do so, add a kobject to the CPU subsystem under the
> > umbrella of which a kobject for each performance domain is attached.
> > 
> > The resulting hierarchy is as follows for a platform with two
> > performance domains for example:
> > 
> > /sys/devices/system/cpu/energy_model
> > ├── pd0
> > │   ├── cost
> > │   ├── cpus
> > │   ├── frequency
> > │   └── power
> 
> cpus (cpumask of the perf domain), frequency (OPP's of the perf domain) and
> power (values at those OPP's) are somehow easy to grasp, cost is definitely
> not.
> 
> You have this nice description in em_pd_energy() what cost actually is.
> IMHO, might be worth repeating this at least in the patch header here.

Hmm, this patch introduces the sysfs interface, not the 'cost' field
itself. As long as 'cost' is documented in the patch that introduces it
we should be good no ? I mean this patch header tells you _where_ the
fields of the structure are exposed. _What_ the structure is all about
is a different story.

But yeah, in any case, a reminder shouldn't hurt I guess, if you really
want one :-)

Thanks,
Quentin


Re: [PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-09-06 Thread Quentin Perret
Hi Dietmar,

On Wednesday 05 Sep 2018 at 23:56:43 (-0700), Dietmar Eggemann wrote:
> On 08/20/2018 02:44 AM, Quentin Perret wrote:
> > Expose the Energy Model (read-only) of all performance domains in sysfs
> > for convenience. To do so, add a kobject to the CPU subsystem under the
> > umbrella of which a kobject for each performance domain is attached.
> > 
> > The resulting hierarchy is as follows for a platform with two
> > performance domains for example:
> > 
> > /sys/devices/system/cpu/energy_model
> > ├── pd0
> > │   ├── cost
> > │   ├── cpus
> > │   ├── frequency
> > │   └── power
> 
> cpus (cpumask of the perf domain), frequency (OPP's of the perf domain) and
> power (values at those OPP's) are somehow easy to grasp, cost is definitely
> not.
> 
> You have this nice description in em_pd_energy() what cost actually is.
> IMHO, might be worth repeating this at least in the patch header here.

Hmm, this patch introduces the sysfs interface, not the 'cost' field
itself. As long as 'cost' is documented in the patch that introduces it
we should be good no ? I mean this patch header tells you _where_ the
fields of the structure are exposed. _What_ the structure is all about
is a different story.

But yeah, in any case, a reminder shouldn't hurt I guess, if you really
want one :-)

Thanks,
Quentin


Re: [PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-09-06 Thread Dietmar Eggemann

On 08/20/2018 02:44 AM, Quentin Perret wrote:

Expose the Energy Model (read-only) of all performance domains in sysfs
for convenience. To do so, add a kobject to the CPU subsystem under the
umbrella of which a kobject for each performance domain is attached.

The resulting hierarchy is as follows for a platform with two
performance domains for example:

/sys/devices/system/cpu/energy_model
├── pd0
│   ├── cost
│   ├── cpus
│   ├── frequency
│   └── power


cpus (cpumask of the perf domain), frequency (OPP's of the perf domain) 
and power (values at those OPP's) are somehow easy to grasp, cost is 
definitely not.


You have this nice description in em_pd_energy() what cost actually is. 
IMHO, might be worth repeating this at least in the patch header here.


[...]


Re: [PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-09-06 Thread Dietmar Eggemann

On 08/20/2018 02:44 AM, Quentin Perret wrote:

Expose the Energy Model (read-only) of all performance domains in sysfs
for convenience. To do so, add a kobject to the CPU subsystem under the
umbrella of which a kobject for each performance domain is attached.

The resulting hierarchy is as follows for a platform with two
performance domains for example:

/sys/devices/system/cpu/energy_model
├── pd0
│   ├── cost
│   ├── cpus
│   ├── frequency
│   └── power


cpus (cpumask of the perf domain), frequency (OPP's of the perf domain) 
and power (values at those OPP's) are somehow easy to grasp, cost is 
definitely not.


You have this nice description in em_pd_energy() what cost actually is. 
IMHO, might be worth repeating this at least in the patch header here.


[...]


[PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-08-20 Thread Quentin Perret
Expose the Energy Model (read-only) of all performance domains in sysfs
for convenience. To do so, add a kobject to the CPU subsystem under the
umbrella of which a kobject for each performance domain is attached.

The resulting hierarchy is as follows for a platform with two
performance domains for example:

   /sys/devices/system/cpu/energy_model
   ├── pd0
   │   ├── cost
   │   ├── cpus
   │   ├── frequency
   │   └── power
   └── pd4
   ├── cost
   ├── cpus
   ├── frequency
   └── power

In this implementation, the kobject abstraction is only used as a
convenient way of exposing data to sysfs. However, it could also be
used in the future to allocate and release performance domains in a more
dynamic way using reference counting.

Cc: Peter Zijlstra 
Cc: "Rafael J. Wysocki" 
Signed-off-by: Quentin Perret 
---
 include/linux/energy_model.h |  1 +
 kernel/power/energy_model.c  | 90 
 2 files changed, 91 insertions(+)

diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index b89b5596c976..5cfdfa25bf0f 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -19,6 +19,7 @@ struct em_cap_state {
 struct em_perf_domain {
struct em_cap_state *table; /* Capacity states, in ascending order. */
int nr_cap_states;
+   struct kobject kobj;
unsigned long cpus[0]; /* CPUs of the frequency domain. */
 };
 
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 2aa6f94343d0..a25d23d73d4e 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -23,6 +23,82 @@ static DEFINE_PER_CPU(struct em_perf_domain *, em_data);
  */
 static DEFINE_MUTEX(em_pd_mutex);
 
+static struct kobject *em_kobject;
+
+/* Getters for the attributes of em_perf_domain objects */
+struct em_pd_attr {
+   struct attribute attr;
+   ssize_t (*show)(struct em_perf_domain *pd, char *buf);
+   ssize_t (*store)(struct em_perf_domain *pd, const char *buf, size_t s);
+};
+
+#define EM_ATTR_LEN 13
+#define show_table_attr(_attr) \
+static ssize_t show_##_attr(struct em_perf_domain *pd, char *buf) \
+{ \
+   ssize_t cnt = 0; \
+   int i; \
+   for (i = 0; i < pd->nr_cap_states; i++) { \
+   if (cnt >= (ssize_t) (PAGE_SIZE / sizeof(char) \
+ - (EM_ATTR_LEN + 2))) \
+   goto out; \
+   cnt += scnprintf([cnt], EM_ATTR_LEN + 1, "%lu ", \
+pd->table[i]._attr); \
+   } \
+out: \
+   cnt += sprintf([cnt], "\n"); \
+   return cnt; \
+}
+
+show_table_attr(power);
+show_table_attr(frequency);
+show_table_attr(cost);
+
+static ssize_t show_cpus(struct em_perf_domain *pd, char *buf)
+{
+   return sprintf(buf, "%*pbl\n", cpumask_pr_args(to_cpumask(pd->cpus)));
+}
+
+#define pd_attr(_name) em_pd_##_name##_attr
+#define define_pd_attr(_name) static struct em_pd_attr pd_attr(_name) = \
+   __ATTR(_name, 0444, show_##_name, NULL)
+
+define_pd_attr(power);
+define_pd_attr(frequency);
+define_pd_attr(cost);
+define_pd_attr(cpus);
+
+static struct attribute *em_pd_default_attrs[] = {
+   _attr(power).attr,
+   _attr(frequency).attr,
+   _attr(cost).attr,
+   _attr(cpus).attr,
+   NULL
+};
+
+#define to_pd(k) container_of(k, struct em_perf_domain, kobj)
+#define to_pd_attr(a) container_of(a, struct em_pd_attr, attr)
+
+static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+   struct em_perf_domain *pd = to_pd(kobj);
+   struct em_pd_attr *pd_attr = to_pd_attr(attr);
+   ssize_t ret;
+
+   ret = pd_attr->show(pd, buf);
+
+   return ret;
+}
+
+static const struct sysfs_ops em_pd_sysfs_ops = {
+   .show   = show,
+};
+
+static struct kobj_type ktype_em_pd = {
+   .sysfs_ops  = _pd_sysfs_ops,
+   .default_attrs  = em_pd_default_attrs,
+};
+
 static struct em_perf_domain *em_create_pd(cpumask_t *span, int nr_states,
struct em_data_callback *cb)
 {
@@ -102,6 +178,11 @@ static struct em_perf_domain *em_create_pd(cpumask_t 
*span, int nr_states,
pd->nr_cap_states = nr_states;
cpumask_copy(to_cpumask(pd->cpus), span);
 
+   ret = kobject_init_and_add(>kobj, _em_pd, em_kobject,
+  "pd%u", cpu);
+   if (ret)
+   pr_err("pd%d: failed kobject_init_and_add(): %d\n", cpu, ret);
+
return pd;
 
 free_cs_table:
@@ -155,6 +236,15 @@ int em_register_perf_domain(cpumask_t *span, unsigned int 
nr_states,
 */
mutex_lock(_pd_mutex);
 
+   if (!em_kobject) {
+   em_kobject = kobject_create_and_add("energy_model",
+   _subsys.dev_root->kobj);
+   if (!em_kobject) {
+   ret = -ENODEV;
+   goto unlock;
+   }
+   }
+

[PATCH v6 04/14] PM / EM: Expose the Energy Model in sysfs

2018-08-20 Thread Quentin Perret
Expose the Energy Model (read-only) of all performance domains in sysfs
for convenience. To do so, add a kobject to the CPU subsystem under the
umbrella of which a kobject for each performance domain is attached.

The resulting hierarchy is as follows for a platform with two
performance domains for example:

   /sys/devices/system/cpu/energy_model
   ├── pd0
   │   ├── cost
   │   ├── cpus
   │   ├── frequency
   │   └── power
   └── pd4
   ├── cost
   ├── cpus
   ├── frequency
   └── power

In this implementation, the kobject abstraction is only used as a
convenient way of exposing data to sysfs. However, it could also be
used in the future to allocate and release performance domains in a more
dynamic way using reference counting.

Cc: Peter Zijlstra 
Cc: "Rafael J. Wysocki" 
Signed-off-by: Quentin Perret 
---
 include/linux/energy_model.h |  1 +
 kernel/power/energy_model.c  | 90 
 2 files changed, 91 insertions(+)

diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h
index b89b5596c976..5cfdfa25bf0f 100644
--- a/include/linux/energy_model.h
+++ b/include/linux/energy_model.h
@@ -19,6 +19,7 @@ struct em_cap_state {
 struct em_perf_domain {
struct em_cap_state *table; /* Capacity states, in ascending order. */
int nr_cap_states;
+   struct kobject kobj;
unsigned long cpus[0]; /* CPUs of the frequency domain. */
 };
 
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index 2aa6f94343d0..a25d23d73d4e 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -23,6 +23,82 @@ static DEFINE_PER_CPU(struct em_perf_domain *, em_data);
  */
 static DEFINE_MUTEX(em_pd_mutex);
 
+static struct kobject *em_kobject;
+
+/* Getters for the attributes of em_perf_domain objects */
+struct em_pd_attr {
+   struct attribute attr;
+   ssize_t (*show)(struct em_perf_domain *pd, char *buf);
+   ssize_t (*store)(struct em_perf_domain *pd, const char *buf, size_t s);
+};
+
+#define EM_ATTR_LEN 13
+#define show_table_attr(_attr) \
+static ssize_t show_##_attr(struct em_perf_domain *pd, char *buf) \
+{ \
+   ssize_t cnt = 0; \
+   int i; \
+   for (i = 0; i < pd->nr_cap_states; i++) { \
+   if (cnt >= (ssize_t) (PAGE_SIZE / sizeof(char) \
+ - (EM_ATTR_LEN + 2))) \
+   goto out; \
+   cnt += scnprintf([cnt], EM_ATTR_LEN + 1, "%lu ", \
+pd->table[i]._attr); \
+   } \
+out: \
+   cnt += sprintf([cnt], "\n"); \
+   return cnt; \
+}
+
+show_table_attr(power);
+show_table_attr(frequency);
+show_table_attr(cost);
+
+static ssize_t show_cpus(struct em_perf_domain *pd, char *buf)
+{
+   return sprintf(buf, "%*pbl\n", cpumask_pr_args(to_cpumask(pd->cpus)));
+}
+
+#define pd_attr(_name) em_pd_##_name##_attr
+#define define_pd_attr(_name) static struct em_pd_attr pd_attr(_name) = \
+   __ATTR(_name, 0444, show_##_name, NULL)
+
+define_pd_attr(power);
+define_pd_attr(frequency);
+define_pd_attr(cost);
+define_pd_attr(cpus);
+
+static struct attribute *em_pd_default_attrs[] = {
+   _attr(power).attr,
+   _attr(frequency).attr,
+   _attr(cost).attr,
+   _attr(cpus).attr,
+   NULL
+};
+
+#define to_pd(k) container_of(k, struct em_perf_domain, kobj)
+#define to_pd_attr(a) container_of(a, struct em_pd_attr, attr)
+
+static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+   struct em_perf_domain *pd = to_pd(kobj);
+   struct em_pd_attr *pd_attr = to_pd_attr(attr);
+   ssize_t ret;
+
+   ret = pd_attr->show(pd, buf);
+
+   return ret;
+}
+
+static const struct sysfs_ops em_pd_sysfs_ops = {
+   .show   = show,
+};
+
+static struct kobj_type ktype_em_pd = {
+   .sysfs_ops  = _pd_sysfs_ops,
+   .default_attrs  = em_pd_default_attrs,
+};
+
 static struct em_perf_domain *em_create_pd(cpumask_t *span, int nr_states,
struct em_data_callback *cb)
 {
@@ -102,6 +178,11 @@ static struct em_perf_domain *em_create_pd(cpumask_t 
*span, int nr_states,
pd->nr_cap_states = nr_states;
cpumask_copy(to_cpumask(pd->cpus), span);
 
+   ret = kobject_init_and_add(>kobj, _em_pd, em_kobject,
+  "pd%u", cpu);
+   if (ret)
+   pr_err("pd%d: failed kobject_init_and_add(): %d\n", cpu, ret);
+
return pd;
 
 free_cs_table:
@@ -155,6 +236,15 @@ int em_register_perf_domain(cpumask_t *span, unsigned int 
nr_states,
 */
mutex_lock(_pd_mutex);
 
+   if (!em_kobject) {
+   em_kobject = kobject_create_and_add("energy_model",
+   _subsys.dev_root->kobj);
+   if (!em_kobject) {
+   ret = -ENODEV;
+   goto unlock;
+   }
+   }
+