Linux CPU core的电源管理(1)_概述

作者:wowo 发布于:2015-4-30 21:20 分类:电源管理子系统

1. 前言

在SMP(Symmetric Multi-Processing)流行起来之前的很长一段时间,Linux kernel的电源管理工作主要集中在外部设备上,和CPU core相关的,顶多就是CPU idle。但随着SMP的普及,一个系统中可用的CPU core越来越多,这些core的频率越来越高,处理能力越来越强,功耗也越来越大。因此,CPU core有关的电源管理,在系统设计中就成为必不可少的一环,与此有关的思考包括:

对消费者(一些专业应用除外)而言,这种暴增的处理能力,是一种极大的浪费,他们很少(或者从不)有如此高的性能需求。但商家对此却永远乐此不疲,原因无外乎:

1)硬件成本越来越低。

2)营销的噱头。

3)软件设计者的不思进取(臃肿的Android就是典型的例子),导致软件效率低下,硬件资源浪费严重。以至于优化几行代码的难度,甚至比增加几个cpu核还困难。

在这种背景下,CPU core的电源管理逻辑,就非常直接了:根据系统的负荷,关闭“多余的CPU性能”,在满足用户需求的前提下,尽可能的降低CPU的功耗。但CPU的控制粒度不可能无限小,目前主要从两个角度实现CPU core的电源管理功能:

1)在SMP系统中,动态的关闭或者打开CPU core(本文重点介绍的功能)。

2)CPU运行过程中,动态的调整CPU core的电压和频率(将在其它文章中单独分析)。

本文将以ARM64为例,介绍linux kernel CPU core相关的电源管理设计。

2. 功能说明

在linux kernel中,CPU core相关的电源管理实现,并不是单纯的电源管理行为,它会涉及到系统初始化、CPU拓扑结构、进程调度、CPU hotplug、memory  hotplug等知识点。总的来说,它主要完成如下功能:

1)系统启动时,CPU core的初始化、信息获取等。

2)系统启动时,CPU core的启动(enable)。

3)系统运行过程中,根据当前负荷,动态的enable/disable某些CPU core,以便在性能和功耗之间平衡。

4)CPU core的hotplug支持。所谓的hotplug,是指可以在系统运行的过程中,动态的增加或者减少CPU core(可以是物理上,也可以是逻辑上)。

5)系统运行过程中的CPU idle管理(具体可参考“Linux cpuidle framework系列文章”)。

6)系统运行过程中,根据当前负荷,动态的调整CPU core的电压和频率,以便在性能和功耗之间平衡。

3. 软件架构

为了实现上面的功能,linux kernel抽象出了下面的软件框架:

linux cpu core pm

软件框架包括arch-dependent和arch-independent两部分。

对ARM64而言,arch-dependent部分位于“arch\arm64\kernel”,负责提供平台相关的控制操作,包括:

CPU信息的获取(cpuinfo);

CPU拓扑结构的获取(cpu topology);

底层的CPU操作(init、disable等)的实现,cpu ops(在ARM32中是以smp ops的形式存在的);

SMP相关的初始化(smp);

等等。

arch-independent负责实现平台无关的抽象,包括:

CPU control模块,屏蔽底层平台相关的实现细节,提供控制CPU(enable、disable等)的统一API,供系统启动、进程调度等模块调用;

CPU subsystem driver,向用户空间提供CPU hotplug有关的功能;

cpuidle,处理CPU idle有关的逻辑,具体可参考“cpuidle framework”相关的文章;

cpufreq,处理CPU frequency调整有关的逻辑,具体可参考后续的文章;

等等。

4. 软件模块的功能及API描述

4.1 kernel cpu control

kernel cpu control位于“.\kernel\cpu.c”中,是一个承上启下的模块,负责屏蔽arch-dependent的实现细节,向上层软件提供CPU core控制的统一API。主要功能包括:

