From: Juri Lelli <hidden> Date: 2016-06-15 10:18:31
Hi all,
this is take 5 of "CPUs capacity information for heterogeneous systems"
patchset [1] (please refer to previous postings to get some context). Apologies
for taking so much time before posting a new version, I've been busy working on
other (related :-)) stuff.
Anyway, after v4 review we seem to still agree that a new DT binding is
reasonable (as it is only a first-order approximation that it is useful to get
acceptable good behaviours during boot and early execution and it can be then
overwritten using the sysfs interface if needed). However, Rob asked for more
precision in defining the binding and Mark, Sai and Vincent seem to agree that
we should extract the frequency component from the values we put in DT.
In this new version I made several changes:
- first patch of v4 is now mainline (but we've got a new one, see below)
- clearly state that Dhrystone is used to get this first order approx values
- the binding is now called capacity-dmips-mhz (suggestions for better naming
are welcome!)
- capacity-dmips-mhz have to be calculated by:
+ running dhrystone at max freq on each cpu (in practice it can be run just
on the first cpu of each cluster and at any frequency)
+ collect DMIPS/MHz by dividing the score by the frequency at which it has
been run
+ normalize DMIPS/MHz and put such values in the DT (we've got a new patch
in the series for JUNO R2)
- at boot we use a cpufreq callback to be able to multiply back capacity-dmips
-mhz for policy->max and then normalize w.r.t. 1024
- if cpufreq is not in the mix, we use capacity-dmips-mhz values as they are
(since we don't know at which frequency we are running at, we assume that
CPUs run all at the same frequency)
I guess at least some more comments in the code and some more lines in
Documentation will help, but I'll defer that to v6: I'd like to see if we can
first reach an agreement.
Patches high level description:
o 01/08 introduces documentation for the new optional DT binding
o [02-06]/08 add cpu-capacity attribute to TC2, Juno and Juno r2 DTs and
provide parsing of such information at boot time
o [07-08]/08 introduce sysfs attribute
The patchset is based on top of mainline as of today (4.7-rc3).
In case you would like to test this out, I pushed a branch here:
git://linux-arm.org/linux-jl.git upstream/default_caps_v5
This branch contains additional patches, useful to better understand how CPU
capacity information is actually used by the scheduler. However, discussion
regarding these additional patches is outside the scope of this posting.
Best,
- Juri
Juri Lelli (8):
Documentation: arm: define DT cpu capacity-dmips-mhz bindings
arm: parse cpu capacity-dmips-mhz from DT
arm, dts: add TC2 cpu capacity-dmips-mhz information
arm64: parse cpu capacity-dmips-mhz from DT
arm64, dts: add Juno cpu capacity-dmips-mhz information
arm64, dts: add Juno r2 cpu capacity-dmips-mhz information
arm: add sysfs cpu_capacity attribute
arm64: add sysfs cpu_capacity attribute
.../devicetree/bindings/arm/cpu-capacity.txt | 236 +++++++++++++++++++++
Documentation/devicetree/bindings/arm/cpus.txt | 10 +
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 5 +
arch/arm/kernel/topology.c | 213 ++++++++++++++++++-
arch/arm64/boot/dts/arm/juno-r2.dts | 6 +
arch/arm64/boot/dts/arm/juno.dts | 6 +
arch/arm64/kernel/topology.c | 213 +++++++++++++++++++
7 files changed, 688 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt
--
2.7.0
From: Juri Lelli <hidden> Date: 2016-06-15 10:18:38
ARM systems may be configured to have cpus with different power/performance
characteristics within the same chip. In this case, additional information
has to be made available to the kernel (the scheduler in particular) for it
to be aware of such differences and take decisions accordingly.
Therefore, this patch aims at standardizing cpu capacities device tree
bindings for ARM platforms. Bindings define cpu capacity-dmips-mhz
parameter, to allow operating systems to retrieve such information from
the device tree and initialize related kernel structures, paving the way
for common code in the kernel to deal with heterogeneity.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <redacted>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <redacted>
Cc: Kumar Gala <redacted>
Cc: Maxime Ripard <redacted>
Cc: Olof Johansson <redacted>
Cc: Gregory CLEMENT <redacted>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Linus Walleij <redacted>
Cc: Chen-Yu Tsai <redacted>
Cc: Thomas Petazzoni <redacted>
Cc: devicetree at vger.kernel.org
Signed-off-by: Juri Lelli <redacted>
---
Changes from v1:
- removed section regarding capacity-scale
- added information regarding normalization
Changes from v4:
- binding changed to capacity-dmips-mhz
- sections and changelod updated accordingly
---
.../devicetree/bindings/arm/cpu-capacity.txt | 236 +++++++++++++++++++++
Documentation/devicetree/bindings/arm/cpus.txt | 10 +
2 files changed, 246 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt
@@ -0,0 +1,236 @@+==========================================+ARM CPUs capacity bindings+==========================================++==========================================+1 - Introduction+==========================================++ARM systems may be configured to have cpus with different power/performance+characteristics within the same chip. In this case, additional information+has to be made available to the kernel (the scheduler in particular) for+it to be aware of such differences and take decisions accordingly.++==========================================+2 - CPU capacity definition+==========================================++CPU capacity is a number that provides the scheduler information about CPUs+heterogeneity. Such heterogeneity can come from micro-architectural differences+(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run+(e.g., SMP systems with multiple frequency domains). Heterogeneity in this+context is about differing performance characteristics; this binding tries to+capture a first-order approximation of the relative performance of CPUs.++CPU capacities are obtained by running a suitable benchmark. This binding makes+no aspersions on the validity or suitability of any particular benchmark, the+final capacity should, however, be:++* A "single-threaded" or CPU affine benchmark+* Divided by the running frequency of the CPU executing the benchmark+* Not subject to dynamic frequency scaling of the CPU++For the time being we however advise usage of the Dhrystone benchmark. What+above thus becomes:++CPU capacities are obtained by running the Dhrystone benchmark on each CPU at+max frequency. The obtained DMIPS score is then divided by the frequency (in+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.+Such values are then normalized w.r.t. the highest score obtained in the+system.++==========================================+3 - capacity-dmips-mhz+==========================================++capacity-dmips-mhz is an optional cpu node [1] property: u32 value+representing CPU capacity expressed in normalized DMIPS/MHz. At boot time, the+maximum frequency available to the cpu is then used to calculate the capacity+value internally used by the kernel.++capacity-dmips-mhz property is all-or-nothing: if it is specified for a cpu+node, it has to be specified for every other cpu nodes, or the system will+fall back to the default capacity value for every CPU. If cpufreq is not+available, final capacities are calculated by directly using capacity-dmips-+mhz values (normalized w.r.t. the highest value found while parsing the DT).++===========================================+4 - Examples+===========================================++Example 1 (ARM 64-bit, 6-cpu system, two clusters):+capacities-dmips-mhz are scaled w.r.t. 1024 (cpu at 0 and cpu at 1)+supposing cluster0 at max-freq=1100 and custer1 at max-freq=850,+final capacities are 1024 for cluster0 and 446 for cluster1++cpus {+ #address-cells = <2>;+ #size-cells = <0>;++ cpu-map {+ cluster0 {+ core0 {+ cpu = <&A57_0>;+ };+ core1 {+ cpu = <&A57_1>;+ };+ };++ cluster1 {+ core0 {+ cpu = <&A53_0>;+ };+ core1 {+ cpu = <&A53_1>;+ };+ core2 {+ cpu = <&A53_2>;+ };+ core3 {+ cpu = <&A53_3>;+ };+ };+ };++ idle-states {+ entry-method = "arm,psci";++ CPU_SLEEP_0: cpu-sleep-0 {+ compatible = "arm,idle-state";+ arm,psci-suspend-param = <0x0010000>;+ local-timer-stop;+ entry-latency-us = <100>;+ exit-latency-us = <250>;+ min-residency-us = <150>;+ };++ CLUSTER_SLEEP_0: cluster-sleep-0 {+ compatible = "arm,idle-state";+ arm,psci-suspend-param = <0x1010000>;+ local-timer-stop;+ entry-latency-us = <800>;+ exit-latency-us = <700>;+ min-residency-us = <2500>;+ };+ };++ A57_0: cpu at 0 {+ compatible = "arm,cortex-a57","arm,armv8";+ reg = <0x0 0x0>;+ device_type = "cpu";+ enable-method = "psci";+ next-level-cache = <&A57_L2>;+ clocks = <&scpi_dvfs 0>;+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;+ capacity-dmips-mhz = <1024>;+ };++ A57_1: cpu at 1 {+ compatible = "arm,cortex-a57","arm,armv8";+ reg = <0x0 0x1>;+ device_type = "cpu";+ enable-method = "psci";+ next-level-cache = <&A57_L2>;+ clocks = <&scpi_dvfs 0>;+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;+ capacity-dmips-mhz = <1024>;+ };++ A53_0: cpu at 100 {+ compatible = "arm,cortex-a53","arm,armv8";+ reg = <0x0 0x100>;+ device_type = "cpu";+ enable-method = "psci";+ next-level-cache = <&A53_L2>;+ clocks = <&scpi_dvfs 1>;+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;+ capacity-dmips-mhz = <578>;+ };++ A53_1: cpu at 101 {+ compatible = "arm,cortex-a53","arm,armv8";+ reg = <0x0 0x101>;+ device_type = "cpu";+ enable-method = "psci";+ next-level-cache = <&A53_L2>;+ clocks = <&scpi_dvfs 1>;+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;+ capacity-dmips-mhz = <578>;+ };++ A53_2: cpu at 102 {+ compatible = "arm,cortex-a53","arm,armv8";+ reg = <0x0 0x102>;+ device_type = "cpu";+ enable-method = "psci";+ next-level-cache = <&A53_L2>;+ clocks = <&scpi_dvfs 1>;+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;+ capacity-dmips-mhz = <578>;+ };++ A53_3: cpu at 103 {+ compatible = "arm,cortex-a53","arm,armv8";+ reg = <0x0 0x103>;+ device_type = "cpu";+ enable-method = "psci";+ next-level-cache = <&A53_L2>;+ clocks = <&scpi_dvfs 1>;+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;+ capacity-dmips-mhz = <578>;+ };++ A57_L2: l2-cache0 {+ compatible = "cache";+ };++ A53_L2: l2-cache1 {+ compatible = "cache";+ };+};++Example 2 (ARM 32-bit, 4-cpu system, two clusters,+ cpus 0,1 at 1GHz, cpus 2,3 at 500MHz):+capacities-dmips-mhz are scaled w.r.t. 2 (cpu at 0 and cpu at 1), this means that first+cpu at 0 and cpu at 1 are twice fast than cpu at 2 and cpu at 3 (at the same frequency)++cpus {+ #address-cells = <1>;+ #size-cells = <0>;++ cpu0: cpu at 0 {+ device_type = "cpu";+ compatible = "arm,cortex-a15";+ reg = <0>;+ capacity-dmips-mhz = <2>;+ };++ cpu1: cpu at 1 {+ device_type = "cpu";+ compatible = "arm,cortex-a15";+ reg = <1>;+ capacity-dmips-mhz = <2>;+ };++ cpu2: cpu at 2 {+ device_type = "cpu";+ compatible = "arm,cortex-a15";+ reg = <0x100>;+ capacity-dmips-mhz = <1>;+ };++ cpu3: cpu at 3 {+ device_type = "cpu";+ compatible = "arm,cortex-a15";+ reg = <0x101>;+ capacity-dmips-mhz = <1>;+ };+};++===========================================+5 - References+===========================================++[1] ARM Linux Kernel documentation - CPUs bindings+ Documentation/devicetree/bindings/arm/cpus.txt
@@ -238,6 +238,14 @@ nodes to be present and contain the properties described below. # List of phandles to idle state nodes supported by this cpu [3].+ - capacity-dmips-mhz+ Usage: Optional+ Value type: <u32>+ Definition:+ # u32 value representing CPU capacity [3] in+ DMIPS/MHz, relative to highest capacity-dmips-mhz+ in the system.+ - rockchip,pmu Usage: optional for systems that have an "enable-method" property value of "rockchip,rk3066-smp"
@@ -461,3 +469,5 @@ cpus { [2] arm/msm/qcom,kpss-acc.txt [3] ARM Linux kernel documentation - idle states bindings Documentation/devicetree/bindings/arm/idle-states.txt+[3] ARM Linux kernel documentation - cpu capacity bindings+ Documentation/devicetree/bindings/arm/cpu-capacity.txt
From: Juri Lelli <hidden> Date: 2016-06-15 10:18:46
With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
can now be calculated from values extracted from DT and information
coming from cpufreq. Add parsing of DT information at boot time, and
complement it with cpufreq information. Also, store such information
using per CPU variables, as we do for arm.
Caveat: the information provided by this patch will start to be used in
the future. We need to #define arch_scale_cpu_capacity to something
provided in arch, so that scheduler's default implementation (which gets
used if arch_scale_cpu_capacity is not defined) is overwritten.
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <redacted>
Cc: Mark Brown <redacted>
Cc: Sudeep Holla <redacted>
Signed-off-by: Juri Lelli <redacted>
---
Changes from v1:
- normalize w.r.t. highest capacity found in DT
- bailout conditions (all-or-nothing)
Changes from v4:
- parsing modified to reflect change in binding (capacity-dmips-mhz)
---
arch/arm64/kernel/topology.c | 145 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 145 insertions(+)
@@ -19,10 +19,152 @@#include<linux/nodemask.h>#include<linux/of.h>#include<linux/sched.h>+#include<linux/slab.h>+#include<linux/cpufreq.h>#include<asm/cputype.h>#include<asm/topology.h>+staticDEFINE_PER_CPU(unsignedlong,cpu_scale)=SCHED_CAPACITY_SCALE;++unsignedlongarch_scale_cpu_capacity(structsched_domain*sd,intcpu)+{+returnper_cpu(cpu_scale,cpu);+}++staticvoidset_capacity_scale(unsignedintcpu,unsignedlongcapacity)+{+per_cpu(cpu_scale,cpu)=capacity;+}++staticu32capacity_scale;+staticu32*raw_capacity;+staticboolcap_parsing_failed;++staticvoid__initparse_cpu_capacity(structdevice_node*cpu_node,intcpu)+{+intret;+u32cpu_capacity;++if(cap_parsing_failed)+return;++ret=of_property_read_u32(cpu_node,+"capacity-dmips-mhz",+&cpu_capacity);+if(!ret){+if(!raw_capacity){+raw_capacity=kzalloc(sizeof(*raw_capacity)*+num_possible_cpus(),GFP_KERNEL);+if(!raw_capacity){+pr_err("cpu_capacity: failed to allocate memory"+" for raw capacities\n");+cap_parsing_failed=true;+return;+}+}+capacity_scale=max(cpu_capacity,capacity_scale);+raw_capacity[cpu]=cpu_capacity;+pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",+cpu_node->full_name,raw_capacity[cpu]);+}else{+pr_err("cpu_capacity: missing %s raw capacity "+"(fallback to 1024 for all CPUs)\n",+cpu_node->full_name);+cap_parsing_failed=true;+kfree(raw_capacity);+}+}++staticvoidnormalize_cpu_capacity(void)+{+u64capacity;+intcpu;++if(WARN_ON(!raw_capacity)||cap_parsing_failed)+return;++pr_debug("cpu_capacity: capacity_scale=%u\n",capacity_scale);+for_each_possible_cpu(cpu){+pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",+cpu,raw_capacity[cpu]);+capacity=(raw_capacity[cpu]<<SCHED_CAPACITY_SHIFT)+/capacity_scale;+set_capacity_scale(cpu,capacity);+pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",+cpu,arch_scale_cpu_capacity(NULL,cpu));+}+}++#ifdef CONFIG_CPU_FREQ+staticcpumask_var_tcpus_to_visit;+staticboolcap_parsing_done;++staticint+init_cpu_capacity_callback(structnotifier_block*nb,+unsignedlongval,+void*data)+{+structcpufreq_policy*policy=data;+intcpu;++if(cap_parsing_failed||cap_parsing_done)+return0;++switch(val){+caseCPUFREQ_NOTIFY:+pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] "+"(to_visit=%*pbl)\n",+cpumask_pr_args(policy->related_cpus),+cpumask_pr_args(cpus_to_visit));+cpumask_andnot(cpus_to_visit,+cpus_to_visit,+policy->related_cpus);+for_each_cpu(cpu,policy->related_cpus){+raw_capacity[cpu]=arch_scale_cpu_capacity(NULL,cpu)*+policy->max/1000UL;+capacity_scale=max(raw_capacity[cpu],capacity_scale);+}+if(cpumask_empty(cpus_to_visit)){+normalize_cpu_capacity();+kfree(raw_capacity);+pr_debug("cpu_capacity: parsing done\n");+cap_parsing_done=true;+}+}+return0;+}++staticstructnotifier_blockinit_cpu_capacity_notifier={+.notifier_call=init_cpu_capacity_callback,+};++staticint__initregister_cpufreq_notifier(void)+{+if(cap_parsing_failed)+return-EINVAL;++if(!alloc_cpumask_var(&cpus_to_visit,GFP_KERNEL)){+pr_err("cpu_capacity: failed to allocate memory for "+"cpus_to_visit\n");+return-ENOMEM;+}+cpumask_copy(cpus_to_visit,cpu_possible_mask);++returncpufreq_register_notifier(&init_cpu_capacity_notifier,+CPUFREQ_POLICY_NOTIFIER);+}+core_initcall(register_cpufreq_notifier);+#else+staticint__initfree_raw_capacity(void)+{+kfree(raw_capacity);++return0;+}+core_initcall(free_raw_capacity);+#endif+staticint__initget_cpu_for_node(structdevice_node*node){structdevice_node*cpu_node;
@@ -34,6 +176,7 @@ static int __init get_cpu_for_node(struct device_node *node)for_each_possible_cpu(cpu){if(of_get_cpu_node(cpu,NULL)==cpu_node){+parse_cpu_capacity(cpu_node,cpu);of_node_put(cpu_node);returncpu;}
@@ -185,6 +328,8 @@ static int __init parse_dt_topology(void)if(ret!=0)gotoout_map;+normalize_cpu_capacity();+/**Checkthatallcoresareinthetopology;theSMPcodewill*onlymarkcoresdescribedintheDTaspossible.
From: Juri Lelli <hidden> Date: 2016-06-15 10:18:57
Add a sysfs cpu_capacity attribute with which it is possible to read and
write (thus over-writing default values) CPUs capacity. This might be
useful in situations where values needs changing after boot.
The new attribute shows up as:
/sys/devices/system/cpu/cpu*/cpu_capacity
Cc: Russell King <redacted>
Signed-off-by: Juri Lelli <redacted>
---
arch/arm/kernel/topology.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
@@ -52,6 +52,74 @@ static void set_capacity_scale(unsigned int cpu, unsigned long capacity)per_cpu(cpu_scale,cpu)=capacity;}+#ifdef CONFIG_PROC_SYSCTL+#include<asm/cpu.h>+#include<linux/string.h>+staticssize_tshow_cpu_capacity(structdevice*dev,+structdevice_attribute*attr,+char*buf)+{+structcpu*cpu=container_of(dev,structcpu,dev);+ssize_trc;+intcpunum=cpu->dev.id;+unsignedlongcapacity=arch_scale_cpu_capacity(NULL,cpunum);++rc=sprintf(buf,"%lu\n",capacity);++returnrc;+}++staticssize_tstore_cpu_capacity(structdevice*dev,+structdevice_attribute*attr,+constchar*buf,+size_tcount)+{+structcpu*cpu=container_of(dev,structcpu,dev);+intthis_cpu=cpu->dev.id,i;+unsignedlongnew_capacity;+ssize_tret;++if(count){+char*p=(char*)buf;++ret=kstrtoul(p,0,&new_capacity);+if(ret)+returnret;+if(new_capacity>SCHED_CAPACITY_SCALE)+return-EINVAL;++for_each_cpu(i,&cpu_topology[this_cpu].core_sibling)+set_capacity_scale(i,new_capacity);+}++returncount;+}++staticDEVICE_ATTR(cpu_capacity,+0644,+show_cpu_capacity,+store_cpu_capacity);++staticintregister_cpu_capacity_sysctl(void)+{+inti;+structdevice*cpu;++for_each_possible_cpu(i){+cpu=get_cpu_device(i);+if(!cpu){+pr_err("%s: too early to get CPU%d device!\n",+__func__,i);+continue;+}+device_create_file(cpu,&dev_attr_cpu_capacity);+}++return0;+}+late_initcall(register_cpu_capacity_sysctl);+#endif+#ifdef CONFIG_OFstructcpu_efficiency{constchar*compatible;
From: Juri Lelli <hidden> Date: 2016-06-15 10:19:04
Add a sysfs cpu_capacity attribute with which it is possible to read and
write (thus over-writing default values) CPUs capacity. This might be
useful in situations where values needs changing after boot.
The new attribute shows up as:
/sys/devices/system/cpu/cpu*/cpu_capacity
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <redacted>
Cc: Mark Brown <redacted>
Cc: Sudeep Holla <redacted>
Signed-off-by: Juri Lelli <redacted>
---
arch/arm64/kernel/topology.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
@@ -37,6 +37,74 @@ static void set_capacity_scale(unsigned int cpu, unsigned long capacity)per_cpu(cpu_scale,cpu)=capacity;}+#ifdef CONFIG_PROC_SYSCTL+#include<asm/cpu.h>+#include<linux/string.h>+staticssize_tshow_cpu_capacity(structdevice*dev,+structdevice_attribute*attr,+char*buf)+{+structcpu*cpu=container_of(dev,structcpu,dev);+ssize_trc;+intcpunum=cpu->dev.id;+unsignedlongcapacity=arch_scale_cpu_capacity(NULL,cpunum);++rc=sprintf(buf,"%lu\n",capacity);++returnrc;+}++staticssize_tstore_cpu_capacity(structdevice*dev,+structdevice_attribute*attr,+constchar*buf,+size_tcount)+{+structcpu*cpu=container_of(dev,structcpu,dev);+intthis_cpu=cpu->dev.id,i;+unsignedlongnew_capacity;+ssize_tret;++if(count){+char*p=(char*)buf;++ret=kstrtoul(p,0,&new_capacity);+if(ret)+returnret;+if(new_capacity>SCHED_CAPACITY_SCALE)+return-EINVAL;++for_each_cpu(i,&cpu_topology[this_cpu].core_sibling)+set_capacity_scale(i,new_capacity);+}++returncount;+}++staticDEVICE_ATTR(cpu_capacity,+0644,+show_cpu_capacity,+store_cpu_capacity);++staticintregister_cpu_capacity_sysctl(void)+{+inti;+structdevice*cpu;++for_each_possible_cpu(i){+cpu=get_cpu_device(i);+if(!cpu){+pr_err("%s: too early to get CPU%d device!\n",+__func__,i);+continue;+}+device_create_file(cpu,&dev_attr_cpu_capacity);+}++return0;+}+late_initcall(register_cpu_capacity_sysctl);+#endif+staticu32capacity_scale;staticu32*raw_capacity;staticboolcap_parsing_failed;
From: Juri Lelli <hidden> Date: 2016-06-15 10:20:35
With the introduction of cpu capacity-dmips-mhz bindings, CPU capacities
can now be calculated from values extracted from DT and information
coming from cpufreq. Add parsing of DT information at boot time, and
complement it with cpufreq information. We keep code that can produce
same information, based on different DT properties and hard-coded
values, as fall-back for backward compatibility.
Caveat: the information provided by this patch will start to be used in
the future. We need to #define arch_scale_cpu_capacity to something
provided in arch, so that scheduler's default implementation (which gets
used if arch_scale_cpu_capacity is not defined) is overwritten.
Cc: Russell King <redacted>
Signed-off-by: Juri Lelli <redacted>
---
Changes from v1:
- normalize w.r.t. highest capacity found in DT
- bailout conditions (all-or-nothing)
Changes from v4:
- parsing modified to reflect change in binding (capacity-dmips-mhz)
---
arch/arm/kernel/topology.c | 145 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 144 insertions(+), 1 deletion(-)
@@ -78,6 +78,134 @@ static unsigned long *__cpu_capacity;#define cpu_capacity(cpu) __cpu_capacity[cpu]staticunsignedlongmiddle_capacity=1;+staticboolcap_from_dt=true;+staticu32*raw_capacity;+staticboolcap_parsing_failed;+staticu32capacity_scale;++staticint__initparse_cpu_capacity(structdevice_node*cpu_node,intcpu)+{+intret=1;+u32cpu_capacity;++if(cap_parsing_failed)+return!ret;++ret=of_property_read_u32(cpu_node,+"capacity-dmips-mhz",+&cpu_capacity);+if(!ret){+if(!raw_capacity){+raw_capacity=kzalloc(sizeof(*raw_capacity)*+num_possible_cpus(),GFP_KERNEL);+if(!raw_capacity){+pr_err("cpu_capacity: failed to allocate memory"+" for raw capacities\n");+cap_parsing_failed=true;+return!ret;+}+}+capacity_scale=max(cpu_capacity,capacity_scale);+raw_capacity[cpu]=cpu_capacity;+pr_debug("cpu_capacity: %s cpu_capacity=%u (raw)\n",+cpu_node->full_name,raw_capacity[cpu]);+}else{+pr_err("cpu_capacity: missing %s raw capacity "+"(fallback to 1024 for all CPUs)\n",+cpu_node->full_name);+cap_parsing_failed=true;+kfree(raw_capacity);+}++return!ret;+}++staticvoidnormalize_cpu_capacity(void)+{+u64capacity;+intcpu;++if(WARN_ON(!raw_capacity)||cap_parsing_failed)+return;++pr_debug("cpu_capacity: capacity_scale=%u\n",capacity_scale);+for_each_possible_cpu(cpu){+capacity=(raw_capacity[cpu]<<SCHED_CAPACITY_SHIFT)+/capacity_scale;+set_capacity_scale(cpu,capacity);+pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",+cpu,arch_scale_cpu_capacity(NULL,cpu));+}+}++#ifdef CONFIG_CPU_FREQ+staticcpumask_var_tcpus_to_visit;+staticboolcap_parsing_done;++staticint+init_cpu_capacity_callback(structnotifier_block*nb,+unsignedlongval,+void*data)+{+structcpufreq_policy*policy=data;+intcpu;++if(cap_parsing_failed||cap_parsing_done)+return0;++switch(val){+caseCPUFREQ_NOTIFY:+pr_debug("cpu_capacity: init cpu capacity for CPUs [%*pbl] "+"(to_visit=%*pbl)\n",+cpumask_pr_args(policy->related_cpus),+cpumask_pr_args(cpus_to_visit));+cpumask_andnot(cpus_to_visit,+cpus_to_visit,+policy->related_cpus);+for_each_cpu(cpu,policy->related_cpus){+raw_capacity[cpu]=arch_scale_cpu_capacity(NULL,cpu)*+policy->max/1000UL;+capacity_scale=max(raw_capacity[cpu],capacity_scale);+}+if(cpumask_empty(cpus_to_visit)){+normalize_cpu_capacity();+kfree(raw_capacity);+pr_debug("cpu_capacity: parsing done\n");+cap_parsing_done=true;+}+}+return0;+}++staticstructnotifier_blockinit_cpu_capacity_notifier={+.notifier_call=init_cpu_capacity_callback,+};++staticint__initregister_cpufreq_notifier(void)+{+if(cap_parsing_failed)+return-EINVAL;++if(!alloc_cpumask_var(&cpus_to_visit,GFP_KERNEL)){+pr_err("cpu_capacity: failed to allocate memory for "+"cpus_to_visit\n");+return-ENOMEM;+}+cpumask_copy(cpus_to_visit,cpu_possible_mask);++returncpufreq_register_notifier(&init_cpu_capacity_notifier,+CPUFREQ_POLICY_NOTIFIER);+}+core_initcall(register_cpufreq_notifier);+#else+staticint__initfree_raw_capacity(void)+{+kfree(raw_capacity);++return0;+}+core_initcall(free_raw_capacity);+#endif/**IterateallCPUs'descriptorinDTandcomputetheefficiency
@@ -99,6 +227,12 @@ static void __init parse_dt_topology(void)__cpu_capacity=kcalloc(nr_cpu_ids,sizeof(*__cpu_capacity),GFP_NOWAIT);+cn=of_find_node_by_path("/cpus");+if(!cn){+pr_err("No CPU information found in DT\n");+return;+}+for_each_possible_cpu(cpu){constu32*rate;intlen;
From: Vincent Guittot <vincent.guittot@linaro.org> Date: 2016-06-15 12:52:11
On 15 June 2016 at 12:17, Juri Lelli [off-list ref] wrote:
quoted hunk
ARM systems may be configured to have cpus with different power/performance
characteristics within the same chip. In this case, additional information
has to be made available to the kernel (the scheduler in particular) for it
to be aware of such differences and take decisions accordingly.
Therefore, this patch aims at standardizing cpu capacities device tree
bindings for ARM platforms. Bindings define cpu capacity-dmips-mhz
parameter, to allow operating systems to retrieve such information from
the device tree and initialize related kernel structures, paving the way
for common code in the kernel to deal with heterogeneity.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <redacted>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <redacted>
Cc: Kumar Gala <redacted>
Cc: Maxime Ripard <redacted>
Cc: Olof Johansson <redacted>
Cc: Gregory CLEMENT <redacted>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Linus Walleij <redacted>
Cc: Chen-Yu Tsai <redacted>
Cc: Thomas Petazzoni <redacted>
Cc: devicetree at vger.kernel.org
Signed-off-by: Juri Lelli <redacted>
---
Changes from v1:
- removed section regarding capacity-scale
- added information regarding normalization
Changes from v4:
- binding changed to capacity-dmips-mhz
- sections and changelod updated accordingly
---
.../devicetree/bindings/arm/cpu-capacity.txt | 236 +++++++++++++++++++++
Documentation/devicetree/bindings/arm/cpus.txt | 10 +
2 files changed, 246 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt
@@ -0,0 +1,236 @@+==========================================+ARM CPUs capacity bindings+==========================================++==========================================+1 - Introduction+==========================================++ARM systems may be configured to have cpus with different power/performance+characteristics within the same chip. In this case, additional information+has to be made available to the kernel (the scheduler in particular) for
not sure that it's worth mentioning the scheduler in particular here
+it to be aware of such differences and take decisions accordingly.
+
+==========================================
+2 - CPU capacity definition
+==========================================
+
+CPU capacity is a number that provides the scheduler information about CPUs
+heterogeneity. Such heterogeneity can come from micro-architectural differences
+(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run
+(e.g., SMP systems with multiple frequency domains). Heterogeneity in this
+context is about differing performance characteristics; this binding tries to
+capture a first-order approximation of the relative performance of CPUs.
+
+CPU capacities are obtained by running a suitable benchmark. This binding makes
+no aspersions on the validity or suitability of any particular benchmark, the
+final capacity should, however, be:
+
+* A "single-threaded" or CPU affine benchmark
+* Divided by the running frequency of the CPU executing the benchmark
+* Not subject to dynamic frequency scaling of the CPU
+
+For the time being we however advise usage of the Dhrystone benchmark. What
+above thus becomes:
+
+CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
+max frequency. The obtained DMIPS score is then divided by the frequency (in
+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.
+Such values are then normalized w.r.t. the highest score obtained in the
+system.
+
+==========================================
+3 - capacity-dmips-mhz
+==========================================
+
+capacity-dmips-mhz is an optional cpu node [1] property: u32 value
+representing CPU capacity expressed in normalized DMIPS/MHz. At boot time, the
+maximum frequency available to the cpu is then used to calculate the capacity
+value internally used by the kernel.
+
+capacity-dmips-mhz property is all-or-nothing: if it is specified for a cpu
+node, it has to be specified for every other cpu nodes, or the system will
+fall back to the default capacity value for every CPU. If cpufreq is not
+available, final capacities are calculated by directly using capacity-dmips-
+mhz values (normalized w.r.t. the highest value found while parsing the DT).
looks good to me
quoted hunk
+
+===========================================
+4 - Examples
+===========================================
+
+Example 1 (ARM 64-bit, 6-cpu system, two clusters):
+capacities-dmips-mhz are scaled w.r.t. 1024 (cpu at 0 and cpu at 1)
+supposing cluster0 at max-freq=1100 and custer1 at max-freq=850,
+final capacities are 1024 for cluster0 and 446 for cluster1
+
+cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&A57_0>;
+ };
+ core1 {
+ cpu = <&A57_1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&A53_0>;
+ };
+ core1 {
+ cpu = <&A53_1>;
+ };
+ core2 {
+ cpu = <&A53_2>;
+ };
+ core3 {
+ cpu = <&A53_3>;
+ };
+ };
+ };
+
+ idle-states {
+ entry-method = "arm,psci";
+
+ CPU_SLEEP_0: cpu-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x0010000>;
+ local-timer-stop;
+ entry-latency-us = <100>;
+ exit-latency-us = <250>;
+ min-residency-us = <150>;
+ };
+
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ arm,psci-suspend-param = <0x1010000>;
+ local-timer-stop;
+ entry-latency-us = <800>;
+ exit-latency-us = <700>;
+ min-residency-us = <2500>;
+ };
+ };
+
+ A57_0: cpu at 0 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A57_L2>;
+ clocks = <&scpi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <1024>;
+ };
+
+ A57_1: cpu at 1 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x1>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A57_L2>;
+ clocks = <&scpi_dvfs 0>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <1024>;
+ };
+
+ A53_0: cpu at 100 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <578>;
+ };
+
+ A53_1: cpu at 101 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x101>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <578>;
+ };
+
+ A53_2: cpu at 102 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x102>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <578>;
+ };
+
+ A53_3: cpu at 103 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x103>;
+ device_type = "cpu";
+ enable-method = "psci";
+ next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
+ cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>;
+ capacity-dmips-mhz = <578>;
+ };
+
+ A57_L2: l2-cache0 {
+ compatible = "cache";
+ };
+
+ A53_L2: l2-cache1 {
+ compatible = "cache";
+ };
+};
+
+Example 2 (ARM 32-bit, 4-cpu system, two clusters,
+ cpus 0,1 at 1GHz, cpus 2,3 at 500MHz):
+capacities-dmips-mhz are scaled w.r.t. 2 (cpu at 0 and cpu at 1), this means that first
+cpu at 0 and cpu at 1 are twice fast than cpu at 2 and cpu at 3 (at the same frequency)
+
+cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu at 0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0>;
+ capacity-dmips-mhz = <2>;
+ };
+
+ cpu1: cpu at 1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <1>;
+ capacity-dmips-mhz = <2>;
+ };
+
+ cpu2: cpu at 2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x100>;
+ capacity-dmips-mhz = <1>;
+ };
+
+ cpu3: cpu at 3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x101>;
+ capacity-dmips-mhz = <1>;
+ };
+};
+
+===========================================
+5 - References
+===========================================
+
+[1] ARM Linux Kernel documentation - CPUs bindings
+ Documentation/devicetree/bindings/arm/cpus.txt
@@ -238,6 +238,14 @@ nodes to be present and contain the properties described below. # List of phandles to idle state nodes supported by this cpu [3].+ - capacity-dmips-mhz+ Usage: Optional+ Value type: <u32>+ Definition:+ # u32 value representing CPU capacity [3] in+ DMIPS/MHz, relative to highest capacity-dmips-mhz+ in the system.+ - rockchip,pmu Usage: optional for systems that have an "enable-method" property value of "rockchip,rk3066-smp"
@@ -461,3 +469,5 @@ cpus { [2] arm/msm/qcom,kpss-acc.txt [3] ARM Linux kernel documentation - idle states bindings Documentation/devicetree/bindings/arm/idle-states.txt+[3] ARM Linux kernel documentation - cpu capacity bindings+ Documentation/devicetree/bindings/arm/cpu-capacity.txt--
+ if (!raw_capacity) {
+ pr_err("cpu_capacity: failed to allocate memory"
+ " for raw capacities\n");
It's normally better to avoid splitting errors message so people can
grep if they see the error.
+ } else {
+ pr_err("cpu_capacity: missing %s raw capacity "
+ "(fallback to 1024 for all CPUs)\n",
+ cpu_node->full_name);
That's going to complain fairly loudly for all existing DTs isn't it and
it's kind of redundant if all the cores have the same capacity (which is
a very common case)? How about printing an error only if we already
found one, or printing a single warning at the end if we didn't get
anything?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160615/7556dbd7/attachment-0001.sig>
From: Mark Brown <broonie@kernel.org> Date: 2016-06-15 14:05:11
On Wed, Jun 15, 2016 at 11:17:50AM +0100, Juri Lelli wrote:
+CPU capacities are obtained by running a suitable benchmark. This binding makes
+no aspersions on the validity or suitability of any particular benchmark, the
+final capacity should, however, be:
Makes no guarantees. An aspersion is an insult!
+CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
+max frequency. The obtained DMIPS score is then divided by the frequency (in
+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.
+Such values are then normalized w.r.t. the highest score obtained in the
+system.
Perhaps worth mentioning that caches and so on should be enabled (based
on previous experience with people doing bringup)?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160615/384c7778/attachment.sig>
From: Juri Lelli <hidden> Date: 2016-06-15 14:22:43
On 15/06/16 15:04, Mark Brown wrote:
On Wed, Jun 15, 2016 at 11:17:50AM +0100, Juri Lelli wrote:
quoted
+CPU capacities are obtained by running a suitable benchmark. This binding makes
+no aspersions on the validity or suitability of any particular benchmark, the
+final capacity should, however, be:
Makes no guarantees. An aspersion is an insult!
Whoops! :-/
Sure, I'll change that.
quoted
+CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
+max frequency. The obtained DMIPS score is then divided by the frequency (in
+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.
+Such values are then normalized w.r.t. the highest score obtained in the
+system.
Perhaps worth mentioning that caches and so on should be enabled (based
on previous experience with people doing bringup)?
OK. I'll add something along this line.
Thanks,
- Juri
From: Juri Lelli <hidden> Date: 2016-06-15 14:24:44
On 15/06/16 14:51, Vincent Guittot wrote:
On 15 June 2016 at 12:17, Juri Lelli [off-list ref] wrote:
[...]
quoted
+==========================================
+ARM CPUs capacity bindings
+==========================================
+
+==========================================
+1 - Introduction
+==========================================
+
+ARM systems may be configured to have cpus with different power/performance
+characteristics within the same chip. In this case, additional information
+has to be made available to the kernel (the scheduler in particular) for
not sure that it's worth mentioning the scheduler in particular here
OK. I can remove that bit.
quoted
+it to be aware of such differences and take decisions accordingly.
+
[...]
quoted
+==========================================
+3 - capacity-dmips-mhz
+==========================================
+
+capacity-dmips-mhz is an optional cpu node [1] property: u32 value
+representing CPU capacity expressed in normalized DMIPS/MHz. At boot time, the
+maximum frequency available to the cpu is then used to calculate the capacity
+value internally used by the kernel.
+
+capacity-dmips-mhz property is all-or-nothing: if it is specified for a cpu
+node, it has to be specified for every other cpu nodes, or the system will
+fall back to the default capacity value for every CPU. If cpufreq is not
+available, final capacities are calculated by directly using capacity-dmips-
+mhz values (normalized w.r.t. the highest value found while parsing the DT).
+ if (!raw_capacity) {
+ pr_err("cpu_capacity: failed to allocate memory"
+ " for raw capacities\n");
It's normally better to avoid splitting errors message so people can
grep if they see the error.
Tried to avoid breaking 80 columns. But, we seem to have longer pr_err
strings already. I'll change that.
quoted
+ } else {
+ pr_err("cpu_capacity: missing %s raw capacity "
+ "(fallback to 1024 for all CPUs)\n",
+ cpu_node->full_name);
That's going to complain fairly loudly for all existing DTs isn't it and
it's kind of redundant if all the cores have the same capacity (which is
a very common case)? How about printing an error only if we already
found one, or printing a single warning at the end if we didn't get
anything?
Right, I'll change the condition for which pr_err is emitted. I think
the situation for which we care the most about is when we find partial
information in DT.
Thanks,
- Juri
From: Rob Herring <robh+dt@kernel.org> Date: 2016-06-15 22:11:47
On Wed, Jun 15, 2016 at 5:17 AM, Juri Lelli [off-list ref] wrote:
quoted hunk
ARM systems may be configured to have cpus with different power/performance
characteristics within the same chip. In this case, additional information
has to be made available to the kernel (the scheduler in particular) for it
to be aware of such differences and take decisions accordingly.
Therefore, this patch aims at standardizing cpu capacities device tree
bindings for ARM platforms. Bindings define cpu capacity-dmips-mhz
parameter, to allow operating systems to retrieve such information from
the device tree and initialize related kernel structures, paving the way
for common code in the kernel to deal with heterogeneity.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <redacted>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <redacted>
Cc: Kumar Gala <redacted>
Cc: Maxime Ripard <redacted>
Cc: Olof Johansson <redacted>
Cc: Gregory CLEMENT <redacted>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Linus Walleij <redacted>
Cc: Chen-Yu Tsai <redacted>
Cc: Thomas Petazzoni <redacted>
Cc: devicetree at vger.kernel.org
Signed-off-by: Juri Lelli <redacted>
---
Changes from v1:
- removed section regarding capacity-scale
- added information regarding normalization
Changes from v4:
- binding changed to capacity-dmips-mhz
- sections and changelod updated accordingly
---
.../devicetree/bindings/arm/cpu-capacity.txt | 236 +++++++++++++++++++++
Documentation/devicetree/bindings/arm/cpus.txt | 10 +
2 files changed, 246 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cpu-capacity.txt
@@ -0,0 +1,236 @@+==========================================+ARM CPUs capacity bindings+==========================================++==========================================+1 - Introduction+==========================================++ARM systems may be configured to have cpus with different power/performance+characteristics within the same chip. In this case, additional information+has to be made available to the kernel (the scheduler in particular) for+it to be aware of such differences and take decisions accordingly.++==========================================+2 - CPU capacity definition+==========================================++CPU capacity is a number that provides the scheduler information about CPUs+heterogeneity. Such heterogeneity can come from micro-architectural differences+(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run+(e.g., SMP systems with multiple frequency domains). Heterogeneity in this+context is about differing performance characteristics; this binding tries to+capture a first-order approximation of the relative performance of CPUs.++CPU capacities are obtained by running a suitable benchmark. This binding makes+no aspersions on the validity or suitability of any particular benchmark, the+final capacity should, however, be:++* A "single-threaded" or CPU affine benchmark+* Divided by the running frequency of the CPU executing the benchmark+* Not subject to dynamic frequency scaling of the CPU++For the time being we however advise usage of the Dhrystone benchmark. What+above thus becomes:++CPU capacities are obtained by running the Dhrystone benchmark on each CPU at+max frequency. The obtained DMIPS score is then divided by the frequency (in+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.+Such values are then normalized w.r.t. the highest score obtained in the+system.
So the property says it represents DMIPS/MHz, but we take that and
"normalize" them back to a made up numbers? Perhaps that step should
be optional. Then paranoid Si vendors can put their fake numbers in
and end users can update the dts files with real numbers.
Is there any point in allowing people to pick their own scale? Why not
just 100 (as in percent)?
Rob
From: Juri Lelli <hidden> Date: 2016-06-16 08:20:49
Hi,
On 15/06/16 17:11, Rob Herring wrote:
On Wed, Jun 15, 2016 at 5:17 AM, Juri Lelli [off-list ref] wrote:
[...]
quoted
+==========================================
+2 - CPU capacity definition
+==========================================
+
+CPU capacity is a number that provides the scheduler information about CPUs
+heterogeneity. Such heterogeneity can come from micro-architectural differences
+(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run
+(e.g., SMP systems with multiple frequency domains). Heterogeneity in this
+context is about differing performance characteristics; this binding tries to
+capture a first-order approximation of the relative performance of CPUs.
+
+CPU capacities are obtained by running a suitable benchmark. This binding makes
+no aspersions on the validity or suitability of any particular benchmark, the
+final capacity should, however, be:
+
+* A "single-threaded" or CPU affine benchmark
+* Divided by the running frequency of the CPU executing the benchmark
+* Not subject to dynamic frequency scaling of the CPU
+
+For the time being we however advise usage of the Dhrystone benchmark. What
+above thus becomes:
+
+CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
+max frequency. The obtained DMIPS score is then divided by the frequency (in
+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.
+Such values are then normalized w.r.t. the highest score obtained in the
+system.
So the property says it represents DMIPS/MHz, but we take that and
"normalize" them back to a made up numbers?
The normalization step is required if one wants to prevent
cross-platform comparisons (I think that's what vendors generally want).
They are not made up, they still come from measured DMIPS/MHz values.
Perhaps that step should
be optional. Then paranoid Si vendors can put their fake numbers in
and end users can update the dts files with real numbers.
But, you can also decide to skip that step and put non normalized
numbers in. This documentation is advising people for what seems to be
be the most common way of coming up with values that, once in a DT,
won't be used to compare perf of different platforms.
Maybe we want to add a paragraph clearly stating this point?
Is there any point in allowing people to pick their own scale? Why not
just 100 (as in percent)?
I think we agreed that not picking any particular scale is more flexible
and easier to use. For example, if there is a 2x factor between you cpus
you can simply put 1 and 2 there. But, if you need higher "resolution"
you can put whatever suits you better and we'll use the max as scale.
Thanks a lot for the review.
Best,
- Juri
From: Juri Lelli <hidden> Date: 2016-06-22 16:51:12
Hi Rob,
On 16/06/16 09:20, Juri Lelli wrote:
Hi,
On 15/06/16 17:11, Rob Herring wrote:
quoted
On Wed, Jun 15, 2016 at 5:17 AM, Juri Lelli [off-list ref] wrote:
[...]
quoted
quoted
+==========================================
+2 - CPU capacity definition
+==========================================
+
+CPU capacity is a number that provides the scheduler information about CPUs
+heterogeneity. Such heterogeneity can come from micro-architectural differences
+(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run
+(e.g., SMP systems with multiple frequency domains). Heterogeneity in this
+context is about differing performance characteristics; this binding tries to
+capture a first-order approximation of the relative performance of CPUs.
+
+CPU capacities are obtained by running a suitable benchmark. This binding makes
+no aspersions on the validity or suitability of any particular benchmark, the
+final capacity should, however, be:
+
+* A "single-threaded" or CPU affine benchmark
+* Divided by the running frequency of the CPU executing the benchmark
+* Not subject to dynamic frequency scaling of the CPU
+
+For the time being we however advise usage of the Dhrystone benchmark. What
+above thus becomes:
+
+CPU capacities are obtained by running the Dhrystone benchmark on each CPU at
+max frequency. The obtained DMIPS score is then divided by the frequency (in
+MHz) at which the benchmark has been run, so that DMIPS/MHz are obtained.
+Such values are then normalized w.r.t. the highest score obtained in the
+system.
So the property says it represents DMIPS/MHz, but we take that and
"normalize" them back to a made up numbers?
The normalization step is required if one wants to prevent
cross-platform comparisons (I think that's what vendors generally want).
They are not made up, they still come from measured DMIPS/MHz values.
quoted
Perhaps that step should
be optional. Then paranoid Si vendors can put their fake numbers in
and end users can update the dts files with real numbers.
But, you can also decide to skip that step and put non normalized
numbers in. This documentation is advising people for what seems to be
be the most common way of coming up with values that, once in a DT,
won't be used to compare perf of different platforms.
Maybe we want to add a paragraph clearly stating this point?
quoted
Is there any point in allowing people to pick their own scale? Why not
just 100 (as in percent)?
I think we agreed that not picking any particular scale is more flexible
and easier to use. For example, if there is a 2x factor between you cpus
you can simply put 1 and 2 there. But, if you need higher "resolution"
you can put whatever suits you better and we'll use the max as scale.
Thanks a lot for the review.
Do you have any further comments on this point?
Best,
- Juri