精华内容
下载资源
问答
  • 自动cpufreq 用于Linux的自动CPU速度和功率优化器,基于对笔记本电脑电池状态,CPU使用率,CPU温度和系统负载的主动监视。 最终,您可以在不做任何妥协的情况下延长电池寿命。 对于tl; dr人员,有一个: 为什么...
  • cpufreq patch

    2021-05-12 13:08:09
    ++#include ++static struct regulator *vddarm;++static unsigned long regulator_latency;+static unsigned long emxx_cpufreq;+struct emxx_dvfs {+ unsigned int vddarm_min;+ unsigned int vddarm_max;+}...

    +

    +#include +

    +static struct regulator *vddarm;

    +

    +static unsigned long regulator_latency;

    +static unsigned long emxx_cpufreq;

    +struct emxx_dvfs {

    +    unsigned int vddarm_min;

    +    unsigned int vddarm_max;

    +};

    +

    +static struct emxx_dvfs emxx_dvfs_table[] = {

    +    [0] = { 1000000, 1150000 },

    +    [1] = { 1050000, 1150000 },

    +    [2] = { 1100000, 1150000 },

    +    [3] = { 1200000, 1350000 },

    +};

    +

    +static struct cpufreq_frequency_table emxx_freq_table[] = {

    +    { 0, 1062000 },

    +    { 0, 1062000 },

    +    { 1, 1062000 },

    +    { 1, 1062000 },

    +    { 2, 1062000 },

    +    { 2, 1062000 },

    +    { 2, 1062000 },

    +    { 2, 1062000 },

    +    { 3, 1062000 },

    +    { 0, CPUFREQ_TABLE_END },

    +};

    +

    +static int emxx_cpufreq_verify_speed(struct cpufreq_policy *policy)

    +{

    +    return cpufreq_frequency_table_verify(policy, emxx_freq_table);

    +}

    +

    +static unsigned int emxx_cpufreq_get_speed(unsigned int cpu)

    +{

    +    return emxx_cpufreq;

    +}

    +

    +static int emxx_cpufreq_set_target(struct cpufreq_policy *policy,

    +                      unsigned int target_freq,

    +                      unsigned int relation)

    +{

    +    int ret;

    +    unsigned int i;

    +    struct cpufreq_freqs freqs;

    +    struct emxx_dvfs *dvfs;

    +

    +    ret = cpufreq_frequency_table_target(policy, emxx_freq_table,

    +                         target_freq, relation, &i);

    +    if (ret != 0)

    +        return ret;

    +

    +    freqs.cpu = 0;

    +    freqs.old = emxx_cpufreq;

    +    freqs.new = emxx_freq_table[i].frequency;

    +    freqs.flags = 0;

    +    dvfs = &emxx_dvfs_table[emxx_freq_table[i].index];

    +

    +    if (freqs.old == freqs.new)

    +        return 0;

    +

    +    pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);

    +

    +    cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);

    +

    +#ifdef CONFIG_REGULATOR

    +    if (vddarm && freqs.new < freqs.old) {

    +        ret = regulator_set_voltage(vddarm,

    +                        dvfs->vddarm_min,

    +                        dvfs->vddarm_max);

    +        if (ret != 0) {

    +            pr_err("cpufreq: Failed to set VDDARM for %dkHz: %d\n",

    +                   freqs.new, ret);

    +            goto err_clk;

    +        }

    +    }

    +#endif

    +

    +    cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);

    +

    +    return 0;

    +}

    +

    +#ifdef CONFIG_REGULATOR

    +static void __init emxx_cpufreq_config_regulator(void)

    +{

    +    int count, v, i, found;

    +    struct cpufreq_frequency_table *freq;

    +    struct emxx_dvfs *dvfs;

    +

    +    count = regulator_count_voltages(vddarm);

    +    if (count < 0) {

    +        pr_err("cpufreq: Unable to check supported voltages\n");

    +    }

    +

    +    freq = emxx_freq_table;

    +    while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {

    +        if (freq->frequency == CPUFREQ_ENTRY_INVALID)

    +            continue;

    +

    +        dvfs = &emxx_dvfs_table[freq->index];

    +        found = 0;

    +

    +        for (i = 0; i < count; i++) {

    +            v = regulator_list_voltage(vddarm, i);

    +            if (v >= dvfs->vddarm_min && v <= dvfs->vddarm_max)

    +                found = 1;

    +        }

    +

    +        if (!found) {

    +            pr_debug("cpufreq: %dkHz unsupported by regulator\n",

    +                 freq->frequency);

    +            freq->frequency = CPUFREQ_ENTRY_INVALID;

    +        }

    +

    +        freq++;

    +    }

    +

    +    /* Guess based on having to do an I2C/SPI write; in future we

    +     * will be able to query the regulator performance here. */

    +    regulator_latency = 1 * 1000 * 1000;

    +}

    +#endif

    +

    +static int __init emxx_cpufreq_driver_init(struct cpufreq_policy *policy)

    +{

    +    int ret;

    +    unsigned int i;

    +    unsigned int bogomips = 0;

    +    struct cpufreq_frequency_table *freq;

    +

    +    if (emxx_freq_table == NULL) {

    +        pr_err("cpufreq: No frequency information for this CPU\n");

    +        return -ENODEV;

    +    }

    +

    +#ifdef CONFIG_REGULATOR

    +    vddarm = regulator_get(NULL, "vddarm");

    +    if (IS_ERR(vddarm)) {

    +        ret = PTR_ERR(vddarm);

    +        pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);

    +        pr_err("cpufreq: Only frequency scaling available\n");

    +        vddarm = NULL;

    +    } else {

    +        emxx_cpufreq_config_regulator();

    +    }

    +#endif

    +

    +    for_each_online_cpu(i)

    +    {

    +        bogomips = per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ);

    +    }

    +

    +    emxx_cpufreq = (bogomips + 5)* 1000 / 2;

    +

    +    freq = emxx_freq_table;

    +    while (freq->frequency != CPUFREQ_TABLE_END) {

    +

    +        if (emxx_cpufreq != freq->frequency) {

    +

    +            freq->frequency = emxx_cpufreq;

    +        }

    +

    +        freq++;

    +    }

    +

    +    policy->cur = emxx_cpufreq;

    +

    +    /* Datasheet says PLL stabalisation time (if we were to use

    +     * the PLLs, which we don't currently) is ~300us worst case,

    +     * but add some fudge.

    +     */

    +    policy->cpuinfo.transition_latency = (500 * 1000) + regulator_latency;

    +

    +    ret = cpufreq_frequency_table_cpuinfo(policy, emxx_freq_table);

    +    if (ret != 0) {

    +        pr_err("cpufreq: Failed to configure frequency table: %d\n",

    +               ret);

    +        regulator_put(vddarm);

    +    }

    +    return ret;

    +}

    +

    +static struct cpufreq_driver emxx_cpufreq_driver = {

    +    .owner        = THIS_MODULE,

    +    .flags          = 0,

    +    .verify        = emxx_cpufreq_verify_speed,

    +    .target        = emxx_cpufreq_set_target,

    +    .get        = emxx_cpufreq_get_speed,

    +    .init        = emxx_cpufreq_driver_init,

    +    .name        = "emev",

    +};

    +

    +static int __init emxx_cpufreq_init(void)

    +{

    +    return cpufreq_register_driver(&emxx_cpufreq_driver);

    +}

    +module_init(emxx_cpufreq_init);

    --

    1.7.5.4

    展开全文
  • CPUFreq开发指南 1 概述 2 代码路径 3 配置⽅法 3.1 Menuconfig配置 3.2 Clock配置 3.3 Regulator配置 3.4 OPP Table配置 3.4.1 增加OPP Table 3.4.2 删除OPP 3.5 根据leakage调整OPP Table 3.5.1 根据...
  • 英特尔P状态和CPUFreq管理器小部件 - Important 截至2020年10月11日,我不再愿意维护此小部件。 我将仅根据我的个人需求进行维护。 感谢您一直以来的支持和反馈。 希望社区能够从这里接管工作,并使小部件变得比...
  • linux cpufreq framework(1)_概述作者:wowo 发布于:2015-6-13 22:20分类:电源管理子系统1. 前言linux kernel主要通过三类机制实现SMP系统CPU core的电源管理功能: 1)cpu hotplug。根据应用场景,enable/disable ...

    linux cpufreq framework(1)_概述

    作者:wowo 发布于:2015-6-13 22:20

    分类:电源管理子系统

    1. 前言

    linux kernel主要通过三类机制实现SMP系统CPU core的电源管理功能: 1)cpu hotplug。根据应用场景,enable/disable CPU core,具体可参考“Linux CPU core的电源管理(4)_cpu control”。

    2) cpuidle framework。在没有进程调度的时候,让CPU core进入idle状态,具体可参考“cpuidle framework系列文章”。

    3) cpufreq framework。根据使用场景和系统负荷,调整CPU core的电压(voltage)和频率(frequency),具体可参考本文以及后续cpufreq相关的。

    对CPU core来说,功耗和性能是一对不可调和的矛盾,通过调整CPU的电压和频率,可以在功耗和性能之间找一个平衡点。由于调整是在系统运行的过程中,因此cpufreq framework的功能也称作动态电压/频率调整(Dynamic Voltage/Frequency Scaling,DVFS)。

    本文主要从功能说明和软件架构两个角度介绍cpufreq framework。

    2. 功能说明

    cpufreq framework的核心功能,是通过调整CPU core的电压和频率,兼顾系统的性能和功耗。在不需要高性能时,降低电压和频率,以降低功耗;在需要高性能时,提高电压和频率,以提高性能。要达到此目的,有两个关键点: 1)如果控制CPU core的电压和频率。

    2)何时改变CPU core的电压和频率。

    针对这两个关键点,CPU core有两种实现。

    实现1:CPU core根据自身的负荷,自动调整电压和频率,不需要OS级别的软件参与。 这种实现,软件复杂度非常低,通常情况下,只需要告诉CPU core电压和频率的调整范围(通过频率表示,scaling_min_freq和scaling_max_freq,也称作policy),CPU core即可自行调整。因此:

    关键点1,由CPU core自行处理;

    关键点2,OS需要根据大致的应用场景(例如,是高性能场景,还是低性能场景),设定一个频率范围,改变时机,由CPU core自行决定。

    注1:由于软件参与度小,该实现的省电效率可能较低。

    实现2:CPU core不参与任何的逻辑动作,由OS软件根据系统运行情况,调整电压和频率。 这种实现,几乎完全由软件掌控DVFS行为:

    关键点2,根据应用场景,手动(用户发起,例如省电模式)或者自动(软件自动调整,例如HMP)的调整。

    注2:对关键点2来说,如果调整比较频繁,则需要CPU core在不同频率之间转换的速度足够快,后面会详细介绍。

    为了实现上述功能需求,cpufreq framework抽象出cpufreq driver、cpufreq policy(策略)、cpufreq governor等多个软件实体,具体请参考下面的说明。

    3. 软件架构

    cpufreq framework的软件架构如下面图片所示:

    ce8a1ac21747b11fb7f0363cf7d5a732.gif 对下,cpufreq framework基于cpu subsystem driver、OPP、clock framework、regulator framework等模块,提供对CPU core频率和电压的控制。这一部分主要由cpufreq driver实现。

    对上,cpufreq framework会通过cpufreq core、cpufreq governors、cpufreq stats等模块,以sysfs的形式,向用户空间提供cpu frequency的查询、控制等接口。同时,在频率改变的时候,通过notifier通知关心的driver。

    内部,cpufreq framework包括cpufreq core、cpufreq driver、cpufreq governors、cpufreq stats等模块,具体功能会在下一章详细分析。

    注3:cpufreq driver中有,有一个特别的driver----arm big·little driver,用于实现ARM平台big·little的切换逻辑。虽然arm bit·little和cpufreq不是同一个概念,但它们的目的和逻辑非常类似,因此就放到这里了。后续会有专门的文章介绍该功能,因此分析cpufreq framework其它内容时,会直接把它忽略不表。

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

    4.1 cpufreq core

    cpufreq core是cpufreq framework的核心模块,和kernel其它framework类似,它主要实现三类功能: 对上,以sysfs的形式向用户空间提供统一的接口,以notifier的形式向其它driver提供频率变化的通知;

    对下,提供CPU core频率和电压控制的驱动框架,方便底层driver的开发;同时,提供governor框架,用于实现不同的频率调整机制;

    内部,封装各种逻辑,实现所需功能。这些逻辑主要围绕struct cpufreq_driver、struct cpufreq_policy和struct cpufreq_governor三个数据结构进行,下面会详细分析。

    1)struct cpufreq_driver

    struct cpufreq_driver用于抽象cpufreq驱动,是平台驱动工程师关注最多的结构,其定义如下:

    1: /* include/linux/cpufreq.h */

    2: struct cpufreq_driver {

    3: char name[CPUFREQ_NAME_LEN];

    4: u8 flags;

    5: void *driver_data;

    6:

    7: /* needed by all drivers */

    8: int (*init) (struct cpufreq_policy *policy);

    9: int (*verify) (struct cpufreq_policy *policy);

    10:

    11: /* define one out of two */

    12: int (*setpolicy) (struct cpufreq_policy *policy);

    13:

    14: /*

    15: * On failure, should always restore frequency to policy->restore_freq

    16: * (i.e. old freq).

    17: */

    18: int (*target) (struct cpufreq_policy *policy, /* Deprecated */

    19: unsigned int target_freq,

    20: unsigned int relation);

    21: int (*target_index) (struct cpufreq_policy *policy,

    22: unsigned int index);

    23: /*

    24: * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION

    25: * unset.

    26: *

    27: * get_intermediate should return a stable intermediate frequency

    28: * platform wants to switch to and target_intermediate() should set CPU

    29: * to to that frequency, before jumping to the frequency corresponding

    30: * to 'index'. Core will take care of sending notifications and driver

    31: * doesn't have to handle them in target_intermediate() or

    32: * target_index().

    33: *

    34: * Drivers can return '0' from get_intermediate() in case they don't

    35: * wish to switch to intermediate frequency for some target frequency.

    36: * In that case core will directly call ->target_index().

    37: */

    38: unsigned int (*get_intermediate)(struct cpufreq_policy *policy,

    39: unsigned int index);

    40: int (*target_intermediate)(struct cpufreq_policy *policy,

    41: unsigned int index);

    42:

    43: /* should be defined, if possible */

    44: unsigned int (*get) (unsigned int cpu);

    45:

    46: /* optional */

    47: int (*bios_limit) (int cpu, unsigned int *limit);

    48:

    49: int (*exit) (struct cpufreq_policy *policy);

    50: void (*stop_cpu) (struct cpufreq_policy *policy);

    51: int (*suspend) (struct cpufreq_policy *policy);

    52: int (*resume) (struct cpufreq_policy *policy);

    53: struct freq_attr **attr;

    54:

    55: /* platform specific boost support code */

    56: bool boost_supported;

    57: bool boost_enabled;

    58: int (*set_boost) (int state);

    59: };

    介绍该结构之前,我们先思考一个问题:由设备模型可知,driver是用来驱动设备的,那么struct cpufreq_driver所对应的设备是什么?也许从该结构中回调函数的参数可以猜到,是struct cpufreq_policy。但这相当难以理解,后面再分析。

    name,该driver的名字,需要唯一,因为cpufreq framework允许同时注册多个driver,用户可以根据实际情况选择使用哪个driver。driver的标识,就是name。

    flags,一些flag,具体会在后续的文章中介绍。

    init,driver的入口,由cpufreq core在设备枚举的时候调用,driver需要根据硬件情况,填充policy的内容。

    verify,验证policy中的内容是否符合硬件要求。它和init接口都是必须实现的接口。

    setpolicy,对于第2章所讲的“实现一”,driver需要提供这个接口,用于设置CPU core动态频率调整的范围(即policy)。

    target、target_index,对于第2章所讲的“实现二”,driver需要实现这两个接口中的一个(target为旧接口,不推荐使用),用于设置CPU core为指定频率(同时修改为对应的电压)。

    后面的接口都是可选的,会在后续的章节中再分析。

    有关struct cpufreq_driver的API包括:

    1: int cpufreq_register_driver(struct cpufreq_driver *driver_data);

    2: int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);

    3:

    4: const char *cpufreq_get_current_driver(void);

    5: void *cpufreq_get_driver_data(void);

    分别为driver的注册、注销。获取当前所使用的driver名称,以及该driver的私有数据结构(driver_data字段)。

    2)struct cpufreq_policy

    struct cpufreq_policy是比较抽象的一个数据结构(蜗蜗觉得,是cpufreq framework中最难理解的地方),我们需要借助cpufreq core中的一些实现逻辑,去分析、理解它。

    前面我们提到过一个问题,cpufreq driver对应的设备是什么?kernel是这样抽象cpufreq的:

    4ca3bfb066141c7c0d78978b561433fb.gif 抽象出一个CPU bus(对应的sysfs目录为/sys/devices/system/cpu/,具体可参考cpu subsystem driver相关的描述),所有的CPU device都挂在这个bus上。cpufreq是CPU device的一类特定功能,被抽象为一个subsys interface(有关subsys interface的概念,请参考“Linux设备模型(6)_Bus”)。

    当CPU device和CPU driver匹配时,bus core会调用subsys interface的add_dev回调函数,相当于为该特定功能添加一个“device”,进而和该特定功能的“driver”(这里为cpufreq driver)匹配,执行driver的初始化(probe,或者其它)接口。

    那么该“特定功能”应该用什么样的“device”表示呢?应具体功能具体对待。kernel使用cpufreq policy(即“调频策略”)来抽象cpufreq。所谓的调频策略,即频率调整的范围,它从一定程度上,代表了cpufreq的属性。这就是struct cpufreq_policy结构的现实意义:

    1: struct cpufreq_policy {

    2: /* CPUs sharing clock, require sw coordination */

    3: cpumask_var_t cpus; /* Online CPUs only */

    4: cpumask_var_t related_cpus; /* Online + Offline CPUs */

    5:

    6: unsigned int shared_type; /* ACPI: ANY or ALL affected CPUs

    7: should set cpufreq */

    8: unsigned int cpu; /* cpu nr of CPU managing this policy */

    9: unsigned int last_cpu; /* cpu nr of previous CPU that managed

    10: * this policy */

    11: struct clk *clk;

    12: struct cpufreq_cpuinfo cpuinfo;/* see above */

    13:

    14: unsigned int min; /* in kHz */

    15: unsigned int max; /* in kHz */

    16: unsigned int cur; /* in kHz, only needed if cpufreq

    17: * governors are used */

    18: unsigned int restore_freq; /* = policy->cur before transition */

    19: unsigned int suspend_freq; /* freq to set during suspend */

    20:

    21: unsigned int policy; /* see above */

    22: struct cpufreq_governor *governor; /* see below */

    23: void *governor_data;

    24: bool governor_enabled; /* governor start/stop flag */

    25:

    26: struct work_struct update; /* if update_policy() needs to be

    27: * called, but you're in IRQ context */

    28:

    29: struct cpufreq_real_policy user_policy;

    30: struct cpufreq_frequency_table *freq_table;

    31:

    32: struct list_head policy_list;

    33: struct kobject kobj;

    34: struct completion kobj_unregister;

    35:

    36: /*

    37: * The rules for this semaphore:

    38: * - Any routine that wants to read from the policy structure will

    39: * do a down_read on this semaphore.

    40: * - Any routine that will write to the policy structure and/or may take away

    41: * the policy altogether (eg. CPU hotplug), will hold this lock in write

    42: * mode before doing so.

    43: *

    44: * Additional rules:

    45: * - Lock should not be held across

    46: * __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);

    47: */

    48: struct rw_semaphore rwsem;

    49:

    50: /* Synchronization for frequency transitions */

    51: bool transition_ongoing; /* Tracks transition status */

    52: spinlock_t transition_lock;

    53: wait_queue_head_t transition_wait;

    54: struct task_struct *transition_task; /* Task which is doing the transition */

    55:

    56: /* For cpufreq driver's internal use */

    57: void *driver_data;

    58: };

    该结构看着很复杂,现在只需要关心几个事情:

    min/max frequency,调频范围,对于可以自动调频的CPU而言,只需要这两个参数就够了。

    current frequency和governor,对于不能自动调频的CPU,需要governor设置具体的频率值。下面介绍一下governor。

    struct cpufreq_policy不会直接对外提供API。

    3) cpufreq governors

    governor的概念可参考“Linux cpuidle framework(1)_概述和软件架构”中相关的描述。对于不能自动调频的CPU core,必须由软件设定具体的频率值。根据使用场景的不同,会有不同的调整方案,这是由governor模块负责的,如下:

    1: struct cpufreq_governor {

    2: char name[CPUFREQ_NAME_LEN];

    3: int initialized;

    4: int (*governor) (struct cpufreq_policy *policy,

    5: unsigned int event);

    6: ssize_t (*show_setspeed) (struct cpufreq_policy *policy,

    7: char *buf);

    8: int (*store_setspeed) (struct cpufreq_policy *policy,

    9: unsigned int freq);

    10: unsigned int max_transition_latency; /* HW must be able to switch to

    11: next freq faster than this value in nano secs or we

    12: will fallback to performance governor */

    13: struct list_head governor_list;

    14: struct module *owner;

    15: };

    name,该governor的名称。

    governor,用于governor状态切换的回调函数。

    show_setspeed、store_setspeed,用于提供sysfs “setspeed” attribute文件的回调函数。

    max_transition_latency,该governor所能容忍的最大频率切换延迟。

    cpufreq governors主要向具体的governor模块提供governor的注册和注销接口,具体会在后续的文章中详细描述。

    4)通过sysfs向用户空间提供的接口

    请参考“linux cpufreq framework(3)_cpufreq core”。

    4.3 cpufreq drivers

    各个driver模块会基于cpufreq core实现具体的driver,请参考“linux cpufreq framework(2)_cpufreq driver”。

    4.4 cpufreq stats

    5. 总结

    本文介绍了cpufreq framework的基本情况,后面通过以下的文章,分析其它内容:

    linux cpufreq framework(3)_cpufreq core,分析cpufreq的内部实现,并总结cpufreq提供的sysfs接口,介绍怎么通过sysfs,控制系统的调频行为;

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

    评论:

    lolo84

    2016-12-09 08:52

    群主,我是那个一直在问怎么在linux下运用api函数动态调整时钟频率的,请问devfreq 的调整有相应的帖子吗?

    2016-12-09 09:42

    @lolo84:抱歉啊,我没有写过devfreq,因为觉得现在用到的不是很多。

    2016-03-27 18:20

    1)如果控制CPU core的电压和频率。

    挑一个错别字, 应该是 “如何控制“ 吧

    kobe.bao

    2016-03-07 20:45

    Hi wowo:

    关于电源管理,有个问题请教,是这样的(高通soc芯片):

    需要regulator供电的外设,都会在其DTS中对regulator进行设置(暂且称之为regulator设置节点),例如:

    qcom,ctrl-supply-entry@0 {

    qcom,supply-name = "vdda";

    qcom,supply-min-voltage = <1250000>;

    qcom,supply-max-voltage = <1250000>;

    ...

    };

    驱动代码中会对该节点进行解析,利用regulator_get、regulator_count_voltages等API函数进行设置。

    通常,外设的DTS中还有一个这样的节点,例如:

    vdda-supply =

    该节点的解释是“Phandle for vreg regulator device node”,暂且称为regulator设备节点。但是我在代码中并没有找到对该节点的解析,我想请问,regulator设备节点与regulator设置节点是怎么联系起来的?

    kobe.bao

    2016-03-07 20:47

    @kobe.bao:sorry,我发错地方了

    2015-09-27 15:18

    hi,wowo:

    文中多次提到cpu core 自动调频,可以根据自身的负载进行调频,只需要软件设置频率最大和最小调节范围即可,这个自调节是硬件自己实现的吗?之前没听说过,有没有相关的资料或者代码之类的可以阅读参考?

    2015-09-27 17:26

    @paoshapaoxue:是这样的。据我所知,kernel中支持cpufreq的那些CPU中,只有intel和索尼的LongRun有这样的特性。代码可以参考“drivers/cpufreq/longrun.c”,不过最好能拿到这些CPU的资料,遗憾的是我也没有。

    2015-08-20 17:15

    hi,wowo:

    你在本文中说的 hot plut 功能可以参考文章“Linux CPU core的电源管理(4)_cpu control” 这个文章我怎么一直没找到呢,是不是还没有完成啊?

    wowo

    2015-08-20 17:37

    @paoshapaoxue:是的,没有加超链接的引用,就是没来得及写,抱歉哈

    dashan

    2015-07-14 21:43

    你好蜗窝,感谢你分享了这么好的文章。现在有一个问题请教一下,我的系统ca9,双核,cpu1&cpu0,自己开发的网卡驱动,工作正常,假设其中断为neta-irq, 如果把beta-irq亲和性设置到cpu1, 发流正常,中断在cpu1正确处理,之后offline cpu1, 中断迁移到cpu 0上,中断依然可以正确处理,收发正常,但是再执行online命令把cpu1启动起来的时候却失败了,这个问题必须发流触发中断才能复现,我分析下来发现cpu-secondary-kernel没有执行,您能否给点建议,我看不出哪里出错了,谢谢

    2015-07-14 22:09

    @dashan:建议从“为什么”cpu secondary kernel“没有执行查起,大致的调用流程是:

    cpu_up-->_cpu_up-->__cpu_up(arch/arm/kernel/smp.c)-->smp_ops.smp_boot_secondary

    在这些函数里面加一些打印,查一下在哪里终止的,大概就明白原因了。

    dashan

    2015-07-17 12:41

    @wowo:谢谢,当时有点记错了,是secondary_start_kernel没有被执行,这部分代码是汇编相关的。请问怎么在汇编加打印? 下面是当时写的邮件:

    axxx_secondary_startup    secondary_startup  __secondary_switched  secondary_start_kernel

    in C function “arm_xxx_boot_secondary” (located in file platsmp-xxx.c), pointer of “axxx_secondary_startup” is written to a address as following, do you know when and where to run the code in that address of “pmsu_mp_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)”?

    if want to start cpu1, secondary_start_kernel must be called, but from my log, this function is not called when the issue happen? I need to know why it is not called.

    Would you like to tell me some details about it? thank you.

    pmsu_set_cpu_boot_addr(cpu, axxx_secondary_startup);

    ……

    void pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)

    {

    writel(virt_to_phys(boot_addr), pmsu_mp_base +

    PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));

    }

    谢谢

    2015-07-17 14:23

    @dashan:据您描述,cpu_die之后,CPU1应该是被掉电了。然后在.smp_boot_secondary()中,会重新上电,CPU1从bootloader开始执行,执行的代码就是“pmsu_mp_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)”。

    cpu up失败,没有执行secondary_startup的原因,可能包括:

    1. 上电失败,CPU压根没有执行。

    2. CPU上电到执行“pmsu_mp_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)”处代码之间,出现问题。

    3. “pmsu_mp_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)”中的数据丢失,

    但和网卡的中断发流有什么关系呢?发流导致有些内存被覆盖?

    正面的查法,还是顺着secondary cpu boot的流程,检查异常的位置。不用打印,可以用其它方法,比如点LED,实在不行,拉GPIO也行。找到异常位置之后,就很好找到原因。

    侧面的查法,可以让网卡只产生中,不发流,看看是否出问题,这样可以知道到底是中断的原因,还是发流的原因,然后再进一步debug。

    dashan

    2015-07-17 22:19

    @wowo:非常感谢您的回复,我会尝试按你说的调试,有发现再告诉你

    bear20081015

    2015-06-24 02:46

    能否介绍下确定一款SOC的频点和电压的原则或方法?比如拿到一款新的SOC,我们应该给它选定哪些频点和电压呢。个人理解选好了这个,再加上cpufreq的软件框架,才能很好的达到power优化的目标吧?

    2015-06-24 09:45

    @bear20081015:据我所知,选频点的一般做法是:

    1. 根据SOC的spec,确定soc支持的频率和电压范围。

    2. 基于性能和功耗的考量,在允许范围内,选出一些潜在的组合。

    3. 通过大规模的老化测试(一般一天测试一个频点,需要尽量多的设备参与),剔除那些不稳定的频点,同时选出可工作的最低和最高频点。

    4. 根据实际的应用情况,在cpufreq中保留几个,用作日常调频。一般3~5个就够了。

    发表评论:

    昵称

    邮件地址 (选填)

    个人主页 (选填)

    d4e3789769c8ad44c7e403863bfc3822.png

    展开全文
  • Cpufreq

    2018-10-16 15:19:52
    引用文章链接: http://www.ibm.com/developerworks/cn/linux/l-cn-cpufreq/ ...   Cpufreq 的由来  随着 energy efficient computing 和 performance per w...

    引用文章链接:

    http://www.ibm.com/developerworks/cn/linux/l-cn-cpufreq/

    http://blog.csdn.net/linweig/archive/2010/10/28/5972312.aspx

     

    Cpufreq 的由来

         随着 energy efficient computing 和 performance per watt 等概念的推广以及高级配置与电源接口ACPI(Advanced Configuration and Power Interface)标准的发展,目前市场上的主流 CPU 都提供了对变频(frequency scaling)技术的支持。例如Intel®处理器所支持的 Enhanced SpeedStep® 技术和 AMD® 处理器所支持的 PowerNow! ® 技术,另外像最新的 PowerPC®、ARM®、SPARC® 和 SuperH® 等处理器中也提供了类似的支持。参考资料中列出了当前 Linux 2.6内核所支持的具备变频技术的处理器。需要注意的是,这里要讨论的变频技术与大家以前所熟知的超频是两个不同的概念。超频是指通过提高核心电压等手段让处理器工作在非标准频率下的行为,这往往会造成 CPU 使用寿命缩短以及系统稳定性下降等严重后果。而变频技术是指CPU硬件本身支持在不同的频率下运行,系统在运行过程中可以根据随时可能发生变化的系统负载情况动态在这些不同的运行频率之间进行切换,从而达到对性能和功耗做到二者兼顾的目的。

    虽然多个处理器生产厂家都提供了对变频技术的支持,但是其硬件实现和使用方法必然存在着细微甚至巨大的差别。这就使得每个处理器生产厂家都需要按照其特殊的硬件实现和使用方法向内核中添加代码,从而让自己产品中的变频技术在 Linux 中得到支持和使用。然而,这种内核开发模式所导致的后果是各个厂家的实现代码散落在 Linux 内核代码树的各个角落里,各种不同的实现之间没有任何代码是共享的,这给内核的维护以及将来添加对新的产品的支持都带来了巨大的开销,并直接导致了 cpufreq 内核子系统的诞生。实际上,正如前文所说,发明变频技术的目的是为了能够让系统在运行过程中随时根据系统负载的变化动态调整 CPU 的运行频率。这件事情可以分为两个部分,一部分是“做什么”的问题,另一部分是“怎么做”的问题。“做什么”是指如何根据系统负载的动态变化挑选出 CPU 合适的运行频率,而“怎么做”就是要按照选定的运行频率在选定的时间对 CPU 进行设置,使之真正工作在这一频率上。这也就是我们在软件设计中经常会遇到的机制 mechanism 与策略 policy 的问题,而设计良好的软件会在架构上保证二者是被清晰的隔离开的并通过规范定义的接口进行通信。

     

    Cpufreq 的设计和使用

    为了解决前文所提到的问题,一个新的内核子系统—— cpufreq 应运而生了。Cpufreq 为在Linux 内核中更好的支持不同 CPU 的变频技术提供了一个统一的设计框架,其软件结构如图 1 所示。


    图 1. Cpufreq 的软件结构

    如图 1 所示,cpufreq 在设计上主要分为以下三个模块:

    • Cpufreq 模块(cpufreq module)对如何在底层控制各种不同 CPU 所支持的变频技术以及如何在上层根据系统负载动态选择合适的运行频率进行了封装和抽象,并在二者之间定义了清晰的接口,从而在设计上完成了前文所提到的对 mechanism 与 policy 的分离。
    • 在 cpufreq 模块的底层,各个 CPU 生产厂商只需根据其变频技术的硬件实现和使用方法提供与其 CPU 相关的变频驱动程序(CPU-specific drivers),例如 Intel 需要提供支持 Enhanced SpeedStep 技术的 CPU 驱动程序,而 AMD 则需要提供支持 PowerNow! 技术的 CPU 驱动程序。
    • 在 cpufreq 模块的上层,governor 作为选择合适的目标运行频率的决策者,根据一定的标准在适当的时刻选择出 CPU 适合的运行频率,并通过 cpufreq 模块定义的接口操作底层与 CPU 相关的变频驱动程序,将 CPU 设置运行在选定的运行频率上。目前最新的 Linux 内核中提供了 performance 、powersave 、userspace、conservative 和 ondemand 五种 governors 供用户选择使用,它们在选择 CPU 合适的运行频率时使用的是各自不同的标准并分别适用于不同的应用场景。用户在同一时间只能选择其中一个 governor 使用,但是可以在系统运行过程中根据应用需求的变化而切换使用另一个 governor 。

           这种设计带来的好处是使得 governor 和 CPU 相关的变频驱动程序的开发可以相互独立进行,并在最大限度上实现代码重用,内核开发人员在编写和试验新的 governor 时不会再陷入到某款特定 CPU 的变频技术的硬件实现细节中去,而 CPU 生产厂商在向 Linux 内核中添加支持其特定的 CPU 变频技术的代码时只需提供一个相对来说简单了很多的驱动程序,而不必考虑在各种不同的应用场景中如何选择合适的运行频率这些复杂的问题。

         内核中的 cpufreq 子系统通过 sysfs 文件系统向上层应用提供了用户接口,对于系统中的每一个 CPU 而言,其 cpufreq 的 sysfs 用户接口位于 /sys/devices/system/cpu/cpuX/cpufreq/ 目录下,其中 X 代表 processor id ,与 /proc/cpuinfo 中的信息相对应。以 cpu0 为例,用户一般会在该目录下观察到以下文件:

    $ ls -F /sys/devices/system/cpu/cpu0/cpufreq/
    affected_cpus
    cpuinfo_cur_freq
    cpuinfo_max_freq
       
      cpuinfo_min_freq
    ondemand/
    scaling_available_frequencies
    scaling_available_governors
    scaling_cur_freq
    scaling_driver
    scaling_governor
    scaling_max_freq
    scaling_min_freq
    stats/
     

     

          这其中的所有可读文件都可以使用 cat 命令进行读操作,另外所有可写文件都可以使用 echo 命令进行写操作。其中 cpuinfo_max_freq 和 cpuinfo_min_freq 分别给出了 CPU 硬件所支持的最高运行频率及最低运行频率, cpuinfo_cur_freq 则会从 CPU 硬件寄存器中读取 CPU 当前所处的运行频率。虽然 CPU 硬件支持多种不同的运行频率,但是在有些场合下用户可以只选择使用其中的一个子集,这种控制是通过 scaling_max_freq 和 scaling_min_freq 进行的。Governor在选择合适的运行频率时只会在 scaling_max_freq 和 scaling_min_freq 所确定的频率范围内进行选择,这也就是 scaling_available_frequencies 所显示的内容与 cpuinfo_cur_freq 不同, scaling_cur_freq 返回的是 cpufreq 模块缓存的 CPU 当前运行频率,而不会对 CPU 硬件寄存器进行检查。 scaling_available_governors 会告诉用户当前有哪些 governors 可供用户使用,而 scaling_driver 则会显示该 CPU 所使用的变频驱动程序。 Stats 目录下给出了对 CPU 各种运行频率的使用统计情况,例如 CPU 在各种频率下的运行时间以及在各种频率之间的变频次数。 Ondemand 目录则与 ondemand governor 相关,在后文会进行相应的介绍。

         通过以上的介绍,大家对如何使用 cpufreq 通过 sysfs 提供的用户接口已经有了大致的了解,但是对于绝大部分用户而言,逐一操作这些文件既费力又耗时。因此 Dominik 等人开发了 cpufrequtils 工具包[2] ,为用户提供了更加简便的对内核 cpufreq 子系统的操作接口。通过 cpufreq-info 的输出,读者可以很清楚的看到刚刚在上面介绍过的 /sys/devices/system/cpu/cpuX/cpufreq/ 目录下各个文件的内容。

    $ cpufreq-info
    cpufrequtils 002: cpufreq-info (C) Dominik Brodowski 2004-2006
    Report errors and bugs to linux@brodo.de, please.
    analyzing CPU 0:
    driver: acpi-cpufreq
    CPUs which need to switch frequency at the same time: 0 1
    hardware limits: 1000 MHz - 1.67 GHz
    available frequency steps: 1.67 GHz, 1.33 GHz, 1000 MHz
    available cpufreq governors: userspace, conservative, ondemand, powersave, performance
    current policy: frequency should be within 1000 MHz and 1.67 GHz.
    The governor "ondemand" may decide which speed to use
    within this range.
    current CPU frequency is 1000 MHz.
    analyzing CPU 1:
    driver: acpi-cpufreq
    CPUs which need to switch frequency at the same time: 0 1
    hardware limits: 1000 MHz - 1.67 GHz
    available frequency steps: 1.67 GHz, 1.33 GHz, 1000 MHz
    available cpufreq governors: userspace, conservative, ondemand, powersave, performance
    current policy: frequency should be within 1000 MHz and 1.67 GHz.
    The governor "ondemand" may decide which speed to use
    within this range.
    current CPU frequency is 1000 MHz.
     
     

         Ondemand governor 的由来及其实现

         刚刚我们在 cpufreq-info 的输出中可以看到 cpufreq 子系统一共提供了五种 governors 供用户选择使用,它们分别是 userspace,conservative,ondemand,powersave 和 performance。在最新的内核中如果用户不进行额外设置的话,ondemand 会被作为默认的 governor 使用。为了理解是什么原因造成了这种现状,我们在这里带领读者回顾一下 cpufreq 子系统中的governor在内核中的开发历史。

        Cpufreq 作为一个子系统最早被加入到 Linux 内核中时只配备了三个 governors ,分别是performance、powersave 和 userspace。当用户选择使用 performance governor 时,CPU会固定工作在其支持的最高运行频率上;当用户选择使用 powersave governor 时,CPU会固定工作在其支持的最低运行频率上。因此这两种 governors 都属于静态 governor ,即在使用它们时 CPU 的运行频率不会根据系统运行时负载的变化动态作出调整。这两种 governors 对应的是两种极端的应用场景,使用 performance governor 体现的是对系统高性能的最大追求,而使用 powersave governor 则是对系统低功耗的最大追求。虽然这两种应用需求确实存在,但大多数用户在大部分时间里需要的是更加灵活的变频策略。最早的 cpufreq 子系统通过 userspace governor 为用户提供了这种灵活性。正如它的名字一样,使用 userspace governor 时,系统将变频策略的决策权交给了用户态应用程序,并提供了相应的接口供用户态应用程序调节 CPU 运行频率使用。通过使用 cpufrequtils 工具包中的 cpufreq-set 将 userspace 设置为 cpufreq 子系统所使用的 governor 后,我们可以看到与之前相比在 /sys/devices/system/cpu/cpuX/cpufreq/ 目录下多出了一个名为 scaling_setspeed 的文件,这正是 userspace governor 所提供的特殊用户接口。用户可以通过向该文件写入任何一个 scaling_available_frequencies 中所支持的运行频率,从而将 CPU 设置在该频率下运行。

    # cpufreq-set -g userspace
    # cat cpuinfo_cur_freq
    1000000
    # cat scaling_available_frequencies
    1667000 1333000 1000000
    # echo 1333000 >scaling_setspeed
    # cat cpuinfo_cur_freq
    1333000
     

     

          刚刚提到在使用 userspace governor 时,系统将变频策略的决策权交给了用户态应用程序。该用户态应用程序一般是一个 daemon 程序,每隔一定的时间间隔收集一次系统信息并根据系统的负载情况使用 userspace governor 提供的 scaling_setspeed 接口动态调整 CPU 的运行频率。作为这个 daemon 程序,当时在几个主要的 Linux 发行版中使用的一般是 powersaved 或者 cpuspeed。这两个 daemon 程序一般每隔几秒钟统计一次 CPU 在这个采样周期内的负载情况,并根据统计结果调整 CPU 的运行频率。这种 userspace governor 加用户态 daemon 程序的变频方法虽然为用户提供了一定的灵活性,但通过开源社区的广泛使用所得到的意见反馈逐渐暴露了这种方法的两个严重缺陷。第一个是性能方面的问题。例如 powersaved 每隔五秒钟进行一次系统负载情况的采样分析的话,我们可以分析一下在下面给出的应用场景中的用户体验。假设 powersaved 的采样分析刚刚结束,而且由于在刚刚结束的采样周期内系统负载很低,CPU 被设置在最低频率上运行。这时用户如果打开 Firefox® 等对 CPU 运算能力要求相当高的程序的话,powersaved 要在下一个采样点——大约五秒钟之后才有机会观察到这种提高 CPU 运行频率的需求。也就是说,在 Firefox 启动之初的五秒钟内 CPU 的计算能力并没有被充分发挥出来,这无疑会使用户体验大打折扣。第二个是系统负载情况的采样分析的准确性问题。将监控系统负载情况并对未来 CPU 的性能需求做出判断的任务交给一个用户态程序完成实际上并不合理,一方面是由于一个用户态程序很难完整的收集到所有需要的信息,因为这些信息大部分都保存在内核空间;另一方面一个用户态程序如果想要收集这些系统信息,必然需要进行用户态与内核态之间的数据交互,而频繁的用户态与内核态之间的数据交互又会给系统性能带来负面影响。

         那么这两个问题有没有解决的方法呢?应该讲社区中的开发人员就第二个问题比较容易达成一致,既然在用户态对系统的负载情况进行采集和分析存在这样那样的问题,那么更加合理的做法就是应该将这部分工作交由内核负责。但是第一个问题呢?第一个问题最直观的解决方案就是降低对系统负载进行采样分析的时间间隔,这样 powersaved 就能尽早的对系统负载的变化做出及时的响应。然而这种简单的降低采样分析的时间间隔的方案同样存在着两方面的问题,一方面这意味着更加频繁的用户态与内核态之间的数据交互,因此必然也就意味着对系统性能带来更大的负面影响;另一方面的主要原因在于当时各个 CPU 生产厂家的变频技术在硬件上仍不完善,具体体现就是在对 CPU 进行变频设置时所需的操作时间过长,例如 Intel 早期的 Speedstep 技术在对 CPU 进行变频设置时需要耗时 250 微秒,在此过程中 CPU 无法正常执行指令。读者如果简单的计算一下不难发现,即使对于一个主频为 1GHz 的 CPU 而言, 250 微秒也意味着 250,000 个时钟周期,在这期间 CPU 完全可以执行完上万条指令。因此从这个角度而言,简单的降低采样分析的时间间隔对系统性能带来的负面影响更加严重。幸运的是随着硬件技术的不断完善和改进,对 CPU 进行变频设置所需的操作时间已经显著降低,例如 Intel 最新的 Enhanced Speedstep 技术在对 CPU 进行变频设置时耗时已降至 10 微秒,下降了不止一个数量级。正是这种 CPU 硬件技术的发展为内核开发人员解决这些早期的遗留问题提供了契机,Venkatesh 等人提出并设计实现了一个新的名为 ondemand 的 governor ,它正是人们长期以来希望看到的一个完全在内核态下工作并且能够以更加细粒度的时间间隔对系统负载情况进行采样分析的 governor。在介绍 ondemand governor 的具体实现之前,我们先来看一下如何使用 ondemand governor 及其向用户提供了哪些操作接口。通过 cpufreq-set 将 ondemand 设置为当前所使用的 governor 之后,在 /sys/devices/system/cpu/cpuX/cpufreq 目录下会出现一个名为 ondemand 的子目录

    $ sudo cpufreq-set -g ondemand
    $ ls /sys/devices/system/cpu/cpu0/cpufreq/ondemand/
    ignore_nice_load
    powersave_bias
    sampling_rate
    sampling_rate_max
    sampling_rate_min
    up_threshold
    $ sudo cat sampling_rate_min sampling_rate sampling_rate_max
    40000
    80000
    40000000
    $ sudo cat up_threshold
     
    ******************************************************************************************
     
     管理策略: 
     

    Linux 内部共有五种对频率的管理策略 userspace , conservative , ondemand , powersave  和  performance

    Ø           1.performance  : CPU 会固定工作在其支持的最高运行频率上;

    Ø           2.powersave  : CPU 会固定工作在其支持的最低运行频率上。因此这两种  governors  都属于静态  governor  ,即在使用它们时  CPU  的运行频率不会根据系统运行时负载的变化动态作出调整。这两种  governors  对应的是两种极端的应用场景,使用  performance governor  体现的是对系统高性能的最大追求,而使用  powersave governor  则是对系统低功耗的最大追求。

    Ø         3.Userspace :最早的  cpufreq  子系统通过  userspace governor  为用户提供了这种灵活性。系统将变频策略的决策权交给了用户态应用程序,并提供了相应的接口供用户态应用程序调节CPU 运行频率使用。(可以使用 Dominik  等人开发了 cpufrequtils  工具包   )

    Ø         4.ondemand  : userspace 是内核态的检测,效率低。而 ondemand 正是人们长期以来希望看到的一个完全在内核态下工作并且能够以更加细粒度的时间间隔对系统负载情况进行采样分析的  governor 。

    Ø         5.conservative  :  ondemand governor  的最初实现是在可选的频率范围内调低至下一个可用频率。这种降频策略的主导思想是尽量减小对系统性能的负面影响,从而不会使得系统性能在短时间内迅速降低以影响用户体验。但是在  ondemand governor  的这种最初实现版本在社区发布后,大量用户的使用结果表明这种担心实际上是多余的,  ondemand governor 在降频时对于目标频率的选择完全可以更加激进。因此最新的  ondemand governor  在降频时会在所有可选频率中一次性选择出可以保证  CPU  工作在  80%  以上负荷的频率,当然如果没有任何一个可选频率满足要求的话则会选择 CPU  支持的最低运行频率。大量用户的测试结果表明这种新的算法可以在不影响系统性能的前提下做到更高效的节能。在算法改进后,  ondemand governor  的名字并没有改变,而  ondemand governor  最初的实现也保存了下来,并且由于其算法的保守性而得名  conservative  。

    Ondemand 降频更加激进,conservative 降频比较缓慢保守,事实使用 ondemand 的效果也是比较好的。

     

    n       Cpufreq 在用户态所呈现的接口:

    Ø         cpuinfo_max_freq   cpuinfo_min_freq :   分别给出了  CPU  硬件所支持的最高运行频率及最低运行频率,

    Ø         cpuinfo_cur_freq  则会从CPU 硬件寄存器中读取CPU 当前所处的运行频率。

    Ø         Governor 在选择合适的运行频率时只会在scaling_max_freq  和 scaling_min_freq  所确定的频率范围内进行选择

    Ø         scaling_cur_freq  返回的是cpufreq 模块缓存的CPU当前运行频率,而不会对CPU 硬件寄存器进行检查。

    Ø         scaling_available_governors  会告诉用户当前有哪些  governors  可供用户使用

    Ø         scaling_driver  则会显示该  CPU  所使用的变频驱动程序

    Ø         Scaling_governor  则会显示当前的管理策略,往这个上 echo 其他类型会有相应的转变。

    Ø         scaling_setspeed :需将 governor 类型切换为 userspace ,才会出现,往这个文件 echo 数值,会切换主频

     

    以下是将 governor 切换为 ondemand 后生成的 ondemand 文件夹下出现的配置文件。( conservative 就不说了,不准备使用)

    Ø         sampling_rate :当前使用的采样间隔   ,单位:微秒

    Ø         sampling_rate_min :允许使用的最短采样间隔

    Ø         sampling_rate_max :允许使用的最长采样间隔

    Ø         up_threshold  :表明了系统负载超过什么百分比时  ondemand governor  会自动提高  CPU  的运行频率

    Ø         ignore_nice_load : ignore_nice_load  文件可以设置为  0  或  1 ( 0  是默认设置)。当这个参数设置为1  时,任何具有  “nice” 值的处理器不计入总处理器利用率。在设置为  0  时,所有处理器都计入利用率。

    Ø         sampling_down_factor :

     

    n       使用方法:

    Ø         cd sys/devices/system/cpu/cpu0/cpufreq/ 目录

    echo 32000 > scaling_min_freq  设置最小工作频率 (khz,32000~88000)

    // 若想使用 userspace 策略

    # echo userspace > scaling_governor 切换工作方式为 userspace

    echo 64000 > scaling_setspeed   设置成想要的工作频率 ( khz )

    // 若想使用 ondemand 策略

    # echo ondemand > scaling_governor 切换工作方式为 ondemand

     

    3. 如何实现?

            首先需要干一些杂活,修改 kconfig makefile 把系统屏蔽的 cpufreq 打开,对于我们来说主要的核心有两部分:

    系统相关:主要有 cpu , timer (变了频率一定要更新系统 timer ,否则系统时间就不准了), sdram 等。

    主要就是实现下面这个结构体:

    static struct cpufreq_driver sep4020_driver =

    {

            .flags       = CPUFREQ_STICKY,

            .verify      = sep4020_verify_speed,

            .target      = sep4020_target,

            .get          = sep4020_getspeed,

            .init          = sep4020_cpu_init,

            .name      = "SEP4020 Freq",

    };

    代码还是很简陋,很多细节都没考虑,所以具体的暂时先不讲了,大家可以先参考 pxa 和 sa1100 的实现。

     

    然后就是收频率影响的驱动:

    简单的来说就是:系统在变化 cpu 主频的时候会调用 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 函数,响挂载在这个 cpu 上所有的驱动发出一个信号,驱动接收到这个信号则调用相应的处理函数。

    这里把串口部分的实现简化,如下:

    #ifdef CONFIG_CPU_FREQ

     

    static int sep4020_serial_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data)

    {

        //       printk("in the serial cpufreq_transition/n");

            int pmcr_pre;

            unsigned long cpu_clk,baud,baudh,baudl;

            pmcr_pre = *(volatile unsigned long*)PMU_PMCR_V;

                   if(pmcr_pre > 0x4000)

                   cpu_clk = (pmcr_pre-0x4000)*8000000;

            else

                   cpu_clk = (pmcr_pre)*4000000;

     

            baud = cpu_clk/16/115200;      

            baudh = baud >>8;

            baudl = baud&0xff;    

     

            *(volatile unsigned char*)UART0_LCR_V |= (0x80);

            *(volatile unsigned char*)UART0_DLBL_V    = baudl;

            *(volatile unsigned char*)UART0_DLBH_V    = baudh;

            *(volatile unsigned char*)UART0_LCR_V &= ~(0x80);

            printk("in the serial cpufreq_transition/n");

         return 0;

    }

     

    static inline int sep4020_serial_cpufreq_register(void)

    {

         sep4020_serial_freq_transition.notifier_call = sep4020_serial_cpufreq_transition;

     

         return cpufreq_register_notifier(&sep4020_serial_freq_transition,

                          CPUFREQ_TRANSITION_NOTIFIER);

    }

     

    static inline void sep4020_serial_cpufreq_deregister(void)

    {

         cpufreq_unregister_notifier(&sep4020_serial_freq_transition,

                         CPUFREQ_TRANSITION_NOTIFIER);

    }

     

    #else

    #endif

     

     30
     

     

        在这个子目录下名字以 sampling 打头的三个文件分别给出了 ondemand governor 允许使用的最短采样间隔,当前使用的采样间隔以及允许使用的最长采样间隔,三者均以微秒为单位。以笔者的电脑为例, ondemand governor 每隔 80 毫秒进行一次采样。另外比较重要的一个文件是 up_threshold ,它表明了系统负载超过什么百分比时 ondemand governor 会自动提高 CPU 的运行频率。以笔者的电脑为例,这个数值为 30% 。那么这个表明系统负载的百分比数值是如何得到的呢?在支持 Intel 最新的 Enhanced Speedstep 技术的 CPU 中,在处理器硬件中直接提供了两个 MSR 寄存器(Model Specific Register)供 ondemand governor 采样分析系统负载情况使用。这两个 MSR 寄存器的 名字分别为 IA32_MPERF 和 IA32_APERF[5] ,其中 IA32_MPERF MSR 中的 MPERF 代表 Maximum Performance , IA32_APERF MSR 中的 APERF 代表 Actual Performance 。就像这两个 MSR 的名字一样, IA32_MPERF MSR 寄存器是一个当 CPU 处在 ACPI C0 状态下时按照 CPU 硬件支持的最高运行频率每隔一个时钟周期加一的计数器; IA32_APERF MSR 寄存器是一个当 CPU 处在 ACPI C0 状态下时按照 CPU 硬件当前的实际运行频率每隔一个时钟周期加一的计数器。有了这两个寄存器的存在,再考虑上 CPU 处于 ACPI C0 和处于 ACPI C1、C2、C3 三种状态下的时间比例,也就是 CPU 处于工作状态和休眠状态的时间比例, ondemand governor 就可以准确的计算出 CPU 的负载情况了。

    得到了 CPU 的负载情况,接下来的问题就是如何选择 CPU 合适的运行频率了。刚刚在前面提到,当系统负载超过 up_threshold 所设定的百分比时, ondemand governor 将会自动提高 CPU 的运行频率,但是具体提高到哪个频率上运行呢?在 ondemand governor 监测到系统负载超过 up_threshold 所设定的百分比时,说明用户当前需要 CPU 提供更强大的处理能力,因此 ondemand governor 会将CPU设置在最高频率上运行,这一点社区中的开发人员和广大用户都没有任何异议。但是当 ondemand governor 监测到系统负载下降,可以降低 CPU 的运行频率时,到底应该降低到哪个频率呢? ondemand governor 的最初实现是在可选的频率范围内调低至下一个可用频率,例如笔者使用的 CPU 支持三个可选频率,分别为 1.67GHz、 1.33GHz 和 1GHz ,如果 CPU 运行在 1.67GHz 时 ondemand governor 发现可以降低运行频率,那么 1.33GHz 将被选作降频的目标频率。这种降频策略的主导思想是尽量减小对系统性能的负面影响,从而不会使得系统性能在短时间内迅速降低以影响用户体验。但是在 ondemand governor 的这种最初实现版本在社区发布后,大量用户的使用结果表明这种担心实际上是多余的, ondemand governor 在降频时对于目标频率的选择完全可以更加激进。因此最新的 ondemand governor 在降频时会在所有可选频率中一次性选择出可以保证 CPU 工作在 80% 以上负荷的频率,当然如果没有任何一个可选频率满足要求的话则会选择 CPU 支持的最低运行频率。大量用户的测试结果表明这种新的算法可以在不影响系统性能的前提下做到更高效的节能。在算法改进后, ondemand governor 的名字并没有改变,而 ondemand governor 最初的实现也保存了下来,并且由于其算法的保守性而得名 conservative 。

    展开全文
  • CPUFreq简介

    2021-07-10 00:41:20
    现在我们在购买一款手机的时候,大家都会去看一下这款手机所采用的芯片型号,有几个CPU核心(是8核处理器还是4核处理器),CPU的主频最高是多少。这些都是一些关系到性能体验的初步的硬件基础参...

    现在我们在购买一款手机的时候,大家都会去看一下这款手机所采用的芯片型号,有几个CPU核心(是8核处理器还是4核处理器),CPU的主频最高是多少。这些都是一些关系到性能体验的初步的硬件基础参数。

    在整个手机处理器的发展历程过程中,经历了从最初的单核心处理,到多核心处理以及现在大小核架构的历程。CPU的主频也从最初的几十MHz,到几百MHz,直到现在的几个GH

    图一:手机发展史也是一部处理器发展史

    今天就给大家介绍一下CPU处理器的频率。首先介绍一下整个CPU系统的拓扑结构。处理器发展到今天,在手机这种对于性能与功耗要求极高,同时电池容量又受到限制的产品类型上,一般都是采用了B-L(Big-Little)架构,即大小核架构。小核也被称为功耗核心(Power Core),其性能稍弱,但是耗电比较低,通常被用来处理诸如电子书、浏览器此类对性能要求较低的轻负载场景;大核也被称为性能核心(Performance Core),其性能较强,但是耗电也高,被用来处理MOBA(Multiplayer Online Battle Arena,多人在线战术竞技游戏)游戏、相机等对于性能要求较高的高负载场景。

    图二:CPU拓扑结构示例

    以上图的这款8核心(4个功耗核心+4个性能核心)的CPU处理器为例,8个CPU核心被分为了2个簇(cluster),其中4个功耗核心在同一个簇上,另外4个性能核心在同一个簇上。基于成本考虑,一般同一个簇上的CPU都由同一个时钟源(clock)提供时钟输入,并由同一路regulator电源进行供电。

    图三:同一个簇由同一个时钟源输入,同一个电源供电

    那么为什么CPU需要调频?

    摘抄一段关于DCVS的描述“dynamic clock and voltage scaling (DCVS) is a technique used to adjust the frequency and voltage of the power equation to deliver the needed performance at the ideal power level.“, 很显然,调频是为了平衡性能与功耗。如果CPU始终运行在高频率上,那么就造成功耗的浪费,特别是对于手持类终端设备,其电池容量本身受到了限制。

    上面讲到了一些CPU相关的硬件基础知识。硬件是软件实现的基础,软件为硬件服务。下面我们回到软件层面。

    图四:CPUFREQ软件框架图

    CPUfreq框架大体可以分为下面几个模块:

    1) 驱动层:提供不同类型CPU的调节频率的驱动能力

    2) Governor:提供动态调频的算法

    3) 核心层:计算机领域的任何问题都可以通过增加一个间接的中间层来解决,CPUfreq核心层其实就是一个中间层,向下提供不同类型CPU驱动的框架接口(注册cpufreq_driver驱动),向上提供不同调频governor的算法接口(注册cpufreq_governor)。同时统一提供对外的API跟sysfs调试接口。我们在进行一些性能功耗的基础调试的时候,会用到了一些sysfs debug的的接口,比如

    通过主动提升频率来初步的进行问题的界定与排查。

    一、框架层

    从图四的CPUFREQ软件框架图可以看出,框架层是一个虚拟中间层(cpufreq.c cpufreq_stats.c  cpufreq_times.c  freq_table.c提供基本函数,统计cpufreq相关信息),提供了承上启下的能力。另外提供了对外的API及能力。

    在/sys/devices/system/cpu目录下可以看到框架层所提供的CPU频率的相关信息。

    上面是关于CPUfreq框架层对外暴露的一个接口及参数信息。内核中采用struct cpufreq_policy来表示某一种CPU的频率策略。由于存在多个CPU由同一个时钟源提供输入的情况。一般struct cpufreq_policy被用来代表一个同一个cluster的时钟策略。struct cpufreq_policy中各个字段变量的描述如下

    我们从一个简单的命令开始,来整体看一下CPUFREQ框架。

    通过代码我们可以看到最终调用了cpufreq_set_policy函数进行参数的调节,最新的kernel 5.4的代码改成了cpufreq QoS,具体可以看本公众号之前的文章《Linux PM QOS介绍》,在此不再赘述。

    除此之外框架层还提供了一些对于cpu时间及频率的相关统计,我们可以看到CPU在某一段时间内在每一个频率点上的驻留时间,用于具体问题的分析。



    二、驱动层

    核心提供API cpufreq_register_driver来用于注册具体的cpufreq的驱动。以高通平台为例,其在qcom-cpufreq-hw.c中的probe函数进行了驱动的注册。

    我们回过头来看一下驱动程序到底提供了哪些能力与信息。

    其他的在struct cpufreq_driver中不常用的一些接口函数就不详细介绍了。

    驱动层除了提供这些能力之外,也提供了一些CPU相关的基础信息。比如芯片所支持的最高频率,最低频率及所有支持的频率点,这些信息来源于驱动层提供。



    三、CPU调频器

    讲完框架层(提供框架支持以及调频策略)及驱动层(提供驱动能力支持),终于来到了本讲内容的重点:CPU调频器。Governor其实我们平时所说的DCVS,当然DVFS包含了硬件的调频能力与软件的算法。本讲集中在软件算法部分。核心层提供了API cpufreq_register_governor来进行注册。通过查看scaling_available_governor可以看到所有已经注册的调频器,通过设置scaling_governor可以进行各种governor之间的切换。

    图五:DCVS与governor

    框架层通过cpufreq_policy设置了上层约束,governor在这个约束的范围内通过采集CPU的使用情况来决定是否需要调频,调到多少的频率合适。

    图六:governor的输入与输出

    图七:CPU使用率

    下面介绍几种常用的governor:



    四、interactive

    基于linux模块化的设计,早期的governor基本都是对CPU的使用率进行定时采样检查,然后根据使用率的情况调整CPU频率。Interactive governor作为早期android的调频器,也属于此类。它除了周期性采样CPU的使用率之外,还加入了一些优化项,来满足交互式终端的性能体验需求。

    图八:interactive governor工作原理(tips:不要把任务都放在同一个进程里面,尽量分散到多个线程上)

    Interactive governor针对android这类交互终端做了一些改进如下:

    1) 引入hi_speed的概念,当CPU使用率超过一定阈值(go_hispeed_load)的时候,会直接跳到预先设定的hi_speed的CPU频率,来满足交互的性能。避免governor周期采样调频的时间延迟。

    2) 引入target_loads的概念,一般governor都默认采用80%作为调频的阈值,即CPU使用率超过80%,向上提高频率;低于80%,向下降低频率。但是具体的CPU的个体上存在差异,比如高频率部分的能效比较差,低频段的能效比较好。可以通过target_loads来设定不同频率区间的调频阈值。

    3) 引入above_hispeed_delay,在hispeed freq以上的部分,CPU频率需要在当前频率上驻留一定的时间才可以继续向上调频,用于功耗优化。

    4) boost/boostpulse_duration: boost模式,上层应用程序按需触发boost模式。

    5) 关于输入参数cpu 使用率,最初的interactive governor参数为CPU运行时间跟处于IDLE的时间。也就是说usage使用率处于0%~100%之间。设想一个大任务或类while(1)循环的场景,其负载始终处于100%。以target load处于80%为例,每次只能向上增加25%的频率。以这样的速度调频的话,什么时候才能调到最高频率呢?所以后来将interactive的CPU使用率参数从cputime切换成scheduler调度器统计的CPU使用负载(高通在walt的时候引入)。

    五、schedutil

    上面讲interactive的部分分析了其优缺点,虽然可以采用scheduler统计的负载来代替cputime的使用率,但是interactive仍然存在一个问题,即采样周期。由于interactive是周期性采样调频的,其结果必然受到了采样周期的影响。采样周期短的话,其响应更加及时,但是系统开销大;采样周期长的话,响应比较缓慢,但是系统开销比较小。随着屏幕的刷新率从60HZ提到了90HZ, 120HZ。每一帧绘制的时间越来越短,对于CPU频率的响应延迟要求越来越高。

    基于上述的一些原因,引入了schedutil调频器。虽然其名字叫schedutil,即来自于scheduler的utilization,但是这一点在schedutil出现之前高通已经在interactive上引入了。个人认为schedutil最大的改动在于将周期性的采样触发改成了基于事件驱动触发(反模块化)。这些事件来自于scheduler。其工作原理大体如下:

    1) 当一个任务被唤醒时,任务被放入到了某个CPU的队列中。此时意味着当前CPU的任务负载变重,需要及时的提高频率来保证性能。于是主动触发了调频。

    2) 当一个任务完成工作,进入休眠状态,从任务队列中被移除。此时意味着当前CPU的任务负载变轻,需要及时的降低频率来降低功耗。于是主动触发了调频。

    上面是2个典型的场景,诸如此类。当CPU上任务负载发生变化的时候,即由scheduler触发频率的调整。

    cpufreq_schedutil.c中注册了hook函数

    scheduler在某些事件发生的时候主动调用cpufreq_update_util来进行频率的调整。其实已经在调度器跟调频器之间搭了座桥梁。

     

    六、小结

    本文主要介绍了CPU频率相关的硬件基础、拓扑结构,介绍了CPUFRE的整体软件框架,调频器的工作原理,android上的调频器的发展历史。

    本文是基于OPPO的开源的kernel-4.19的代码进行分析的。https://github.com/oppo-source/kernel_msm-4.19。

    参考资料:

    [1] CPU调频文档,linux kernel

    [2] cpufreq schedutil原理剖析,内核工匠

    [3] cpufreq: interactive: New 'interactive' governor, LWN

    [4] EAS, ARM & linaro

    [5] Power vs. Performance Management of the CPU,  Qualcomm blog

    长按关注

    内核工匠微信

    Linux 内核黑科技 | 技术文章 | 精选教程

    展开全文
  • openwrt-cpufreq-源码

    2021-04-11 19:24:52
    luci-app-cpufreq Openwrt LuCI应用程序管理ARM处理器的内核参数。 OpenWrt> = 19.07。 屏幕截图
  • ubuntu控制cpu的频率(cpufreq,cpufrequtils,indicator-cpufreq)ubuntu控制cpu的频率查看当前cpu的频率方法一方法二更改当前CPU频率控制策略更改当前CPU频率通过图形化界面来调整CPU频率 ubuntu控制cpu的频率 ...
  • cpufreq学习笔记

    2020-12-02 10:22:33
    cpufreq学习笔记
  • cpufreq 代码分析

    2020-03-27 10:05:11
    cpufreq 代码分析 基础知识: 1.cpufreq 的五种模式 2.cpufreq 的框架 cpufreq 代码分析 从 drivers\cpufreq\Makefile 开始,(注:我的是linux-4.14.63) # SPDX-License-Identifier: GPL-2.0 # CPUfreq core obj-...
  • 3.管理策略:Linux内部共有五种对频率的管理策略userspace,conservative,ondemand,powersave和performanceperformance:CPU会固定工作在其支持的最高运行频率上;powersave:CPU会固定工作在其支持的最低运行频率...
  • Linux系统的Cpufreq

    2021-05-10 23:14:10
    从 2.6.0 Linux 内核开始,您可以通过 CPUfreq子系统动态调整处理器频率。当处理器以较低的时钟速度运行时,它们消耗的电能和产生的热量也相对较少。时钟速度的这种缩放可以控制系统在未全力运行时消耗较少电能。CPU...
  • 背景Read the fucking source code! --By 鲁迅A picture is worth a thousand words. --By 高尔基说明:... 介绍cpufreq子系统负责在运行时对CPU频率和电压的动态调整,以达到性能和功耗的平衡,它也叫DVFS(Dynam...
  • Cpufreq_for_intel

    2016-10-26 22:34:50
    cpufreq动态频率调节(Sofia3GR)浅析及应用层APK实现http://blog.csdn.net/qf0727/article/details/52935501 这篇文章配套的apk demo
  • cpufreq schedutil原理剖析

    千次阅读 2021-02-10 17:00:00
    本文会基于Android Pixel4(android linux kernel 4.14+ARMv8(AArch64)),重点分析schedutil这个cpufreq的governor,...
  • 随着技术的发展,我们对CPU的处理能力提出了越来越高的需求,芯片厂家也对制造工艺不断地提升。现在的主流PC处理器的主频已经在3GHz左右,就算是智能手机的处理器也已经可以工作在1.5GHz以上,可是我们并不是...
  • [cpufreq governor]sched governor解析

    千次阅读 2018-08-22 19:31:50
    前有schedutil governor来调节cpu频率,现有schedfreq governor来调节cpu频率,现在来讲解它的来龙去脉。 源代码参考AOSP kernel的这个分支:remotes/origin/android-msm-wahoo-4.4-pie,kernel version:4.4.116...
  • auto-cpufreq-1.2.zip

    2020-08-14 22:04:45
    在linux下自动调节cpu,实现监控,cpu资源自动调度。可用于UOS操作系统,目前在X86下已经完成测试。欢迎大家自行测试。
  • 1. 前言 本文从平台驱动工程师的角度,介绍怎么编写cpufreq...cpufreq driver主要完成平台相关的CPU频率/电压的控制,它在cpufreq framework中是非常简单的一个模块,编写步骤包括: 1)平台相关的初始化动作
  • 记录: 1. cpufreq 使用 2. 加大负载方式 3. 查看负载方式 4. cpufreq 几种governor
  • 具有CPU频率和CPU温度的htop htop修改了Ubuntu deb软件包以显示CPU频率和CPU温度。 Ubuntu 16.04 Ubuntu 18.04 臂64 Ubuntu 18.04 安装htop : sudo dpkg -i ./htop_2.1.0-3_arm64.deb [ ] [ ] [ ] 高负载...
  • linux cpufreq调频

    2021-05-13 12:13:26
    cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor #查询当前系统支持的调频策略方式 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors #根据运行负载需求调频 echo ondemand > ...
  • cpufreq 五种模式

    千次阅读 2020-03-23 11:54:57
    cpufreq 是一个动态调整cpu频率的模块,系统启动时生成一个文件夹/sys/devices/system/cpu/cpu0/cpufreq/,里面有几个文件, 其中: scaling_min_freq 代表最低频率, scaling_max_freq 代表最高频率, scalin_...
  • Linux电源管理(四)CPUFreq

    千次阅读 2017-10-03 18:46:13
    CPUFreq简介CPUFreq是一种实时的电压和频率调节技术,也叫DVFS(Dynamic Voltage and Frequency Scaling)动态电压频率调节。为何需要CPUFreq随着技术的发展,CPU的频率越来越高,性能越来越好,芯片制造工艺也...
  • 了解loongson cpufreq 1.clock 初始化 170 static int loongson3_clock_init(void) 171 { 172 int i; 173 174 for_each_possible_cpu(i) { 175 sprintf(clk_names[i], "cpu%d_clk", i); 176 cpu_clks[i]....
  • Linux cpufreq framework(2)

    2021-05-16 00:52:33
    Linux cpufreq framework(2)_cpufreq driver作者:wowo 发布于:2015-6-19 22:27分类:电源管理子系统1. 前言本文从平台驱动工程师的角度,介绍怎么编写cpufreq驱动。注1:本文基于2. cpufreq driver的编写步骤cpu...
  • 问题: 使用VMware安装Ubuntu18.04.4时出现错误:cpufreq: cpufreq_online: Failed to initialize policy for cpu: 0 (-19) 原因:版本问题 VMware12.5.7不支持安装Ubuntu18.04.4, 解决:
  • Linux cpufreq 简介

    千次阅读 2019-01-23 16:05:15
    CPU变频即改变CPU运行时的频率,CPU在不同的频率下运行时所需的电压不同,频率越高,所需的电压也随之升高,因此在移动设备领域,为了节省功耗,在系统suspend或者load较小时,让CPU运行在较低的频点,可以减少CPU的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,403
精华内容 6,961
关键字:

cpufreq

友情链接: lwip-1.1.0.zip