1)将CPU core抽象为possible、present、online和active四种状态,并以bitmap的形式,在模块内部维护所有CPU core的状态,同时以cpumask的形式向其它模块提供状态查询、状态修改的API。相关的API如下:

   1: /* kernel/cpu.c */
   2:  
   3: #ifdef CONFIG_INIT_ALL_POSSIBLE
   4: static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
   5:         = CPU_BITS_ALL;
   6: #else
   7: static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
   8: #endif
   9: const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
  10: EXPORT_SYMBOL(cpu_possible_mask);
  11:  
  12: static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
  13: const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
  14: EXPORT_SYMBOL(cpu_online_mask);
  15:  
  16: static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
  17: const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
  18: EXPORT_SYMBOL(cpu_present_mask);
  19:  
  20: static DECLARE_BITMAP(cpu_active_bits, CONFIG_NR_CPUS) __read_mostly;
  21: const struct cpumask *const cpu_active_mask = to_cpumask(cpu_active_bits);
  22: EXPORT_SYMBOL(cpu_active_mask);

bitmap的定义是:
#define DECLARE_BITMAP(name,bits)    unsigned long name[BITS_TO_LONGS(bits)]

其本质上是一个long型的数组,数组中每一个bit,代表一个CPU core的状态。例如long的长度为64位的系统中,如果有8个CPU core,则可以使用长度为1的数组的前8个bit,代表这个8个core的状态。

这里一共有4种状态需要表示:

cpu_possible_bits,系统中包含的所有的可能的CPU core,在系统初始化的时候就已经确定。对于ARM64来说,DTS中所有格式正确的CPU core,都属于possible的core;

cpu_present_bits,系统中所有可用的CPU core(具备online的条件,具体由底层代码决定),并不是所有possible的core都是present的。对于支持CPU hotplug的形态,present core可以动态改变;

cpu_online_bits,系统中所有运行状态的CPU core(后面会详细说明这个状态的意义);

cpu_active_bits,有active的进程正在运行的CPU core。

 

另外,在使用bitmap表示这4种状态的同时,还提供了4个cpumask,用于对外提供接口。cpumask的本质也是bitmap(多一层封装而已),只是kernel提供了一些方便的API,可以以CPU编号为单位,操作cpumask(具体可参考include/linux/cpumask.h)。

注1:这里有一个关于constant变量的经典例子,大家可以学习一下。
毫无疑问,CPU core的这些状态,是相当重要的一些状态,因此kernel希望它们对外(除cpu control外)是read only的,对内又是writeable的。怎么办呢?
这里的设计很巧妙,对内使用4个static的bitmap变量,因此是writeable的。而对外呢,使用4个constant类型的cpumask指针(指针readonly,值readonly),因此是readonly的。
外部模块read时,通过一层转换,从static的bitmap中获取实际的值。是不是很有意思?

下面是这几个变量有关的操作函数:

   1: /* include/linux/cpumask.h */
   2:  
   3: #define num_online_cpus()       cpumask_weight(cpu_online_mask)
   4: #define num_possible_cpus()     cpumask_weight(cpu_possible_mask)
   5: #define num_present_cpus()      cpumask_weight(cpu_present_mask)
   6: #define num_active_cpus()       cpumask_weight(cpu_active_mask)
   7: #define cpu_online(cpu)         cpumask_test_cpu((cpu), cpu_online_mask)
   8: #define cpu_possible(cpu)       cpumask_test_cpu((cpu), cpu_possible_mask)
   9: #define cpu_present(cpu)        cpumask_test_cpu((cpu), cpu_present_mask)
  10: #define cpu_active(cpu)         cpumask_test_cpu((cpu), cpu_active_mask)
  11:  
  12:  
  13: #define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
  14: #define for_each_online_cpu(cpu)   for_each_cpu((cpu), cpu_online_mask)
  15: #define for_each_present_cpu(cpu)  for_each_cpu((cpu), cpu_present_mask)
  16:  
  17: /* Wrappers for arch boot code to manipulate normally-constant masks */
  18: void set_cpu_possible(unsigned int cpu, bool possible);
  19: void set_cpu_present(unsigned int cpu, bool present);
  20: void set_cpu_online(unsigned int cpu, bool online);
  21: void set_cpu_active(unsigned int cpu, bool active);
  22: void init_cpu_present(const struct cpumask *src);
  23: void init_cpu_possible(const struct cpumask *src);
  24: void init_cpu_online(const struct cpumask *src);


2)提供CPU core的up/down操作,以及up/down时的notifier机制

