精华内容
下载资源
问答
  • DVFS

    千次阅读 2013-06-18 15:06:19
    英文全称为:Dynamic voltage and frequency scaling,简写是DVFS;中文一般译作动态电压频率调整 DVFS 即动态电压频率调整,动态技术则是根据芯片所运行的应用程序对计算能力的不同需要,动态调节芯片的运行...

    英文全称为:Dynamic voltage and frequency scaling,简写是DVFS;中文一般译作动态电压频率调整

    DVFS 即动态电压频率调整,动态技术则是根据芯片所运行的应用程序对计算能力的不同需要,动态调节芯片的运行频率和电压(对于同一芯片,频率越高,需要的电压也越高),从而达到节能的目的。降低频率可以降低功率,但是单纯地降低频率并不能节省能量。因为对于一个给定的任务,F*t是一个常量,只有在降低频率的同时降低电压,才能真正地降低能量的消耗。 目前许多芯片支持DVFS,比如InteI公司的芯片支持SpeedStep,ARM的支持IEM(Intelligent Energy Man-ager)和AVS(Adaptive Voltage Scaling)等。但是要让DVFS发挥作用,真正地实现节能,只有芯片的支持还是不够的,还需要软件与硬件的综合设计。目前S3C6410开发板中,重庆海特克的开发板有DVFS设计,说明了他们对算法预测这方面有很大的突破。S3C6410芯片本身针对的是手持设备,如果有DVFS这项技术的辅助,功耗这方面将会降的更低,对手持设备研发帮助将会更大。 DVFS系统流程: 1. 采集与系统负载有关的信号,计算当前的系统负载。 2. 根据系统的当前负载,预测系统在下一时间段需要的性能。 3. 将预测的性能转换成需要的频率,从而调整芯片的时钟设置。 4. 根据新的频率计算相应的电压。通知电源管理模块调整给CPU的电压。另外,在调整频率和电压时,要特别注意调整的顺序。当频率由高到低调整时,应该先降频率,再降电压;相反,当升高频率时,应该先升电压,再升频率。虽然现在做DVFS的不是很多,是因为很多都被预测算法给难住,但是作者相信,随着预测算法的进步,DVFS技术必将得到广泛的应用,因为它能够节省很多能量。而节能对许多便携式设备来说,常常是第一要求。
    展开全文
  • CloudSim_DVFS-源码

    2021-07-06 23:23:22
    CloudSim_DVFS 目标: 开发 RAM DVFS 控制 开发新的调度器
  • ForREST - 多核处理器的React式 DVFS 控制 FoREST 是一个新的 DVFS 守护进程,它控制基于 CPU 频率的周期性 CPU 强度分析。 硬件支持 Intel x86:SandyBridge、IvyBridge 英特尔至强融核 (2013) 预编译 此命令是...
  • CloudSim_DVFS CloudSim 的 DVFS 实现实验 代码提供者:。 该模拟器由 Tom Guerout 等人创建:Tom Guerout、Thierry Monteil、Georges Da Costa、Rodrigo N. Calheiros、Rajkumar Buyya、Mihai Alexandru。 使用 ...
  • DVFS简介

    千次阅读 2014-11-04 14:36:17
    英文全称为:Dynamic voltage and frequency scaling,简写是DVFS;中文一般译作动态电压频率调整。 DVFS 即动态电压频率调整,动态技术则是根据芯片所运行的应用程序对计算能力的不同需要,动态调节芯片的运行...

    英文全称为:Dynamic voltage and frequency scaling,简写是DVFS;中文一般译作动态电压频率调整。

    DVFS 即动态电压频率调整,动态技术则是根据芯片所运行的应用程序对计算能力的不同需要,动态调节芯片的运行频率和电压(对于同一芯片,频率越高,需要的电压也越高),从而达到节能的目的。
    降低频率可以降低功率,但是单纯地降低频率并不能节省能量。因为对于一个给定的任务,F*t是一个常量,只有在降低频率的同时降低电压,才能真正地降低能量的消耗。 
    目前许多芯片支持DVFS,比如InteI公司的芯片支持SpeedStep,ARM的支持IEM(Intelligent Energy Man-ager)和AVS(Adaptive Voltage Scaling)等。但是要让DVFS发挥作用,真正地实现节能,只有芯片的支持还是不够的,还需要软件与硬件的综合设计。
    DVFS系统流程: 
    1. 采集与系统负载有关的信号,计算当前的系统负载。 
    2. 根据系统的当前负载,预测系统在下一时间段需要的性能。 
    3. 将预测的性能转换成需要的频率,从而调整芯片的时钟设置。 
    4. 根据新的频率计算相应的电压。通知电源管理模块调整给CPU的电压。
    另外,在调整频率和电压时,要特别注意调整的顺序。当频率由高到低调整时,应该先降频率,再降电压;相反,当升高频率时,应该先升电压,再升频率。

    转自:http://blog.csdn.net/cqhtk/article/details/4969345
    展开全文
  • GPU-DVFS-作业计划-源码

    2021-02-08 08:24:20
    GPU_DVFS_Job_Schedule
  • DVFS解析

    千次阅读 2014-11-04 14:24:03
    DVFS(Dynamic Voltage and Frequency Scaling)动态电压频率调节,是一种实时的电压和频率调节技术。在 CMOS 电路中功率消耗主要可以分为动态功率消耗和静态功率消耗,公式如下:   其中 C 代表负载电容...

    一、基本概念

    DVFS(Dynamic Voltage and Frequency Scaling)动态电压频率调节,是一种实时的电压和频率调节技术。在 CMOS 电路中功率消耗主要可以分为动态功率消耗静态功率消耗,公式如下:

        

    其中 C 代表负载电容的容值,V 是工作电压α 是当前频率下的翻转率f工作频率I_dq 代表静态电流。公式的前部分代表的是动态功率消耗,后部分则代表的是静态功率消耗。从公式中可以看出,想要降低动态功率消耗可以从C、V、α、f着手,对于软件来讲常用的调节方式只涉及到V、f 两个因素。


    二、代码解析

    1、数据结构

    系统中存在 7 大总线:ARM_CLK、AXI_CLK、DSP_CLK、APP_CLK、MPH_CLK、GE_CLK、VS_CLK,DVFS 系统的所有工作都围绕这几大总线以及核心电压CORE_VOLTAGE展开,代码里面用到的数据结构有:DVFS_REQ、DVFS_CMD、DVFS_NODE、DVFS_CDB,定义如下:

    1. typedef struct {  
    2.     const char*   module;   /* 发出调节请求的模块名称 */  
    3.     unsigned char flag;     /* 调节频率的标记: 有最低、最高、锁定三种 */  
    4.     DVFS_CLK_e    clk;      /* 申请调节的时钟总线,有7大总线 */  
    5.     int           freq;     /* 期望频率值 */  
    6. } DVFS_REQ;  
    7.   
    8. typedef struct {  
    9.     DVFS_CBF    cb;     /* 回调函数 */  
    10.     int         arg;    /* 参数 */  
    11.     int         num;    /* 本次请求的数目 */  
    12.     DVFS_REQ    reqs[MAX_REQ_NUM];   /* 请求存放的数组,最多8个请求 */  
    13. } DVFS_CMD;  
    14.   
    15. typedef struct {  
    16.     struct list_head head;  /* 链表节点 */  
    17.     DVFS_REQ         req;   /* 当前请求 */  
    18. } DVFS_NODE;  
    19.   
    20. typedef struct {  
    21.     // cmd queue managment  
    22.     DVFS_CMD    q_array[CMD_Q_LENGTH];  
    23.     uint8_t     q_idx_r;  
    24.     uint8_t     q_idx_w;  
    25.     uint8_t     q_idx_p;  
    26.     spinlock_t  q_lock;  
    27.   
    28.     // worker thread management  
    29.     wait_queue_head_t q_wait;  /* 等待队列 */  
    30.     struct task_struct* task;  /* 任务 */  
    31.   
    32.     // list of request for each clock  
    33.     DVFS_NODE*  req_lists[DVFS_CLK_ALL];       /* 指向每条总线的请求链表 */  
    34.   
    35.     // clock/voltage setttings  
    36.     int         curr_freq_idx[DVFS_CLK_ALL];   /* 当前频率的索引值 */  
    37.     int         trgt_freq_idx[DVFS_CLK_ALL];   /* 目标频率的索引值 */  
    38.     struct clk* hw_clock[DVFS_CLK_ALL];        /* 时钟设置 */  
    39.     uint8_t curr_vol_idx;        /* 当前电压索引值 */  
    40.     uint8_t trgt_vol_idx;        /* 目标电压索引值 */  
    41.     unsigned long vol_jiffies;   /* 电压调节时间记录,用于记录调节间隔 */  
    42. } DVFS_CDB;  
    其中 DVFS_REQ 用于描述一个调节请求,存放了相关信息;DVFS_CMD 用于多个请求构造的一次调节操作;DVFS_NODE 作为链表节点,每一条总线的调节请求都由各自的链表维护;DVFS_CDB则存放了 DVFS 系统的大部分信息,系统中只存在一个全局的 DVFS_CDB 变量。

    2、函数接口

    当要调用 DVFS 系统时,通常的调用方法如下:

    1. DVFS_CREATE_REQ(reqs[0], "camera", AXI_CLK, axi_freq, DVFS_REQ_MIN);  /* 创建一个调节请求 */  
    2. init_completion(&cam_complete);  
    3. dvfs_send_reqs(reqs, 1, suspend_cb, 0);     /* 发送调节请求 */  
    4. wait_for_completion(&cam_complete);         /* 等待调节完成 */  
    通过 DVFS_CREATE_REQ 宏定义创建一个调节请求,宏定义原型如下:

    1. #define DVFS_CREATE_REQ(req, MODULE, CLK, FREQ, FLAG) { \  
    2.     req.module = MODULE;\  
    3.     req.clk = CLK;\  
    4.     req.flag = FLAG;\  
    5.     req.freq = FREQ;\  
    6.     }  
    宏主要用于构造一个 DVFS_REQ 结构,然后通过 dvfs_send_reqs 构造 DVFS_CMD 完成调节并执行回调函数 suspend_cb。

    3、代码解析

    在 DVFS 系统的初始化过程中,做的工作有如下几个:a、初始化 cdb->hw_clock;b、创建每条总线的链表;c、创建 proc 文件节点;d、创建等待队列以及内核线程专门用于 DVFS。当初始化完成之后就启动内核线程 dvfs_thread_func,在这里面会等待 dvfs_send_reqs 发出唤醒事件,然后进行电压和频率的调节并执行回调函数。下面我们从发送调节请求开始解析,函数 dvfs_send_reqs实现如下:

    1. int dvfs_send_reqs(DVFS_REQ *reqs, int num, DVFS_CBF cb, int arg)  
    2. {  
    3.     int      ret;  
    4.     DVFS_CMD *cmd;  
    5.     unsigned long irq_flags;  
    6.   
    7.     if ((ret = sanity_check(reqs, num))) {  /* 检查参数有效性 */  
    8.         return ret;  
    9.     }  
    10.   
    11.     if (num == 1 && reqs[0].clk == APP_CLK) {  /* APP_CLK 可以快速处理 */  
    12.         mutex_lock(&app_lock); /* 互斥体 */  
    13.         ret = dvfs_process_req(&dvfs_cdb, reqs);  /* 处理调节请求,如果需要调节返回非 0 值 */  
    14.         if (ret) {  
    15.             dvfs_cdb.curr_freq_idx[APP_CLK] = dvfs_cdb.trgt_freq_idx[APP_CLK];  
    16.             clk_set_rate(dvfs_cdb.hw_clock[APP_CLK], dvfs_get_rate(APP_CLK, dvfs_cdb.curr_freq_idx[APP_CLK]));  
    17.         }  
    18.         mutex_unlock(&app_lock);  
    19.         return 0;  
    20.     }  
    21.   
    22.     spin_lock_irqsave(&dvfs_cdb.q_lock, irq_flags);  /* 数据更新 */  
    23.     cmd = &dvfs_cdb.q_array[dvfs_cdb.q_idx_w & CMD_Q_MASK]; /* 构造 cmd */  
    24.     cmd->cb     = cb;  
    25.     cmd->num    = num;  
    26.     cmd->arg    = arg;  
    27.     memcpy(cmd->reqs, reqs, num * sizeof(DVFS_REQ));   
    28.     smp_mb();  
    29.     dvfs_cdb.q_idx_w++;  
    30.     spin_unlock_irqrestore(&dvfs_cdb.q_lock, irq_flags);  
    31.   
    32.     wake_up_all(&dvfs_cdb.q_wait);  /* 唤醒等待队列 */  
    33.     return 0;  
    34. }  
    35. EXPORT_SYMBOL(dvfs_send_reqs);  
    函数首先进行参数有效性验证,然后判断是否只调节 APP_CLK,因为 APP_CLK 用于外设不影响系统运行,所以可以直接调节。如果不只调节 APP_CLK 接下来将会构造 DVFS_CMD,然后唤醒内核线程 dvfs_thread_func,实现如下:

    1. int dvfs_thread_func(void *data)  
    2. {  
    3.     DVFS_CDB *cdb = (DVFS_CDB*)data;  
    4.     DVFS_CMD *cmd;  
    5.   
    6.     do {  
    7.         /* 等待唤醒 */  
    8.         if(wait_event_interruptible(cdb->q_wait, (cdb->q_idx_w != cdb->q_idx_r)) != 0)  
    9.             continue;  
    10.   
    11.         /* 判断是否需要调节电压和频率 */  
    12.         if (cal_target_freq(cdb)) {  
    13.             dvfs_reset_clk(cdb);  /* 开始调节 */  
    14.         }  
    15.           
    16.         /* 触发回调函数 */  
    17.         if (cmd->cb != NULL) {  
    18.             cmd->cb(cmd->arg);  
    19.         }  
    20.     } while (1);  
    21. }  
    当线程被唤醒后会根据函数 cal_target_freq 判断当前是否需要进行电压和频率的调节,cal_target_freq 里面首先根据传递的 CMD 更新链表,然后根据链表记录去判断是否需要调节频率,如果需要调节就会根据目标频率值通过查表(电压 - 频率表)查找系统支持的最合适的频率值。接着就来到了 DVFS 系统最重要的函数 dvfs_reset_clk,电压和频率调节都将在这个函数里面完成:

    1. void dvfs_reset_clk(DVFS_CDB *cdb)  
    2. {  
    3.     int idx;  
    4.     int vol;  
    5.   
    6. reqs_updated:  
    7.     cal_target_vol_idx(cdb);  /* 首先计算电压是否需要调节 */  
    8.   
    9.     /* 需要升高电压 */  
    10.     if (cdb->trgt_vol_idx > cdb->curr_vol_idx && arm_regulator) {  
    11.         for (idx = cdb->curr_vol_idx + 1; idx <= cdb->trgt_vol_idx; ++idx) {  
    12.             unsigned int interval_ms = jiffies_to_msecs(jiffies - cdb->vol_jiffies);  
    13.             if (interval_ms < 100) { /* 距离上次调节小于 100ms 则需等待 */  
    14.                 msleep(100 - interval_ms);  
    15.                 if (cal_target_freq(cdb))  
    16.                     goto reqs_updated;  
    17.             }  
    18.   
    19.             if (idx + 1 <= cdb->trgt_vol_idx)   
    20.                 ++idx;  
    21.             vol = voltage_table[idx].voltage;  
    22.             regulator_set_voltage(arm_regulator, vol, vol);  
    23.             cdb->curr_vol_idx = idx;  
    24.             cdb->vol_jiffies = jiffies;  
    25.             dvfs_dbg("DVFS increase arm voltage to %d uV\n", vol);  
    26.         }  
    27.     }  
    28.   
    29.     do_reset_clk(cdb);  /* 调节频率 */  
    30.     if (cal_target_freq(cdb))  /* 查看当前是否有新的调节请求 */  
    31.         goto reqs_updated;  
    32.   
    33.     /* 需要降低电压 */  
    34.     if (cdb->trgt_vol_idx < cdb->curr_vol_idx && arm_regulator) {  
    35.         for (idx = cdb->curr_vol_idx - 1; idx >= cdb->trgt_vol_idx; --idx) {  
    36.             unsigned int interval_ms = jiffies_to_msecs(jiffies - cdb->vol_jiffies);  
    37.             if (interval_ms < 100) {  
    38.                 msleep(100 - interval_ms);  
    39.                 if (cal_target_freq(cdb))  
    40.                     goto reqs_updated;  
    41.             }  
    42.   
    43.             vol = voltage_table[idx].voltage;  
    44.             regulator_set_voltage(arm_regulator, vol, vol);  
    45.             cdb->curr_vol_idx = idx;  
    46.             cdb->vol_jiffies = jiffies;  
    47.             dvfs_dbg("DVFS decrease arm voltage to %d uV\n", vol);  
    48.         }  
    49.     }  
    50. }  

    函数里面先进行电压调节满足“升频率时先升电压,降频率时后降电压”的准则并且两次电压的调节需要间隔 100ms以上,然后通过 do_reset_clk 进行频率调节,实现如下:

    1. static void do_reset_clk(DVFS_CDB *cdb)  
    2. {  
    3.     int clk, idx;  
    4.   
    5.     for (clk = 0; clk < DVFS_CLK_ALL; clk++) { /* 依次调节频率 */  
    6.         int curr = cdb->curr_freq_idx[clk];  
    7.         int trgt = cdb->trgt_freq_idx[clk];  
    8.   
    9.         if (ARM_CLK == clk && curr != trgt) {  /* 调整 arm 频率,需要经过 cpufreq 子系统 */  
    10.             unsigned int i;  
    11.             struct cpufreq_freqs freqs = {  
    12.                 .flags = 0,  
    13.                 .old = frequency_table[clk][curr].freq / 1000,  
    14.                 .new = frequency_table[clk][trgt].freq / 1000,  
    15.             };  
    16.             for_each_online_cpu(i) {  
    17.                 freqs.cpu = i;  
    18.                 /* 函数向挂载在这个 cpu 上所有的驱动发出一个信号,驱动接收到这个信号则调用相应的处理函数 */  
    19.                 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);  
    20.             }  
    21.         }  
    22.   
    23.         if (curr < trgt) {  /* 如果当前频率比目标频率低 */  
    24.             for (idx = curr+1; idx <= trgt; idx++) {  /* 逐级调节频率可以保证系统的稳定性 */  
    25.                 if (idx == trgt) {  
    26.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    27.                 } else if (frequency_table[clk][idx].need_delay) {  
    28.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    29.                     msleep(1);  
    30.                 }  
    31.             }  
    32.         } else if (curr > trgt) { /* 如果当前比目标频率高 */  
    33.             for (idx = curr-1; idx >= trgt; idx--) {  /* 逐级调节频率可以保证系统的稳定性 */  
    34.                 if (idx == trgt) {  
    35.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    36.                 } else if (frequency_table[clk][idx].need_delay) {  
    37.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    38.                     msleep(1);  
    39.                 }  
    40.             }  
    41.         }  
    42.         cdb->curr_freq_idx[clk] = trgt;  /* 更新索引记录 */  
    43.   
    44.         if (ARM_CLK == clk && curr != trgt) {  
    45.             unsigned int i;  
    46.             struct cpufreq_freqs freqs = {  
    47.                 .flags = 0,  
    48.                 .old = frequency_table[clk][curr].freq / 1000,  
    49.                 .new = frequency_table[clk][trgt].freq / 1000,  
    50.             };  
    51.             if (freqs.new >= 806000) {  
    52.                 freqs.new = 1200000;  
    53.             }  
    54.             for_each_online_cpu(i) {  
    55.                 freqs.cpu = i;  
    56.                 /* 通知函数在 cpu 频率的调节过程中调用两次,驱动处理函数通过 cpufreq_register_notifier 注册 */  
    57.                 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);  
    58.             }  
    59.         }  
    60.     }  
    61. }  

    对于频率需要满足逐级调节的准则以保证系统的稳定性,ARM_CLK 的调节需要经过 cpufreq 子系统。至此,电压频率调节完成,线程将会执行调节请求的回调函数然后进入睡眠。


    * 调试注意:

    1、处理器需要可靠的电压 - 频率对应关系,这个需要较长时间的测试

    2、升频率时先升电压,降频率时后降电压

    3、逐级调节电压和频率有助于提升系统稳定性

    4、每次调节电压和频率后,尤其是升电压之后等待一定时间再升频率

    5、通常是在各模块的驱动程序里面进行电压和频率的调节,用户程序通过对各模块驱动的调用以达到调节的目的

    6、某些情况下为了获得更好的用户体验还可以对一些用户程序进行特殊处理让其直接将电压频率调节到最优值

    7、驱动程序里面升高电压频率时需要同步等待操作完成才能继续后续工作,因为一些硬件模块的工作对电压频率比较敏感

    8、用户程序为了获得更好的体验而升高电压频率,则不必同步等待其完成,因为用户程序对时序基本无要求


    * 调试心得:

    对于所有的软件bug,不能怀疑程序被处理器错误执行了,这个是可以保证的,唯一需要怀疑的就是程序的逻辑是否正确,一切bug都可以看做是没有完善的错误处理引起的,这是指导思想。(个人经验)


    转自:http://blog.csdn.net/g_salamander/article/details/17009055

    展开全文
  • 率调节(dynamic voltage frequency scaling,简称DVFS)来提升单节点的能耗表现.但是,DVFS这一类机制同时影响到.应用的能源消耗和性能,而这一问题尚未被深入探索.专注于 DVFS 机制对应用程序性能的影响,提出了一个分析...
  • dvfs 解析

    千次阅读 2013-12-02 21:48:01
    DVFS(Dynamic Voltage and Frequency Scaling)动态电压频率调节,是一种实时的电压和频率调节技术。在 CMOS 电路中功率消耗主要可以分为动态功率消耗和静态功率消耗,公式如下:   其中 C 代表负载电容的容值...

    一、基本概念

    DVFS(Dynamic Voltage and Frequency Scaling)动态电压频率调节,是一种实时的电压和频率调节技术。在 CMOS 电路中功率消耗主要可以分为动态功率消耗静态功率消耗,公式如下:

        

    其中 C 代表负载电容的容值,V工作电压α 是当前频率下的翻转率f工作频率I_dq 代表静态电流。公式的前部分代表的是动态功率消耗,后部分则代表的是静态功率消耗。从公式中可以看出,想要降低动态功率消耗可以从C、V、α、f着手,对于软件来讲常用的调节方式只涉及到V、f 两个因素。


    二、代码解析

    1、数据结构

    系统中存在 7 大总线:ARM_CLK、AXI_CLK、DSP_CLK、APP_CLK、MPH_CLK、GE_CLK、VS_CLK,DVFS 系统的所有工作都围绕这几大总线以及核心电压CORE_VOLTAGE展开,代码里面用到的数据结构有:DVFS_REQ、DVFS_CMD、DVFS_NODE、DVFS_CDB,定义如下:

    1. typedef struct {  
    2.     const char*   module;   /* 发出调节请求的模块名称 */  
    3.     unsigned char flag;     /* 调节频率的标记: 有最低、最高、锁定三种 */  
    4.     DVFS_CLK_e    clk;      /* 申请调节的时钟总线,有7大总线 */  
    5.     int           freq;     /* 期望频率值 */  
    6. } DVFS_REQ;  
    7.   
    8. typedef struct {  
    9.     DVFS_CBF    cb;     /* 回调函数 */  
    10.     int         arg;    /* 参数 */  
    11.     int         num;    /* 本次请求的数目 */  
    12.     DVFS_REQ    reqs[MAX_REQ_NUM];   /* 请求存放的数组,最多8个请求 */  
    13. } DVFS_CMD;  
    14.   
    15. typedef struct {  
    16.     struct list_head head;  /* 链表节点 */  
    17.     DVFS_REQ         req;   /* 当前请求 */  
    18. } DVFS_NODE;  
    19.   
    20. typedef struct {  
    21.     // cmd queue managment  
    22.     DVFS_CMD    q_array[CMD_Q_LENGTH];  
    23.     uint8_t     q_idx_r;  
    24.     uint8_t     q_idx_w;  
    25.     uint8_t     q_idx_p;  
    26.     spinlock_t  q_lock;  
    27.   
    28.     // worker thread management  
    29.     wait_queue_head_t q_wait;  /* 等待队列 */  
    30.     struct task_struct* task;  /* 任务 */  
    31.   
    32.     // list of request for each clock  
    33.     DVFS_NODE*  req_lists[DVFS_CLK_ALL];       /* 指向每条总线的请求链表 */  
    34.   
    35.     // clock/voltage setttings  
    36.     int         curr_freq_idx[DVFS_CLK_ALL];   /* 当前频率的索引值 */  
    37.     int         trgt_freq_idx[DVFS_CLK_ALL];   /* 目标频率的索引值 */  
    38.     struct clk* hw_clock[DVFS_CLK_ALL];        /* 时钟设置 */  
    39.     uint8_t curr_vol_idx;        /* 当前电压索引值 */  
    40.     uint8_t trgt_vol_idx;        /* 目标电压索引值 */  
    41.     unsigned long vol_jiffies;   /* 电压调节时间记录,用于记录调节间隔 */  
    42. } DVFS_CDB;  
    其中 DVFS_REQ 用于描述一个调节请求,存放了相关信息;DVFS_CMD 用于多个请求构造的一次调节操作;DVFS_NODE 作为链表节点,每一条总线的调节请求都由各自的链表维护;DVFS_CDB则存放了 DVFS 系统的大部分信息,系统中只存在一个全局的 DVFS_CDB 变量。

    2、函数接口

    当要调用 DVFS 系统时,通常的调用方法如下:

    1. DVFS_CREATE_REQ(reqs[0], "camera", AXI_CLK, axi_freq, DVFS_REQ_MIN);  /* 创建一个调节请求 */  
    2. init_completion(&cam_complete);  
    3. dvfs_send_reqs(reqs, 1, suspend_cb, 0);     /* 发送调节请求 */  
    4. wait_for_completion(&cam_complete);         /* 等待调节完成 */  
    通过 DVFS_CREATE_REQ 宏定义创建一个调节请求,宏定义原型如下:
    1. #define DVFS_CREATE_REQ(req, MODULE, CLK, FREQ, FLAG) { \  
    2.     req.module = MODULE;\  
    3.     req.clk = CLK;\  
    4.     req.flag = FLAG;\  
    5.     req.freq = FREQ;\  
    6.     }  
    宏主要用于构造一个 DVFS_REQ 结构,然后通过 dvfs_send_reqs 构造 DVFS_CMD 完成调节并执行回调函数 suspend_cb。

    3、代码解析

    在 DVFS 系统的初始化过程中,做的工作有如下几个:a、初始化 cdb->hw_clock;b、创建每条总线的链表;c、创建 proc 文件节点;d、创建等待队列以及内核线程专门用于 DVFS。当初始化完成之后就启动内核线程 dvfs_thread_func,在这里面会等待 dvfs_send_reqs 发出唤醒事件,然后进行电压和频率的调节并执行回调函数。下面我们从发送调节请求开始解析,函数 dvfs_send_reqs实现如下:

    1. int dvfs_send_reqs(DVFS_REQ *reqs, int num, DVFS_CBF cb, int arg)  
    2. {  
    3.     int      ret;  
    4.     DVFS_CMD *cmd;  
    5.     unsigned long irq_flags;  
    6.   
    7.     if ((ret = sanity_check(reqs, num))) {  /* 检查参数有效性 */  
    8.         return ret;  
    9.     }  
    10.   
    11.     if (num == 1 && reqs[0].clk == APP_CLK) {  /* APP_CLK 可以快速处理 */  
    12.         mutex_lock(&app_lock); /* 互斥体 */  
    13.         ret = dvfs_process_req(&dvfs_cdb, reqs);  /* 处理调节请求,如果需要调节返回非 0 值 */  
    14.         if (ret) {  
    15.             dvfs_cdb.curr_freq_idx[APP_CLK] = dvfs_cdb.trgt_freq_idx[APP_CLK];  
    16.             clk_set_rate(dvfs_cdb.hw_clock[APP_CLK], dvfs_get_rate(APP_CLK, dvfs_cdb.curr_freq_idx[APP_CLK]));  
    17.         }  
    18.         mutex_unlock(&app_lock);  
    19.         return 0;  
    20.     }  
    21.   
    22.     spin_lock_irqsave(&dvfs_cdb.q_lock, irq_flags);  /* 数据更新 */  
    23.     cmd = &dvfs_cdb.q_array[dvfs_cdb.q_idx_w & CMD_Q_MASK]; /* 构造 cmd */  
    24.     cmd->cb     = cb;  
    25.     cmd->num    = num;  
    26.     cmd->arg    = arg;  
    27.     memcpy(cmd->reqs, reqs, num * sizeof(DVFS_REQ));   
    28.     smp_mb();  
    29.     dvfs_cdb.q_idx_w++;  
    30.     spin_unlock_irqrestore(&dvfs_cdb.q_lock, irq_flags);  
    31.   
    32.     wake_up_all(&dvfs_cdb.q_wait);  /* 唤醒等待队列 */  
    33.     return 0;  
    34. }  
    35. EXPORT_SYMBOL(dvfs_send_reqs);  
    函数首先进行参数有效性验证,然后判断是否只调节 APP_CLK,因为 APP_CLK 用于外设不影响系统运行,所以可以直接调节。如果不只调节 APP_CLK 接下来将会构造 DVFS_CMD,然后唤醒内核线程 dvfs_thread_func,实现如下:
    1. int dvfs_thread_func(void *data)  
    2. {  
    3.     DVFS_CDB *cdb = (DVFS_CDB*)data;  
    4.     DVFS_CMD *cmd;  
    5.   
    6.     do {  
    7.         /* 等待唤醒 */  
    8.         if(wait_event_interruptible(cdb->q_wait, (cdb->q_idx_w != cdb->q_idx_r)) != 0)  
    9.             continue;  
    10.   
    11.         /* 判断是否需要调节电压和频率 */  
    12.         if (cal_target_freq(cdb)) {  
    13.             dvfs_reset_clk(cdb);  /* 开始调节 */  
    14.         }  
    15.           
    16.         /* 触发回调函数 */  
    17.         if (cmd->cb != NULL) {  
    18.             cmd->cb(cmd->arg);  
    19.         }  
    20.     } while (1);  
    21. }  
    当线程被唤醒后会根据函数 cal_target_freq 判断当前是否需要进行电压和频率的调节,cal_target_freq 里面首先根据传递的 CMD 更新链表,然后根据链表记录去判断是否需要调节频率,如果需要调节就会根据目标频率值通过查表(电压 - 频率表)查找系统支持的最合适的频率值。接着就来到了 DVFS 系统最重要的函数 dvfs_reset_clk,电压和频率调节都将在这个函数里面完成:
    1. void dvfs_reset_clk(DVFS_CDB *cdb)  
    2. {  
    3.     int idx;  
    4.     int vol;  
    5.   
    6. reqs_updated:  
    7.     cal_target_vol_idx(cdb);  /* 首先计算电压是否需要调节 */  
    8.   
    9.     /* 需要升高电压 */  
    10.     if (cdb->trgt_vol_idx > cdb->curr_vol_idx && arm_regulator) {  
    11.         for (idx = cdb->curr_vol_idx + 1; idx <= cdb->trgt_vol_idx; ++idx) {  
    12.             unsigned int interval_ms = jiffies_to_msecs(jiffies - cdb->vol_jiffies);  
    13.             if (interval_ms < 100) { /* 距离上次调节小于 100ms 则需等待 */  
    14.                 msleep(100 - interval_ms);  
    15.                 if (cal_target_freq(cdb))  
    16.                     goto reqs_updated;  
    17.             }  
    18.   
    19.             if (idx + 1 <= cdb->trgt_vol_idx)   
    20.                 ++idx;  
    21.             vol = voltage_table[idx].voltage;  
    22.             regulator_set_voltage(arm_regulator, vol, vol);  
    23.             cdb->curr_vol_idx = idx;  
    24.             cdb->vol_jiffies = jiffies;  
    25.             dvfs_dbg("DVFS increase arm voltage to %d uV\n", vol);  
    26.         }  
    27.     }  
    28.   
    29.     do_reset_clk(cdb);  /* 调节频率 */  
    30.     if (cal_target_freq(cdb))  /* 查看当前是否有新的调节请求 */  
    31.         goto reqs_updated;  
    32.   
    33.     /* 需要降低电压 */  
    34.     if (cdb->trgt_vol_idx < cdb->curr_vol_idx && arm_regulator) {  
    35.         for (idx = cdb->curr_vol_idx - 1; idx >= cdb->trgt_vol_idx; --idx) {  
    36.             unsigned int interval_ms = jiffies_to_msecs(jiffies - cdb->vol_jiffies);  
    37.             if (interval_ms < 100) {  
    38.                 msleep(100 - interval_ms);  
    39.                 if (cal_target_freq(cdb))  
    40.                     goto reqs_updated;  
    41.             }  
    42.   
    43.             vol = voltage_table[idx].voltage;  
    44.             regulator_set_voltage(arm_regulator, vol, vol);  
    45.             cdb->curr_vol_idx = idx;  
    46.             cdb->vol_jiffies = jiffies;  
    47.             dvfs_dbg("DVFS decrease arm voltage to %d uV\n", vol);  
    48.         }  
    49.     }  
    50. }  

    函数里面先进行电压调节满足“升频率时先升电压,降频率时后降电压”的准则并且两次电压的调节需要间隔 100ms以上,然后通过 do_reset_clk 进行频率调节,实现如下:

    1. static void do_reset_clk(DVFS_CDB *cdb)  
    2. {  
    3.     int clk, idx;  
    4.   
    5.     for (clk = 0; clk < DVFS_CLK_ALL; clk++) { /* 依次调节频率 */  
    6.         int curr = cdb->curr_freq_idx[clk];  
    7.         int trgt = cdb->trgt_freq_idx[clk];  
    8.   
    9.         if (ARM_CLK == clk && curr != trgt) {  /* 调整 arm 频率,需要经过 cpufreq 子系统 */  
    10.             unsigned int i;  
    11.             struct cpufreq_freqs freqs = {  
    12.                 .flags = 0,  
    13.                 .old = frequency_table[clk][curr].freq / 1000,  
    14.                 .new = frequency_table[clk][trgt].freq / 1000,  
    15.             };  
    16.             for_each_online_cpu(i) {  
    17.                 freqs.cpu = i;  
    18.                 /* 函数向挂载在这个 cpu 上所有的驱动发出一个信号,驱动接收到这个信号则调用相应的处理函数 */  
    19.                 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);  
    20.             }  
    21.         }  
    22.   
    23.         if (curr < trgt) {  /* 如果当前频率比目标频率低 */  
    24.             for (idx = curr+1; idx <= trgt; idx++) {  /* 逐级调节频率可以保证系统的稳定性 */  
    25.                 if (idx == trgt) {  
    26.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    27.                 } else if (frequency_table[clk][idx].need_delay) {  
    28.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    29.                     msleep(1);  
    30.                 }  
    31.             }  
    32.         } else if (curr > trgt) { /* 如果当前比目标频率高 */  
    33.             for (idx = curr-1; idx >= trgt; idx--) {  /* 逐级调节频率可以保证系统的稳定性 */  
    34.                 if (idx == trgt) {  
    35.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    36.                 } else if (frequency_table[clk][idx].need_delay) {  
    37.                     clk_set_rate(cdb->hw_clock[clk], frequency_table[clk][idx].freq);  
    38.                     msleep(1);  
    39.                 }  
    40.             }  
    41.         }  
    42.         cdb->curr_freq_idx[clk] = trgt;  /* 更新索引记录 */  
    43.   
    44.         if (ARM_CLK == clk && curr != trgt) {  
    45.             unsigned int i;  
    46.             struct cpufreq_freqs freqs = {  
    47.                 .flags = 0,  
    48.                 .old = frequency_table[clk][curr].freq / 1000,  
    49.                 .new = frequency_table[clk][trgt].freq / 1000,  
    50.             };  
    51.             if (freqs.new >= 806000) {  
    52.                 freqs.new = 1200000;  
    53.             }  
    54.             for_each_online_cpu(i) {  
    55.                 freqs.cpu = i;  
    56.                 /* 通知函数在 cpu 频率的调节过程中调用两次,驱动处理函数通过 cpufreq_register_notifier 注册 */  
    57.                 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);  
    58.             }  
    59.         }  
    60.     }  
    61. }  

    对于频率需要满足逐级调节的准则以保证系统的稳定性,ARM_CLK 的调节需要经过 cpufreq 子系统。至此,电压频率调节完成,线程将会执行调节请求的回调函数然后进入睡眠。


    * 调试注意:

    1、处理器需要可靠的电压 - 频率对应关系,这个需要较长时间的测试

    2、升频率时先升电压,降频率时后降电压

    3、逐级调节电压和频率有助于提升系统稳定性

    4、每次调节电压和频率后,尤其是升电压之后等待一定时间再升频率

    5、通常是在各模块的驱动程序里面进行电压和频率的调节,用户程序通过对各模块驱动的调用以达到调节的目的

    6、某些情况下为了获得更好的用户体验还可以对一些用户程序进行特殊处理让其直接将电压频率调节到最优值

    7、驱动程序里面升高电压频率时需要同步等待操作完成才能继续后续工作,因为一些硬件模块的工作对电压频率比较敏感

    8、用户程序为了获得更好的体验而升高电压频率,则不必同步等待其完成,因为用户程序对时序基本无要求


    * 调试心得:

    对于所有的软件bug,不能怀疑程序被处理器错误执行了,这个是可以保证的,唯一需要怀疑的就是程序的逻辑是否正确,一切bug都可以看做是没有完善的错误处理引起的,这是指导思想。(个人经验)

    展开全文
  • 使用动态电压和频率缩放(DVFS),CMP系统可以在性能和能效之间取得平衡。 在本文中,我们提出了一种针对CMP系统的三相离散DVFS算法,该算法专用于应用程序周期较长的应用程序。 任务图小于任务的截止日期。 在这些...
  • 文章目录功耗降低技术 —— DVFS 功耗降低技术 —— DVFS DVFS:Dynamic voltage and frequency scaling:动态电压频率调整 根据芯片所运行的应用程序对计算机的不同需要,动态调节芯片的运行频率和电压(对统一芯片...
  • DVFS User Guide

    2016-04-29 17:35:36
    What is DVFS? Dynamic Voltage and Frequency scaling is a framework to change the frequency and/or operating voltage of a processor(s) based on system performance requirements at the given point of
  • rk3288 android6.0 dvfs

    2018-04-17 15:35:29
    Platform: RockchipOS: Android 6.0Kernel: 3.10.92ddr,gpu以及arm的clock都受dvfs模块管控, 所以只要执行:root@rk3288:/ # cat /sys/dvfs/dvfs_tree [78603.186480] -------------DVFS TREE-----------[78603....
  • CloudSim DVFS

    2014-07-16 14:55:17
    澳大利亚墨尔本大学开发的云计算仿真工具CloudSim的改进版,用来模拟节点技术,适合研究云计算或绿色云计算的可研人员
  • 在本文中,我们试图研究当数据中心配备能源感知方法时,即使用动态电压和频率缩放 (DVFS) 方法而不使用节能方法时能耗水平的差异。 仿真结果表明,与非功耗感知方法相比,支持 DVFS 的数据中心消耗的能源减少了 66%...
  • Latency-aware DVFS for efficient power state transitions on many-core architectures
  • 为了解决云数据中心资源分配时能耗与性能间的均衡问题,提出了一种基于DVFS感知与虚拟机动态合并的能效优化策略。首先,策略通过新的DVFS管理算法(DVFS-perf)在不降低系统性能的同时降低了数据中心功耗;然后,...
  • Linux系统中的dvfs功能

    2020-01-29 17:34:37
    由于调整是在系统运行的过程中,因此这种功能也称作动态电压/频率调整(Dynamic Voltage/Frequency Scaling,DVFS)。说白了,就是在不需要高性能时,降低电压和频率,以降低功耗;在需要高性能时,...
  • 适用于基于DVFS的SoC的高效​​全数字IR下降报警器
  • Linux DEVFREQ - 通用DVFS Framework

    千次阅读 2018-08-13 13:21:26
    DEVFREQ: generic DVFS framework with device-specific OPPs, devfreq是来自三星的MyungJoo Ham myungjoo.ham@samsung.com 一个具有OPPs的设备(Operating Performance Points)一般具有多个档位的频率和电压集合...
  • DVFS及多核处理器功耗优化技术详解

    千次阅读 2018-10-09 20:25:04
     降低嵌入式系统功耗有多种方法,其中动态电源管理(DPM)和动态电压频率调整技术(DVFS)是降低系统功耗的两种关键技术。其中动态电源管理主要依据设备工作负载的变化切换器工作状态以达到系统功耗最小化。本篇...
  • DVFS CPUFreq Regulator

    千次阅读 2015-03-03 16:57:33
    DVFS CPUFreq Regulator  一、 Cpu 频率调节 (governor:调节器) 1.1 Linux内部共有以下几种对cpu频率的管理策略 Ø Performance n CPU会固定工作在其支持的最高运行频率上 Ø Powersave n CPU会固定...
  • [RK3288][Android6.0] GPU DVFS控制策略小结

    千次阅读 2017-09-22 09:31:51
    Kernel: 3.10.92mali_device_driver 分为两个部分 : platform_dependent_part 和 common_parts, 参见 mali_kbase_config_rk.c 开头部分的注释.gpu dvfs核心控制在mali_kbase_dvfs.c中.s_mali_dvfs_lev
  • DVFS--动态电压频率调整
  • Kernel: 3.10.92GPU的DVFS不是在dts而是在驱动中直接控制并且默认打开的.DVFS控制核心函数是mali_dvfs_event_proc(), 放在队列中处理,而队列是否开启受变量dvfs->is_enabled的控制.int kbase_platform_dvfs_event...
  • rk3368 dvfs 相关的一些理解

    千次阅读 2017-12-29 11:01:38
    dts 文件&clk_core_b_dvfs_table { operating-points = < /* KHz uV */ 216000 950000 312000 950000 408000 950000 600000 950000 696000 950000 816000 975000 1008000 1050000 //1200000 115

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,058
精华内容 423
关键字:

DVFS