CPU电源管理——基本概念和topology

Posted hellokitty2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CPU电源管理——基本概念和topology相关的知识,希望对你有一定的参考价值。

1. 相关名词解释

SMP:(Symmetric Multi-Processing)对称多处理,一个chip上集成多个核心
SMT:(Simultaneous multithreading)同时多线程,一个核心上实现多个hardware context,以支持多线程。通过复制硬件寄存器状态等手段,同时执行多个线程。

Node:某些Core之间,独享总线和memory,称作Node。Core只访问Node内的memory,因此可以减轻对总线和memory的带宽需求。但是有些场景下,Core会不可避免的访问其它Node的memory,这会造成很大的访问延迟。

NUMA: (Non-uniform Memory Access)不一致内存访问,以内存访问的不一致性为代价,减轻对总线和memory的带宽需求。这种结构对进程调度算法的要求较高,尽量减少跨Node的内存访问次数,以提升系统性能。

HMP:(Heterogeneous Multi-Processing)异构多处理,ARM的一种架构,在乎功耗的存在。HMP架构在一个chip中,封装两类ARM Core,一类为高性能Core(如Cortex-A15,也称作big core),一类为低性能Core(如Cortex-A7,也称作little core),因此HMP也称作big·little架构。
还有big-middle-little架构。

2. CPU topology除了描述CPU的组成之外,其主要功能是向kernel调度器提供必要的信息,以便让它合理地分配任务,最终达到性能和功耗之间的平衡。

CPU topology:Cluster-->Core-->Threads

3.CPU拓扑框架

-------------------------     ----------------------------  
|  CPU topology driver  |     |    Task Scheduler etc.  | 
-------------------------     ----------------------------
------------------------------------------------------- 
|      Kernel general CPU topology       | 
----------------------------------------------------------
---------------------------------------------------------- 
|      arch-dependent CPU topology       | 
---------------------------------------------------------- 

Kernel general CPU topology位于"include/linux/topology.h”中,定义了获取系统CPU topology信息的标准接口。底层的arch-dependent CPU topology会根据平台的特性,实现kernel定义的那些接口。

CPU topology信息有两个重要的使用场景:一是向用户提供当前的CPU信息(eg:lscpu),这是由CPU topology driver实现的;二是向调度器提供CPU core的信息,以便合理的调度任务。

3.1 Kernel general CPU topology

Kernel general CPU topology位于 include/linux/topology.h 中,主要以“#ifndef ... #define”类型的宏定义的形式提供API,其目的是:底层的arch-dependent CPU topology可以重新定义这些宏,只要底层有定义,则优先使用底层的,否则就使用Kernel general CPU topology中的默认API,主要包括:

/* include/linux/topology.h */
#ifndef topology_physical_package_id
#define topology_physical_package_id(cpu)       ((void)(cpu), -1)
#endif
#ifndef topology_core_id
#define topology_core_id(cpu)                   ((void)(cpu), 0)
#endif
#ifndef topology_thread_cpumask
#define topology_thread_cpumask(cpu)            cpumask_of(cpu)
#endif
#ifndef topology_core_cpumask
#define topology_core_cpumask(cpu)              cpumask_of(cpu)
#endif

#ifdef CONFIG_SCHED_SMT
static inline const struct cpumask *cpu_smt_mask(int cpu)
{
    return topology_thread_cpumask(cpu);
}
#endif

static inline const struct cpumask *cpu_cpu_mask(int cpu)
{
    return cpumask_of_node(cpu_to_node(cpu));
}

topology_physical_package_id:用于获取某个CPU的package ID,即socket(X86)或者cluster(ARM),具体意义依赖于具体平台的实现;
topology_core_id:某个CPU的core ID。即第二章所描述的core,具体意义依赖于具体的平台实现;
topology_thread_cpumask:获取和该CPU属于同一个core的所有CPU,通俗的讲,就是姐妹Thread;
topology_core_cpumask:获取和该CPU属于同一个cluster的所有CPU;
cpu_cpu_mask: 获取该CPU属于同一个Node的所有CPU;
cpu_smt_mask: 用于SMT调度(CONFIG_SCHED_SMT)的一个封装,意义同topology_thread_cpumask。

 