通俗地讲,所谓的CPU core up,就是将某一个CPU core“运行”起来。何为运行呢?回忆一下单核CPU的启动,就是让该CPU core在指定的memory地址处取指执行。因此该功能只对SMP系统有效(使能了CONFIG_SMP)。而CPU core down,就是让CPU core保存现场(后面可以继续执行)后,停止取指,只有在CPU hotplug功能使能(CONFIG_HOTPLUG_CPU)时有效。这两个功能对应的API为:

   1: /* include/linux/cpu.h */
   2:  
   3: int cpu_up(unsigned int cpu);
   4:  
   5: int cpu_down(unsigned int cpu);

同时,提供了CPU up/down时的通知API,具体请参考“include/linux/cpu.h"。

3)提供SMP PM有关的操作

系统休眠过程中,将noboot的CPU禁用,并在系统恢复时恢复(可参考“Linux电源管理(6)_Generic PM之Suspend功能”中的有关描述)。

   1: #ifdef CONFIG_PM_SLEEP_SMP
   2: extern int disable_nonboot_cpus(void);
   3: extern void enable_nonboot_cpus(void);
   4: #else /* !CONFIG_PM_SLEEP_SMP */
   5: static inline int disable_nonboot_cpus(void) { return 0; }
   6: static inline void enable_nonboot_cpus(void) {}
   7: #endif /* !CONFIG_PM_SLEEP_SMP */


4.2 cpu subsystem driver

cpu subsystem driver位于“drivers/base/cpu.c”中,从设备模型的角度,抽象CPU core设备,并通过sysfs提供CPU core状态查询、hotplug控制等接口。具体如下:

1)注册一个名称为“bus”的subsystem(在sysfs中目录为“/sys/devices/system/cpu/”,有关subsystem的描述,可参考“Linux设备模型(6)_Bus”)。

2)使用struct cpu抽象CPU core device(见“include/linux/cpu.h”)。

4)从设备模型的角度,提供CPU core device的register/unregister等接口,并在系统初始化的时候根据CPU core的个数,将这些device注册到kernel中。同时根据kernel配置,注册相关的CPU attribute。

   1: extern int register_cpu(struct cpu *cpu, int num);
   2: extern struct device *get_cpu_device(unsigned cpu);
   3: extern bool cpu_is_hotpluggable(unsigned cpu);
   4: extern bool arch_match_cpu_phys_id(int cpu, u64 phys_id);
   5: extern bool arch_find_n_match_cpu_physical_id(struct device_node *cpun,
   6:                                               int cpu, unsigned int *thread);
   7:  
   8: extern int cpu_add_dev_attr(struct device_attribute *attr);
   9: extern void cpu_remove_dev_attr(struct device_attribute *attr);
  10:  
  11: extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
  12: extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
  13:  
  14: #ifdef CONFIG_HOTPLUG_CPU
  15: extern void unregister_cpu(struct cpu *cpu);
  16: extern ssize_t arch_cpu_probe(const char *, size_t);
  17: extern ssize_t arch_cpu_release(const char *, size_t);
  18: #endif

最终在sysfs中的目录结构如下:

# ls /sys/devices/system/cpu/

autoplug/  cpu2/      cpuidle/   offline    power/    

cpu0/      cpu3/      kernel_max online     present

具体会在后续的文章中详细说明。

4.3 smp

smp位于“arch/arm64/kernel/smp.c”,在arch-dependent代码中,承担承上启下的角色,主要提供两类功能:

1)arch-dependent的SMP初始化、CPU core控制等操作(本文需要关注的功能)。

2)IPI(Inter-Processor Interrupts)相关的支持(具体可参考本站“中断子系统”有关的文章)。

SMP初始化操作,主要负责从DTS中解析CPU core信息,并获取必要的信息以及操作函数集,由smp_init_cpus接口实现,并在setup_arch(arch\arm64\kernel\setup.c)中调用。

CPU core控制相关的接口包括:

   1: /* arch/arm64/include/asm/smp.h */
   2:  
   3: /*
   4:  * Called from the secondary holding pen, this is the secondary CPU entry point.
   5:  */
   6: asmlinkage void secondary_start_kernel(void);
   7:  
   8: /*
   9:  * Initial data for bringing up a secondary CPU.
  10:  */
  11: struct secondary_data {
  12:         void *stack;
  13: };
  14: extern struct secondary_data secondary_data;
  15: extern void secondary_entry(void);
  16:  
  17: extern void arch_send_call_function_single_ipi(int cpu);
  18: extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
  19:  
  20: extern int __cpu_disable(void);
  21:  
  22: extern void __cpu_die(unsigned int cpu);
  23: extern void cpu_die(void);

secondary_start_kernel、secondary_entry,是那些 noboot CPU的入口,具体后面再详细介绍;

__cpu_disable、__cpu_die、cpu_die等函数负责disable某个CPU core,它们不会直接操作硬件,而是通过下层的cpu_ops控制具体的CPU core,具体请参考4.4小节的说明。

4.4 cpu ops

由于SMP架构比较复杂,特别是对ARM64而言,又涉及到虚拟化等安全特性,ARM便将CPU core的up/down等电源管理操作,封装起来(例如封装到secure mode下,特权级别的OS代码通过一些指令码与其交互,具体请参考后续的文章)。在ARM64中,这种封装便是通过cpu os结构(struct cpu_operations)体现的,如下:

   1: /* arch/arm64/include/asm/cpu_ops.h */
   2:  
   3: /**
   4:  * struct cpu_operations - Callback operations for hotplugging CPUs.
   5:  *
   6:  * @name:       Name of the property as appears in a devicetree cpu node's
   7:  *              enable-method property.
   8:  * @cpu_init:   Reads any data necessary for a specific enable-method from the
   9:  *              devicetree, for a given cpu node and proposed logical id.
  10:  * @cpu_init_idle: Reads any data necessary to initialize CPU idle states from
  11:  *              devicetree, for a given cpu node and proposed logical id.
  12:  * @cpu_prepare: Early one-time preparation step for a cpu. If there is a
  13:  *              mechanism for doing so, tests whether it is possible to boot
  14:  *              the given CPU.
  15:  * @cpu_boot:   Boots a cpu into the kernel.
  16:  * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary
  17:  *              synchronisation. Called from the cpu being booted.
  18:  * @cpu_disable: Prepares a cpu to die. May fail for some mechanism-specific
  19:  *              reason, which will cause the hot unplug to be aborted. Called
  20:  *              from the cpu to be killed.
  21:  * @cpu_die:    Makes a cpu leave the kernel. Must not fail. Called from the
  22:  *              cpu being killed.
  23:  * @cpu_kill:  Ensures a cpu has left the kernel. Called from another cpu.
  24:  * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing
  25:  *               to wrong parameters or error conditions. Called from the
  26:  *               CPU being suspended. Must be called with IRQs disabled.
  27:  */
  28: struct cpu_operations {
  29:         const char      *name;
  30:         int             (*cpu_init)(struct device_node *, unsigned int);
  31:         int             (*cpu_init_idle)(struct device_node *, unsigned int);
  32:         int             (*cpu_prepare)(unsigned int);
  33:         int             (*cpu_boot)(unsigned int);
  34:         void            (*cpu_postboot)(void);
  35: #ifdef CONFIG_HOTPLUG_CPU
  36:         int             (*cpu_disable)(unsigned int cpu);
  37:         void            (*cpu_die)(unsigned int cpu);
  38:         int             (*cpu_kill)(unsigned int cpu);
  39: #endif
  40: #ifdef CONFIG_ARM64_CPU_SUSPEND
  41:         int             (*cpu_suspend)(unsigned long);
  42: #endif
  43: };

ARM architecture提供多种可选的cpu ops实现,如spin-table、PSCI(Power State Coordination Interface)等(具体会在后续的文章中详细描述),开发者可以根据需求,选择一种。4.3节所描述的smp初始化时,会解析DTS,并填充cpu ops变量。

这里以PSCI为例,简单了解一下这些接口的含义(具体说明请参考后续的文章)。

cpu_boot:   Boots a cpu into the kernel.  其实就是将启动函数(secondary_entry)的物理地址,给到CPU core执行,具体要看spec

cpu_disable: Prepares a cpu to die.

cpu_die: Makes a cpu leave the kernel.