3.2 arch-dependent CPU topology

位于“arch/arm64/include/asm/topology.h”和“arch/arm64/kernel/topology.c”中,主要负责ARM64平台相关的topology转换,包括:

(1) 定义一个数据结构,以及基于该数据结构的变量,用于存储系统的CPU topology

/* arch/arm64/include/asm/topology.h */
struct cpu_topology {
    int thread_id;
    int core_id;
    int cluster_id;
    cpumask_t thread_sibling;
    cpumask_t core_sibling;
};
extern struct cpu_topology cpu_topology[NR_CPUS];

cluster_id、core_id、thead_id描述了拓扑结构的三个层次,thread_sibling和core_sibling,保存了和该CPU位于相同级别(同一个core和同一个cluster)的所有姐妹CPU。系统中每个CPU(个数由NR_CPUS指定,是从OS的角度看的)都有一个struct cpu_topology变量,用于描述该CPU在整个topology中的地位。以数组的形式维护。

(2)重定义CPU topology有关的宏定义

/* arch/arm64/include/asm/topology.h */
#define topology_physical_package_id(cpu)       (cpu_topology[cpu].cluster_id)
#define topology_core_id(cpu)           (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu)      (&cpu_topology[cpu].core_sibling)
#define topology_thread_cpumask(cpu)    (&cpu_topology[cpu].thread_sibling)

实现比较简单,从该CPU对应的struct cpu_topology变量中取出指定的字段即可。

(3)提供初始化并构建CPU topology的方法,以便在系统启动时调用

/* arch/arm64/include/asm/topology.h */
void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid);

init_cpu_topology的调用路径是:kernel_init-->smp_prepare_cpus-->init_cpu_topology,主要完成如下任务:

store_cpu_topology的调用路径是:kernel_init-->smp_prepare_cpus-->store_cpu_topology,在没有从DTS中成功获取CPU topology的情况下,从ARM64的MPIDR寄存器中读取topology信息。

设备树中的cpu-map和clusterX描述了CPU的拓扑结构,具体可参考“Documentation/devicetree/bindings/arm/topology.txt”中的描述。

3.3 CPU topology driver

CPU topology driver位于“driversase opology.c”中,基于“include/linux/topology.h”所提供的API,以sysfs的形式,向用户空间提供获取CPU topology信息的接口,lscpu应用,就是基于该接口实现的。sysfs的格式可参考“Documentation/cputopology.txt”。

/sys/devices/system/cpu/cpuX/topology/下

physical_package_id: //就是此CPU位于的Cluster编号
core_id: //在一个Cluster内此CPU的编号
thread_siblings: //每个CPU核的位掩码,CPU0 CPU1 CPU2分别为0x1 0x2 0x4
thread_siblings_list: //CPU是几这个就是几,CPU0就是0,CPU7就是7
core_siblings: //每个Cluster内的CPU组成的位掩码,若四小核Cluster0就是0x0f,3中核就是0x70
core_siblings_list: //每个Cluster内的CPU组成的数字加中画线显示,若4小核,3中核,1大核,小核的是0-3,中核就是4-6,大核就是7

/sys/devices/system/cpu/下

kernel_max 一共有多少个核,7
kernel_max: 31
offline: 2,4-31,32-63
online: 0-1,3
possible: 0-31
present: 0-31

 

4. CPU一共有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。

 

 

参考:

Linux CPU core的电源管理(1)_概述: http://www.wowotech.net/pm_subsystem/cpu_core_pm_overview.html

Linux CPU core的电源管理(2)_cpu topology:http://www.wowotech.net/pm_subsystem/cpu_topology.html

 

以上是关于CPU电源管理——基本概念和topology的主要内容,如果未能解决你的问题,请参考以下文章

storm中的基本概念

黑苹果解锁CFG LOCK教程,开启原生电源管理,体验更完美的睡眠和CPU变频

Storm基本概念以及Topology的并发度

错误的CPU时间片大小概念

Linux内核设计与实现 进程调度1: 基本概念

多线程上下文切换