cpu_suspend: Suspends a cpu and saves the required context.

4.5 cpu topology

本文提到了很多诸如SMP、CPU core之类的字眼,相应读者可能看的不太明白,这和CPU的拓扑结构有关。进程调度、cpufreq等模块,可能需要根据具体的拓扑结构,制定相应的策略。

ARM64的topology在“./arch/arm64/include/asm/topology.h”中定义,如下:

   1: struct cpu_topology {
   2:         int thread_id;
   3:         int core_id;
   4:         int cluster_id;
   5:         cpumask_t thread_sibling;
   6:         cpumask_t core_sibling;
   7: };
   8:  
   9: extern struct cpu_topology cpu_topology[NR_CPUS];
  10:  
  11: #define topology_physical_package_id(cpu)       (cpu_topology[cpu].cluster_id)
  12: #define topology_core_id(cpu)           (cpu_topology[cpu].core_id)
  13: #define topology_core_cpumask(cpu)      (&cpu_topology[cpu].core_sibling)
  14: #define topology_thread_cpumask(cpu)    (&cpu_topology[cpu].thread_sibling)
  15:  
  16: void init_cpu_topology(void);
  17: void store_cpu_topology(unsigned int cpuid);
  18: const struct cpumask *cpu_coregroup_mask(int cpu);

topology的实现位于“arch/arm64/kernel/topology.c ”中,负责在系统初始化的时候,由boot cpu读取DTS,填充每个CPU core的struct cpu_topology变量。同时,该文件提供一些通用的宏定义,用于获取执行CPU core的信息,例如该CPU core的package id、core id等。

topology的具体描述,请参考下一篇文章。

4.6 cpu info及其它

cpu info位于“arch/arm64/kernel/cpuinfo.c”,负责在初始化的时候将ARM CPU core有关的信息,从寄存器中读出,缓存在struct cpuinfo_arm64类型的变量中,以便后面使用。具体不再详细描述。

5. 结束语

本文简单的介绍了CPU core电源管理相关的软件组成,并认识了cpu ops、cpu topology等概念,后续将通过以下的文章进行更为详细的分析:

Linux CPU core的电源管理(2)_cpu topology,认识并理解ARM处理器的拓扑结构,以及cluster(socket)、core、thread等处理器结构相关的概念;

Linux CPU core的电源管理(3)_cpu ops,分析cpu operations抽象和物理意义;

Linux CPU core的电源管理(4)_PSCI,分析ARM PSCI(Power State Coordination Interface)接口;

Linux CPU core的电源管理(5)_cpu control,从系统的角度,分析系统初始化、进程调度、CPU hotplug等场景下,CPU up/down等操作的流程;

Linux cpufreq framework系列文章,分析CPU动态频率/电压调整相关的实现。

 

原创文章,转发请注明出处。蜗窝科技www.wowotech.net

标签: Linux PM core cpu

评论:

koala
2016-05-27 09:13
hi,wowo,

我们经常所说的DVFS,狭隘地是指interactive这个governor吗?还有其他地方有涉及吗?

啥时候有空把interactive governor分析一下啊?

谢谢
wowo
2016-05-27 10:55
@koala:可以这么理解,不过你也可以设计自己的策略。

有时间可以分析一下interactive governor,多谢关注~
archer
2016-01-27 19:56
写的很好,才发现有这么好的一个地方,谢谢! 希望能快点学习,以后我也能在这里写一篇文章。 :)
wowo
2016-01-28 08:57
@archer:希望不止有一篇哈,等着你:-)
YANG23
2015-09-17 15:35
非常期待 电源管理PSCI相关的文章,希望作者尽快发表啊,另外能不能对比一下 PSCI和SMP SPIN TABLE优劣主要对功耗的影响呢  期待作者
wowo
2015-09-18 12:20
@YANG23:多谢关注,其实一般情况下,不会深入到PSCI的,会用就可以了。
PSCI主要的特点,就是支持CPU hotplug。对功耗而言,PSCI的ops可能会单独core的power,因而肯定比SPIN table好。
firo
2015-08-30 20:25
非常期待 Linux CPU core的电源管理(5)_cpu control
这篇文章.
现在移植一个cpuidle功能到高版本内核, bootloader一走完, 就hang住了.
我猜和PM与SMP初始化哪里出错了. 很多代码不是我写的, 现在正在看.
请教lz, PM和smp初始化相关的代码有哪些呢?
wowo
2015-08-31 09:05
@firo:解决问题的时候,看代码不是最有效的方法,你可以用一些收到,查一查hang在哪里了。
另外,这个时候和PM没有关系吧?SMP的话,可以去“arch/xxx/kernel/smp.c”看看。
firo
2015-08-31 10:42
@wowo:感谢.

内核什么信息都没打印出来,就hang了.
因为我是只把上个版本cpuidle & suspend相关的代码和进来.系统就不能启动了. 所以和PM关系非常大.
snail
2015-09-01 09:45
@firo:可以把选项CONFIG_DEBUG_LL(kernel low-level debugging functions)打开,即使console还没有初始化,也可以用printascii等函数加入打印信息,这样就可以定位具体挂在哪里了?这个功能非常实用。
firo
2015-09-01 11:13
@snail:感谢!
昨天用printascii看到4个core都走到了cpu_startup_entry.看上去系统正常启动了.

1. 可能是console没有正常启动所以看不到printk之类的信息, 概率较小, 因为支部分代码没动过.
2. wowo知道用什么方法可以, 把printk在系统启动时打到console里面的信息用printascii 或者其他方法输出出来, 看看用户态是否起来了? 排除是否只是console有问题.
3. 还有一个问题, arm多核cpu_do_idle是用宏定义成processor._do_idle(), 我没有找到这个_do_idle是在哪里初始化的.
在setup_processor只看到了processor的整体赋值语句
list = lookup_processor_type(read_cpuid_id());
...
processor = *list->proc;
我昨天用printascii打印的时候只打印到
static void default_idle(void)
{
        if (arm_pm_idle)
                arm_pm_idle();
        else
                cpu_do_idle(); //这是个宏
        local_irq_enable();
}接下来不知道怎么走了.
wowo
2015-09-01 12:26
@firo:2. 很久以前我们做过,方法有多种,比如重写printk,调用printascii 输出。
3. processor的_do_idle,一般都是发指令到CPU core中了,不同平台不一样。一般情况下,跟到这里面,就没有方法接着跟了。
tigger
2015-08-20 14:51
cpu_online_bits,系统中所有运行状态的CPU core(后面会详细说明这个状态的意义);
系统是如果确定运行状态呢?
cpu_active_bits,有active的进程正在运行的CPU core。
这个online 与active 如何区别呢?
wowo
2015-08-20 17:11
@tigger:不好意思,一直空接着写这一块的东西:
cpu_online_bits比较容易理解,CPU启动的话(也即CPU运行了kernel代码,secondary_start_kernel),就认为是online的,会通过set_cpu_online接口设置这个bit mask。
而cpu_active_bits,则表示有任务在这个CPU上调度,由kenrel sched模块,调用set_cpu_active设置。
online和active的区别是,只要active,一定是online,因此online更多的代码了CPU的“物理状态”,而active,更多的是OS调度层面的抽象,CPU本身没有这一个状态。
buhui
2015-08-08 15:19
好文章,读这样的文章,就像饥饿的人扑到了面包上。比陈浩强的文章有天壤之别。
schedule
2015-05-10 14:57
高端手机平台现在都是cpuidle + scheduler(HMP) 做省功耗方案。hotplug只在thermal控制中使用了。
wowo
2015-05-11 10:29
@schedule:多谢分享,第一次听说HMP的概念,要了解了解。
zzq57683968
2015-05-24 22:42
@wowo:1、是的,64bit 4核以上arm cpu方案基本都采用HMP(GTS) + Interactive(DVFS)组合,但功耗调试需要花时间。
wowo
2015-05-25 11:05
@zzq57683968:原来HMP就是big·little模式的multi-processor,我对HMP这个词不太了解。big·little是ARM为了性能和功耗平衡搞出来的一个东西,和CPU topology有关。
DVFS还没有深入了解,就是我们项目加上去过一段时间,后来又去掉了,据说不太稳定,呵呵。
schedule
2015-05-10 14:38
CPU/GPU 绝对耗电大户啊

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog