精华内容
下载资源
问答
  • 为了提高频谱的利用效率和应对无线传感网络中多节点频率信息动态配置问题,提出了一种基于云计算的WSN动态频率分配系统。该动态频率分配系统在无线传感器网络的无线通信框架上,利用云资源调度、分布式数据管理、...
  • 芯片面积和功耗与工作频率紧密相关,在保持原有项目设计的条件下,利用门电路在不同频率下的开关工作原理,提出一种动态频率闭环设计方法,从系统级综合优化芯片的面积和功耗。通过筛选满足条件的多组测试集,建立...
  • Linux动态频率调节系统CPUFreq之一:概述 Linux动态频率调节系统CPUFreq之二:核心(core)架构与API Linux动态频率调节系统CPUFreq之三:governor
    展开全文
  • 提出了一种电网动态频率测量的移频迭代滤波新方法,该方法首先采用时域移频将信号负频率成分移到零频附近,然后采用迭代滤波方法滤除高频分量和噪声,最后运用相位差实现频率估计。所提方法具有抗噪性好、运算量小的...
  • 一种LDO稳压器内部动态频率补偿电路的设计 刘鸿雁1 来新泉2 黄涛涛2 1 中国人民解放军92941部队 2 西安电子科技大学电路CAD研究所 引言 LDO稳压器的调整元件通常采用PNP管或PMOS管,通过共射或共源的结构输出,...
  • 动态频率选择(DFS )一直是无线供应商和部署者之间备受争论的话题,自第一个5GHz无线标准出现以来,DFS一直以来都是一个考虑因素,但现在,802.11ac中使用的更宽的带宽信道使这个问题更加复杂化了。在本文中,我们将...
  • 一种LDO稳压器内部动态频率补偿电路的设计 刘鸿雁1 来新泉2 黄涛涛2 1 中国人民解放军92941部队 2 西安电子科技大学电路CAD研究所 引言 LDO稳压器的调整元件通常采用PNP管或PMOS管,通过共射或共源的结构输出,...
  • WiFi DFS(动态频率选择)

    2021-01-27 08:55:21
    然而,就在你畅快的体验的5GHZ WiFi带来的快感时,有一个潜在的问题必须要足够重视: DFS(动态频率选择),这也是很多商用WLAN公司的产品走出国门时必须要面对的一个问题。 DFS机制研究的背景 WiFi网络资源是免费

    前言

    WiFi网络为我们提供了2个无线LAN网络运营频段:2.4GHZ频段和5GHz频段。2.4GHz频段的干扰是目前WLAN网络面临的困境之一。许多无线局域网专业人员通常会建议您尽可能将重要的业务场景放在5GHz频段上,因为5GHz频段拥有更多可用信道且每个信道相应的设备数量相应更少。然而,就在你畅快的体验的5GHZ WiFi带来的快感时,有一个潜在的问题必须要足够重视: DFS(动态频率选择),这也是很多商用WLAN公司的产品走出国门时必须要面对的一个问题。

    DFS机制研究的背景

    WiFi网络资源是免费许可的频谱资源,这对比其他的需授权无线频谱来讲确实是一个优势。但是即使WLAN是免许可的,仍然要考虑在同频段中其最小化影响其他无线设备的运行。

    这其中,与无线LAN共享频谱的一项特殊服务是雷达。某些类型的雷达安装工作在WiFi网络使用的5GHz频段,这意味着他们可能会使用一些与WiFi网络相同的频率。

    DFS(Dynamic Frequency Selection)动态频率选择。 是一种用于动态选择无线局域网(WLAN)中接入点(AP)
    与多个移动终端(MT)之间的通信信道的方法和系统。

    802.11a标准使用5GHz频率。这个标准在美国没有问题,但是在欧洲却遇到强烈的抵制。因为欧洲军方的雷达系统广泛运用这一频率(其中探测隐型飞机的雷达就使用这一频率)。如果民用的无线产品也使用这一频率,很可能会对军事雷达和通讯产生干扰。为了解决这一安全顾虑,在欧洲出售的WLAN产品必须具备TPS和DFS这两个功能,即发射功率控制和动态频率选择。TPS是为了防止无线产品发放过大的功率来干扰军方雷达。DFS是为了使无线产品主动探测军方使用的频率,并主动选择另一个频率,以避开军方频率。通过这种方式,也可以避免其它WLAN,最高效地利用波长。这两个功能是属于强制性的,不符合标准的产品将不会获得欧盟的上市许可。

    展开全文
  • 从二维热力学方程在动态频率范围内的解析,我们根据材料的深度或横向绘制了温度的演化曲线。 它们将使我们能够评估被牵引材料的热行为。 研究的目的是通过提出一种在动态频率范围内确定有效隔热层的方法来将纤维用作...
  • 基于小区间干扰抑制的AFDD双工系统动态频率分配方案,王永涛,王宗文,未来的移动通信系统要求其无线资源分配策略能抑制小区间的干扰,适应上下行业务分布不对称的特性,提供较高的频谱利用率。自适应
  • DFS(动态频率选择)与802.11n

    千次阅读 2016-08-06 17:08:35
    DFS(动态频率选择)与802.11n http://www.searchnetworking.com.cn/showcontent_16081.htm 随着802.11n产品化并大大增加Wi-Fi在5GHz频段的使用,DFS(动态频率选择)开始进入WLAN用户视野,DFS是什么概念?...

    DFS(动态频率选择)与802.11n

    http://www.searchnetworking.com.cn/showcontent_16081.htm

    随着802.11n产品化并大大增加Wi-Fi在5GHz频段的使用,DFS(动态频率选择)开始进入WLAN用户视野,DFS是什么概念?用户应如何选择?最近能引起风波的802.11n话题都围绕在一种叫做DFS(动态频率选择)的功能上展开,很多与DFS相关的问题都需要我们审慎考虑。DFS从何而来几年前,美国相关部门针对Wi-Fi传输流开放了5GHz频段中的更多信道,主要想法是为Wi-Fi技术提供更多的信道容量。从理论上讲,用户拥有能够传送传输流的信道越多,总可用容量就变得越大,因此这一措施被认为是件好事情。鉴于当时802.11n还只是IEEE正在酝酿中的标准,FCC(美国联邦通信委员会)主要是为 802.11a网络批准了Wi-Fi设备使用免许可国家信息基础设施(UNII)-2频段(具体说,就是5.25GHz~5.35GHz,以及 5.47GHz~5.725GHz中的信道)的许可。同时,由于这些频段还用于军用设备和气象雷达,因此它暗含一个必备条件:运行在这些频段中的产品必须获得支持DFS技术的FCC认证。这种DFS技术被用来检测UNII-2信道中是否存在雷达数据,如果存在,它会迅速将任何干扰传输转移到其他信道,为雷达使用清除障碍。这样做也是十分合理的:事关国家安全的事情或许应当优先于条形码扫描。华盛顿特区Fish & Richardson律师事务所法规实践主管Terry Mahn透露,不愿支持DFS的厂商可以选择以集成商或最终用户不能修改的理由阻塞那些额外信道。而在实践的过程中,当802.11n逐渐成为人们的主要话题时,业界也几乎没有开始部署可以使用这些额外信道的802.11a网络。同时,802.11n则主要依赖于5GHz频段来提供它所承诺的更大的吞吐量,因此有许多用户都将跳过802.11a的部署而直接选择802.11n。你的802.11n设备厂商支持DFS吗?如果不支持,有什么不利之处吗?如果支持,可能还存在什么不利之处吗?与你有关的答案部分取决于你的容量需求和避免干扰的方法,以及你选择的WLAN厂商的实现情况。福音还是麻烦前面提到,按照美国管理部门的观点,DFS变换信道的能力适用于军用和气象雷达偶尔使用的,并且FCC也同意在没有雷达数据传输时可用于Wi-Fi传输的某些5GH频段。那么从实现和性能角度看,这意味着什么呢?首先,你是否真的需要使用3个免许可国家信息基础设施(UNII)5GHz频段中的全部12个非重叠信道?如果答案是肯定的,你选择的厂商必须要做出比“支持DFS技术”更多的工作。其产品必须获得在5.25GHz~5.35GHz和 5.47GHz~5.725GHz使用的FCC认证,这就意味着该产品要通过一家FCC实验室对DFS能力的检测。如果某个5GHz Wi-Fi产品没有获得在这些信道中使用的FCC认证,将发生以下两件事中的一件事情:1、厂商将阻塞这些信道,使你不能使用它们,这种做法符合FCC的规定,但却意味着你放弃使用一些频段的潜力;2、厂商要么出于无知,要么有意骗你非法使用这些信道。Terry Mahn表示,如果FCC发现你的厂商在没有获得FCC DFS认证的情况下开放这些信道,FCC“将有你的厂商好看的。”他马上接着补充说,作为企业用户,你不负有支付罚金或受到其他处罚的责任,但必须关闭网络,直到阻塞这些信道或者是获得FCC认证后。Gartner最近也发表了一篇有关DFS问题的短报告,建议避免在UNII-2频段中运行关键任务应用,因为这些信道最容易出现信道变更和相关的延迟。还有另一个情况,你的厂商合法地支持DFS并获得了FCC认证,但这家厂商可能选择了在所有的信道上支持DFS(而不仅仅是所需要的UNII-2频段)作为其避免信道干扰的技术。这类产品将把在任何信道中遇到干扰的传输流转移到另一个信道。而如果这些系统特别容易出现干扰并因此进行很多的信道变更的话,你可能最后得到的是很多的延迟和不稳定的性能。例如,一些系统在传输流一旦切换到一个新信道后就要求整个重启。而另一些系统则不这样做。因此,一个友善的DFS系统给你带来的是福音还是麻烦,实际上取决于许多情况,而这些情况你应当在制定802.11n战略时仔细考虑。Drexel大学的选择一个实际的例子是,美国费城Drexel大学现在正忙着安装一千台Draft 2.0 802.11n接入点:这所拥有21000名学生的研究型大学将用Aruba 802.11n设备代替2004年安装的Cisco 1200系统“胖”802.11g接入点。Aruba公司的设备对DFS支持的考虑使得Drexel做出了最后决定。Drexel大学核心技术助理副总裁Kenneth Blackney介绍说,过去大学里使用非屏蔽同轴电缆技术将信号扩展到各个宿舍,每隔3到4米竖立的墙壁会造成信号的减弱。为了补偿信号的衰减,Drexel采用同轴电缆作为一条扩展信号覆盖范围的长长的“天线”。为了让一定受控量的射频信号泄露到空中,非屏蔽同轴电缆的外导体上有很多开口,从而代替每隔几英尺部署接入点或购买昂贵的分布式天线系统(DAS)。“然而,我们在使用Aruba设备时将不会使用非屏幕同轴电缆。”Blackney指出,“因为我们现在面临的问题是大大增加容量而不是覆盖范围。为此,我们将安装7倍于我们目前接入点数量的接入点。”最终,这所大学决定只在5GHz频段部署802.11n,同时将所有802.11n传输转移到5GHz 频段。Blackney解释说:“我们的校园地处市内,有很多人住在我们的周边。2.4GHz频段非常拥挤和嘈杂。”而在启用DFS功能后,5GHz频段可在美国提供12个非重叠的信道。在做出这一决定后,其他竞争对手避免同信道干扰的方法在Blackney眼里“变得不是很有意义”。Blackney表示,“Aruba提供额外的频段(支持DFS)并且比其他产品使用的功率略低,这使它非常适合Drexel。”小贴士:选择DFS产品四部曲 1. 确定你的无线网络的容量需求。在启用DFS功能后,5GHz频段可提供12个非重叠的信道(美国地区),你真的需要那么多信道吗? 2. 确定避免无线信道干扰的方法。每个无线设备厂商都有自己的独特技术,未必DFS就是最适合自己网络情况的方式。 3. 如果确实需要使用DFS,考虑清楚可能带来的不良后果(更多的延迟和不稳定的性能),同时避免在这些信道上传输关键业务。 4. 选择支持DFS的产品时,要确定该厂商是否合法地支持DFS并获得了FCC认证。与DFS相关的标准和技术802.11h针对802.11a无线网络在5GHz频段工作时遇到的信道干扰问题而制定,其所定义的机制能使基于802.11a的无线系统避免与雷达和其他同类系统中的宽带技术相干扰,保障无线通信的畅通。为此,802.11h引入DFS和发射功率控制(TPC)两项关键技术。后者旨在通过降低WLAN设备的无线发射功率,减少WLAN与卫星通信的相互干扰。 TPC还能用于管理无线装置的功耗和接入点与无线装置之间的距离。软件定义无线电(SDR)与802.11n及DFS密切相关,FCC对SDR的描述为:“从前完全在硬件中执行的功能,比如发射信号的产生,以及接收到的无线信号的调谐和检测等,可利用软件控制高速信号处理器的方式来实现。”简单地说,SDR可以让一个无线电在多个频段中进行变化调整,来适应复杂应用带来的各种规格。SDR和DFS的关系是,FCC不允许 802.11设备厂商未经认证的情况下将产品升级为支持DFS,除非这些产品具有FCC认证的SDR功能。SDR关系到UNII-2频段和DFS,在帮助 802.11n获得更高传输速率方面具有重要的作用。

    TechTarget中国原创内容,原文链接: http://www.searchnetworking.com.cn/showcontent_16081.htm
    © TechTarget中国:http://www.techtarget.com.cn

    展开全文
  • Linux动态频率调节系统CPUFreq之三:governor 转载 目录(?)[+] 在上一篇文章中,介绍了cpufreq的core层,core提供了cpufreq系统的初始化,公共数据结构的建立以及对cpufreq中其它子 部件提供注册...
    转载

    目录(?)[+]

    在上一篇文章中,介绍了cpufreq的core层,core提供了cpufreq系统的初始化,公共数据结构的建立以及对cpufreq中其它子 部件提供注册功能。core的最核心功能是对policy的管理,一个policy通过cpufreq_policy结构中的governor字段,和某 个governor相关联,本章的内容正是要对governor进行讨论。

    /*****************************************************************************************************/

    声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!

    /*****************************************************************************************************/

    通过前面两篇文章的介绍,我们知道,governor的作用是:检测系统的负载状况,然后根据当前的负载,选择出某个可供使用的工作频率,然后把该 工作频率传递给cpufreq_driver,完成频率的动态调节。内核默认提供了5种governor供我们使用,在之前的内核版本中,每种 governor几乎是独立的代码,它们各自用自己的方式实现对系统的负载进行监测,很多时候,检测的逻辑其实是很相似的,各个governor最大的不 同之处其实是根据检测的结果,选择合适频率的策略。所以,为了减少代码的重复,在我现在分析的内核版本中(3.10.0),一些公共的逻辑代码被单独抽象 出来,单独用一个文件来实现:/drivers/cpufreq/cpufreq_governor.c,而各个具体的governor则分别有自己的代 码文件,如:cpufreq_ondemand.c,cpufreq_performance.c。下面我们先从公共部分讨论。

    1.  数据结构


    cpu_dbs_common_info  该结构把对计算cpu负载需要使用到的一些辅助变量整合在了一起,通常,每个cpu都需要一个cpu_dbs_common_info结构体,该结构体中的成员会在governor的生命周期期间进行传递,以用于统计当前cpu的负载,它的定义如下:

    1. /* Per cpu structures */  
    2. struct cpu_dbs_common_info {  
    3.         int cpu;  
    4.         u64 prev_cpu_idle;  
    5.         u64 prev_cpu_wall;  
    6.         u64 prev_cpu_nice;  
    7.         struct cpufreq_policy *cur_policy;  
    8.         struct delayed_work work;  
    9.   
    10.         struct mutex timer_mutex;  
    11.         ktime_t time_stamp;  
    12. };  
    • cpu  与该结构体相关联的cpu编号。
    • prev_cpu_idle  上一次统计时刻该cpu停留在idle状态的总时间。
    • prev_cpu_wall  上一次统计时刻对应的总工作时间。
    • cur_policy  指向该cpu所使用的cpufreq_policy结构。
    • work  工作队列,该工作队列会被定期地触发,然后定期地进行负载的更新和统计工作。
    dbs缩写,实际是:demand based switching,通常,因为cpu_dbs_common_info只包含了经过抽象后的公共部分,所以,各个governor会自己定义的一个包含 cpu_dbs_common_info的自定义结构,例如对于ondemand,他会定义:
    1. struct od_cpu_dbs_info_s {  
    2.         struct cpu_dbs_common_info cdbs;  
    3.         struct cpufreq_frequency_table *freq_table;  
    4.         unsigned int freq_lo;  
    5.         unsigned int freq_lo_jiffies;  
    6.         unsigned int freq_hi_jiffies;  
    7.         unsigned int rate_mult;  
    8.         unsigned int sample_type:1;  
    9. };  
    而对于Conservative,他的定义如下:
    1. struct cs_cpu_dbs_info_s {  
    2.         struct cpu_dbs_common_info cdbs;  
    3.         unsigned int down_skip;  
    4.         unsigned int requested_freq;  
    5.         unsigned int enable:1;  
    6. };  
    把它理解为类似于C++语言的基类和子类的概念就是了。


    common_dbs_data    各个独立的governor,需要和governor的公共层交互,需要实现一套公共的接口,这个接口由common_dbs_data结构来提供:

    1. struct common_dbs_data {  
    2.         /* Common across governors */  
    3.         #define GOV_ONDEMAND            0  
    4.         #define GOV_CONSERVATIVE        1  
    5.         int governor;  
    6.         struct attribute_group *attr_group_gov_sys; /* one governor - system */  
    7.         struct attribute_group *attr_group_gov_pol; /* one governor - policy */  
    8.   
    9.         /* Common data for platforms that don't set have_governor_per_policy */  
    10.         struct dbs_data *gdbs_data;  
    11.   
    12.         struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu);  
    13.         void *(*get_cpu_dbs_info_s)(int cpu);  
    14.         void (*gov_dbs_timer)(struct work_struct *work);  
    15.         void (*gov_check_cpu)(int cpu, unsigned int load);  
    16.         int (*init)(struct dbs_data *dbs_data);  
    17.         void (*exit)(struct dbs_data *dbs_data);  
    18.   
    19.         /* Governor specific ops, see below */  
    20.         void *gov_ops;  
    21. };  
    主要的字段意义如下:
    • governor  因为ondemand和conservative的实现部分有很多相似的地方,用该字段做一区分,可以设置为GOV_ONDEMAND或GOV_CONSERVATIVE的其中之一。
    • attr_group_gov_sys  该公共的sysfs属性组。
    • attr_group_gov_pol  各policy使用的属性组,有时候多个policy会使用同一个governor算法。
    • gdbs_data  通常,当没有设置have_governor_per_policy时,表示所有的policy使用了同一种governor,该字段指向该governor的dbs_data结构。
    • get_cpu_cdbs  回调函数,公共层用它取得对应cpu的cpu_dbs_common_info结构指针。
    • get_cpu_dbs_info_s  回调函数,公共层用它取得对应cpu的cpu_dbs_common_info_s的派生结构指针,例如:od_cpu_dbs_info_s,cs_cpu_dbs_info_s。
    • gov_dbs_timer  前面说过,cpu_dbs_common_info_s结构中有一个工作队列,该回调通常用作工作队列的工作函数。
    • gov_check_cpu  计算cpu负载的回调函数,通常会直接调用公共层提供的dbs_check_cpu函数完成实际的计算工作。
    • init   初始化回调,用于完成该governor的一些额外的初始化工作。
    • exit  回调函数,governor被移除时调用。
    • gov_ops  各个governor可以用该指针定义各自特有的一些操作接口。

    dbs_data    该结构体通常由governor的公共层代码在governor的初始化阶段动态创建,该结构的一个最重要的字段就是cdata:一个 common_dbs_data结构指针,另外,该结构还包含一些定义governor工作方式的一些调节参数。该结构的详细定义如下:

    1. struct dbs_data {  
    2.         struct common_dbs_data *cdata;  
    3.         unsigned int min_sampling_rate;  
    4.         int usage_count;  
    5.         void *tuners;  
    6.   
    7.         /* dbs_mutex protects dbs_enable in governor start/stop */  
    8.         struct mutex mutex;  
    9. };  

    几个主要的字段:
    • cdata  一个common_dbs_data结构指针,通常由具体governor的实现部分定义好,然后作为参数,通过公共层的 API:cpufreq_governor_dbs,传递到公共层,cpufreq_governor_dbs函数在创建好dbs_data结构后,把该 指针赋值给该字段。
    • min_sampling_rate  用于记录统计cpu负载的采样周期。
    • usage_count  当没有设置have_governor_per_policy时,意味着所有的policy采用同一个governor,该字段就是用来统计目前该governor被多少个policy引用。
    • tuners  指向governor的调节参数结构,不同的governor可以定义自己的tuner结构,公共层代码会在governor的初始化阶段调用 common_dbs_data结构的init回调函数,governor的实现可以在init回调中初始化tuners字段。
    如果设置了have_governor_per_policy,每个policy拥有各自独立的governor,也就是说,拥有独立的 dbs_data结构,它会记录在cpufreq_policy结构的governor_data字段中,否则,如果没有设置 have_governor_per_policy,多个policy共享一个governor,和同一个dbs_data结构关联,此 时,dbs_data被赋值在common_dbs_data结构的gdbs_data字段中。

    cpufreq_governor  这个结构在本系列文章的第一篇已经介绍过了,请参看Linux动态频率调节系统CPUFreq之一:概述。几个数据结构的关系如下图所示:


                                                                                             图 1.1  governor的数据结构关系

    下面我们以ondemand这个系统已经实现的governor为例,说明一下如何实现一个governor。具体的代码请参看:/drivers/cpufreq/cpufreq_ondemand.c。

    2.  定义一个governor


    要实现一个governor,首先要定义一个cpufreq_governor结构,对于ondeman来说,它的定义如下:

    1. struct cpufreq_governor cpufreq_gov_ondemand = {  
    2.         .name                   = "ondemand",  
    3.         .governor               = od_cpufreq_governor_dbs,  
    4.         .max_transition_latency = TRANSITION_LATENCY_LIMIT,  
    5.         .owner                  = THIS_MODULE,  
    6. };  
    其 中,governor是这个结构的核心字段,cpufreq_governor注册后,cpufreq的核心层通过该字段操纵这个governor的行 为,包括:初始化、启动、退出等工作。现在,该字段被设置为od_cpufreq_governor_dbs,我们看看它的实现:
    1. static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,  
    2.                 unsigned int event)  
    3. {  
    4.         return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);  
    5. }  
    只 是简单地调用了governor的公共层提供的API:cpufreq_governor_dbs,关于这个API,我们在后面会逐一进行展开,这里我们 注意到参数:&od_dbs_cdata,正是我们前面讨论过得common_dbs_data结构,作为和governor公共层的接口,在这 里它的定义如下:
    1. static struct common_dbs_data od_dbs_cdata = {  
    2.         .governor = GOV_ONDEMAND,  
    3.         .attr_group_gov_sys = &od_attr_group_gov_sys,  
    4.         .attr_group_gov_pol = &od_attr_group_gov_pol,  
    5.         .get_cpu_cdbs = get_cpu_cdbs,  
    6.         .get_cpu_dbs_info_s = get_cpu_dbs_info_s,  
    7.         .gov_dbs_timer = od_dbs_timer,  
    8.         .gov_check_cpu = od_check_cpu,  
    9.         .gov_ops = &od_ops,  
    10.         .init = od_init,  
    11.         .exit = od_exit,  
    12. };  
    这 里先介绍一下get_cpu_cdbs和get_cpu_dbs_info_s这两个回调,前面介绍cpu_dbs_common_info_s结构的时 候已经说过,各个governor需要定义一个cpu_dbs_common_info_s结构的派生结构,对于ondemand来说,这个派生结构 是:od_cpu_dbs_info_s。两个回调函数分别用来获得基类和派生类这两个结构的指针。我们先看看od_cpu_dbs_info_s是如何 定义的:
    1. static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);  
    没 错,它被定义为了一个per_cpu变量,也就是说,每个cpu拥有各自独立的od_cpu_dbs_info_s,这很正常,因为每个cpu需要的实时 负载是不一样的,需要独立的上下文变量来进行负载的统计。前面也已经列出了od_cpu_dbs_info_s的声明,他的第一个字段cdbs就是一个 cpu_dbs_common_info_s结构。内核为我们提供了一个辅助宏来帮助我们定义get_cpu_cdbs和 get_cpu_dbs_info_s这两个回调函数:
    1. #define define_get_cpu_dbs_routines(_dbs_info)                          \  
    2. static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu)                \  
    3. {                                                                       \  
    4.         return &per_cpu(_dbs_info, cpu).cdbs;                           \  
    5. }                                                                       \  
    6.                                                                         \  
    7. static void *get_cpu_dbs_info_s(int cpu)                                \  
    8. {                                                                       \  
    9.         return &per_cpu(_dbs_info, cpu);                                \  
    10. }        
    所以,在cpufreq_ondemand.c中,我们只要简单地使用上述的宏即可定义这两个回调:
    1. define_get_cpu_dbs_routines(od_cpu_dbs_info);  
    经过上述这一系列的定义以后,governor的公共层即可通过这两个回调获取各个cpu所对应的cpu_dbs_common_info_s和od_cpu_dbs_info_s的结构指针,用来记录本次统计周期的一些上下文参数(idle时间和运行时间等等)。

    3.  初始化一个governor


    当一个governor被policy选定后,核心层会通过__cpufreq_set_policy函数对该cpu的policy进行设定,参看 Linux动态频率调节系统CPUFreq之二:核心(core)架构与API中 的第4节和图4.1。如果policy认为这是一个新的governor(和原来使用的旧的governor不相同),policy会通过 __cpufreq_governor函数,并传递CPUFREQ_GOV_POLICY_INIT参数,而__cpufreq_governor函数实 际上是调用cpufreq_governor结构中的governor回调函数,在第2节中我们已经知道,这个回调最后会进入governor公共 API:cpufreq_governor_dbs,下面是它收到CPUFREQ_GOV_POLICY_INIT参数时,经过简化后的代码片段:

    1. case CPUFREQ_GOV_POLICY_INIT:  
    2.         ......  
    3.   
    4.         dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL);  
    5.         ......  
    6.   
    7.         dbs_data->cdata = cdata;  
    8.         dbs_data->usage_count = 1;  
    9.         rc = cdata->init(dbs_data);  
    10.         ......  
    11.   
    12.         rc = sysfs_create_group(get_governor_parent_kobj(policy),  
    13.                         get_sysfs_attr(dbs_data));  
    14.         ......  
    15.   
    16.         policy->governor_data = dbs_data;  
    17.   
    18.         ......  
    19.         /* Bring kernel and HW constraints together */  
    20.         dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,  
    21.                         MIN_LATENCY_MULTIPLIER * latency);  
    22.         set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,  
    23.                                 latency * LATENCY_MULTIPLIER));  
    24.         if ((cdata->governor == GOV_CONSERVATIVE) &&  
    25.                         (!policy->governor->initialized)) {  
    26.                 struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;  
    27.   
    28.                 cpufreq_register_notifier(cs_ops->notifier_block,  
    29.                                 CPUFREQ_TRANSITION_NOTIFIER);  
    30.         }  
    31.   
    32.         if (!have_governor_per_policy())  
    33.                 cdata->gdbs_data = dbs_data;  
    34.   
    35.         return 0;  
    首 先,它会给这个policy分配一个dbs_data实例,然后把通过参数cdata传入的common_dbs_data指针,赋值给它的cdata字 段,这样,policy就可以通过该字段获得governor的操作接口(通过cdata的一系列回调函数)。然后,调用cdata的init回调函数, 对这个governor做进一步的初始化工作,对于ondemand来说,init回调的实际执行函数是:od_init,主要是完成和governor 相关的一些调节参数的初始化,然后把初始化好的od_dbs_tuners结构指针赋值到dbs_data的tuners字段中,它的详细代码这里就不贴 出了。接着,通过sysfs_create_group函数,建立该governor在sysfs中的节点,以后我们就可以通过这些节点对该 governor的算法逻辑进行微调,ondemand在我的电脑中,建立了以下这些节点(sys/devices/system/cpu /cpufreq/ondemand):

    sampling_rate;
    io_is_busy;
    up_threshold;
    sampling_down_factor;
    ignore_nice;
    powersave_bias;
    sampling_rate_min;

    继续,把初始化好的dbs_data结构赋值给policy的governor_data字段,以方便以后的访问。最后是通过 set_sampling_rate设置governor的采样周期,如果还有设置have_governor_per_policy,把 dbs_data结构指针赋值给cdata结构的gdbs_data字段,至此,governor的初始化工作完成,下面是整个过程的序列图:


                                                                                            图 3.1  governor的初始化

    4.  启动一个governor


    核心层会通过__cpufreq_set_policy函数,通过CPUFREQ_GOV_POLICY_INIT参数,在公共层的 API:cpufreq_governor_dbs中,完成了对governor的初始化工作,紧接着,__cpufreq_set_policy会通过 CPUFREQ_GOV_START参数,和初始化governor的流程一样,最终会到达cpufreq_governor_dbs函数中,我们看看它 是如何启动一个governor的:

    1. case CPUFREQ_GOV_START:  
    2.         if (!policy->cur)  
    3.                 return -EINVAL;  
    4.   
    5.         mutex_lock(&dbs_data->mutex);  
    6.   
    7.         for_each_cpu(j, policy->cpus) {  
    8.                 struct cpu_dbs_common_info *j_cdbs =  
    9.                         dbs_data->cdata->get_cpu_cdbs(j);  
    10.   
    11.                 j_cdbs->cpu = j;  
    12.                 j_cdbs->cur_policy = policy;  
    13.                 j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,  
    14.                                        &j_cdbs->prev_cpu_wall, io_busy);  
    15.                 if (ignore_nice)  
    16.                         j_cdbs->prev_cpu_nice =  
    17.                                 kcpustat_cpu(j).cpustat[CPUTIME_NICE];  
    18.   
    19.                 mutex_init(&j_cdbs->timer_mutex);  
    20.                 INIT_DEFERRABLE_WORK(&j_cdbs->work,  
    21.                                      dbs_data->cdata->gov_dbs_timer);  
    22.         }  

    首先,遍历使用该policy的所有的处于online状态的cpu,针对每一个cpu,做以下动作:
    • 取出该cpu相关联的cpu_dbs_common_info结构指针,之前已经讨论过,governor定义了一个per_cpu变量来定义各 个cpu所对应的cpu_dbs_common_info结构,通过common_dbs_data结构的回调函数可以获取该结构的指针。
    • 初 始化cpu_dbs_common_info结构的 cpu,cur_policy,prev_cpu_idle,prev_cpu_wall,prev_cpu_nice字段,其 中,prev_cpu_idle,prev_cpu_wall这两个字段会被以后的负载计算所使用。
    • 为每个cpu初始化一个工作队列, 工作队列的执行函数是common_dbs_data结构中的gov_dbs_timer字段所指向的回调函数,对于ondemand来说,该函数 是:od_dbs_timer。这个工作队列会被按照设定好的采样率定期地被唤醒,进行cpu负载的统计工作。
    然后,记录目前的时间戳,调度初始化好的工作队列在稍后某个时间点运行:
    1. /* Initiate timer time stamp */  
    2.  cpu_cdbs->time_stamp = ktime_get();  
    3.   
    4.  gov_queue_work(dbs_data, policy,  
    5.                  delay_for_sampling_rate(sampling_rate), true);  

    下图表达了启动一个governor的过程:

                                                                               图 4.1  启动一个governor

    工作队列被调度执行后,会在工作队列的执行函数中进行cpu负载的统计工作,这个我们在下一节中讨论。

    5.  系统负载的检测


    上一节我们提到,核心层启动一个governor后,会在每个使用该governor的cpu上建立一个工作队列,工作队列的执行函数是在 common_dbs_data中gov_dbs_timer字段所指向的函数,理所当然,该函数由各个governor的具体代码来实现,对于 ondemand governor,它的实现函数是od_dbs_timer。governor的公共层代码为我们提供了一个API:dbs_check_cpu,该 API用来计算两个统计周期期间某个cpu的负载情况,我们先分析一下dbs_check_cpu:

    1. void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)  
    2. {  
    3.         struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);  
    4.         ......  
    5.   
    6.         policy = cdbs->cur_policy;  
    7.   
    8.         /* Get Absolute Load (in terms of freq for ondemand gov) */  
    9.         for_each_cpu(j, policy->cpus) {  
    10.                 struct cpu_dbs_common_info *j_cdbs;  
    11.                 ......  
    12.   
    13.                 j_cdbs = dbs_data->cdata->get_cpu_cdbs(j);  
    14.   
    15.                 ......  
    16.                 cur_idle_time = get_cpu_idle_time(j, &cur_wall_time, io_busy);  
    17.   
    18.                 wall_time = (unsigned int)  
    19.                         (cur_wall_time - j_cdbs->prev_cpu_wall);  
    20.                 j_cdbs->prev_cpu_wall = cur_wall_time;  
    21.   
    22.                 idle_time = (unsigned int)  
    23.                         (cur_idle_time - j_cdbs->prev_cpu_idle);  
    24.                 j_cdbs->prev_cpu_idle = cur_idle_time;  
    25.                 ......  
    26.   
    27.                 load = 100 * (wall_time - idle_time) / wall_time;  
    28.                 ......  
    29.                 load *= cur_freq;    /* 实际的代码不是这样,为了简化讨论,精简为实际的计算逻辑*/  
    30.   
    31.                 if (load > max_load)  
    32.                         max_load = load;  
    33.         }  
    34.   
    35.         dbs_data->cdata->gov_check_cpu(cpu, max_load);  
    36. }  
    由 代码可以看出,遍历该policy下每个online的cpu,取出该cpu对应的cpu_dbs_common_info结构,该结构中的 prev_cpu_idle和prev_cpu_wall保存有上一次采样周期时记录的idle时间和运行时间,负载的计算其实很简单:
    • idle_time = 本次idle时间 - 上次idle时间;
    • wall_time = 本次总运行时间 - 上次总运行时间;
    • 负载load = 100 * (wall_time - idle_time)/ wall_time;
    • 把所有cpu中,负载最大值记入max_load中,作为选择频率的依据;
    计算出最大负载max_load后,调用具体governor实现的gov_check_cpu回调函数,对于ondemand来说,该回调函数是:od_check_cpu,我们跟进去看看:
    1. static void od_check_cpu(int cpu, unsigned int load_freq)  
    2. {  
    3.         struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);  
    4.         struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;  
    5.         struct dbs_data *dbs_data = policy->governor_data;  
    6.         struct od_dbs_tuners *od_tuners = dbs_data->tuners;  
    7.   
    8.         dbs_info->freq_lo = 0;  
    9.   
    10.         /* Check for frequency increase */  
    11.         if (load_freq > od_tuners->up_threshold * policy->cur) {  
    12.                 /* If switching to max speed, apply sampling_down_factor */  
    13.                 if (policy->cur < policy->max)  
    14.                         dbs_info->rate_mult =  
    15.                                 od_tuners->sampling_down_factor;  
    16.                 dbs_freq_increase(policy, policy->max);  
    17.                 return;  
    18.         }  
    当负载比预设的阀值高时(od_tuners->up_threshold,默认值是95%),立刻选择该policy最大的工作频率作为接下来的工作频率。如果负载没有达到预设的阀值,但是当前频率已经是最低频率了,则什么都不做,直接返回:
    1. if (policy->cur == policy->min)  
    2.         return;  
    运行到这里,cpu的频率可能已经在上面的过程中被设置为最大频率,实际上我们可能并不需要这么高的频率,所以接着判断,当负载低于另一个预设值时,这时需要计算一个合适于该负载的新频率:
    1. if (load_freq < od_tuners->adj_up_threshold  
    2.                 * policy->cur) {  
    3.         unsigned int freq_next;  
    4.         freq_next = load_freq / od_tuners->adj_up_threshold;  
    5.   
    6.         /* No longer fully busy, reset rate_mult */  
    7.         dbs_info->rate_mult = 1;  
    8.   
    9.         if (freq_next < policy->min)  
    10.                 freq_next = policy->min;  
    11.   
    12.         if (!od_tuners->powersave_bias) {  
    13.                 __cpufreq_driver_target(policy, freq_next,  
    14.                                 CPUFREQ_RELATION_L);  
    15.                 return;  
    16.         }  
    17.   
    18.         freq_next = od_ops.powersave_bias_target(policy, freq_next,  
    19.                                 CPUFREQ_RELATION_L);  
    20.         __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);  
    21. }  
    对 于ondemand来说,因为传入的负载是乘上了当前频率后的归一化值,所以计算新频率时,直接用load_freq除以想要的负载即可。本来计算出来的 频率直接通过__cpufreq_driver_target函数,交给cpufreq_driver调节频率即可,但是这里的处理考虑了 powersave_bias的设置情况,当设置了powersave_bias时,表明我们为了进一步节省电力,我们希望在计算出来的新频率的基础上, 再乘以一个powersave_bias设定的百分比,作为真正的运行频率,powersave_bias的值从0-1000,每一步代表0.1%。实际 的情况比想象中稍微复杂一点,考虑到乘以一个powersave_bias后的新频率可能不在cpu所支持的频率表中,ondemand算法会在频率表中 查找,分别找出最接近新频率的一个区间,由高低两个频率组成,低的频率记入od_cpu_dbs_info_s结构的freq_lo字段中,高的频率通过 od_ops.powersave_bias_target回调返回。同时,od_ops.powersave_bias_target回调函数还计算出 高低两个频率应该运行的时间,分别记入od_cpu_dbs_info_s结构的freq_hi_jiffies和freq_low_jiffies字段 中。原则是,通过两个不同频率的运行时间的组合,使得综合结果接近我们想要的目标频率。详细的计算逻辑请参考函 数:generic_powersave_bias_target。
    讨论完上面两个函数,让我们回到本节的开头,负载的计算工作是在一个工作队列中发起的,前面说过,ondemand对应的工作队列的工作函数是od_dbs_timer,我们看看他的实现代码:
    1. static void od_dbs_timer(struct work_struct *work)  
    2. {  
    3.         ......  
    4.   
    5.         /* Common NORMAL_SAMPLE setup */  
    6.         core_dbs_info->sample_type = OD_NORMAL_SAMPLE;  
    7.         if (sample_type == OD_SUB_SAMPLE) {  
    8.                 delay = core_dbs_info->freq_lo_jiffies;  
    9.                 __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,  
    10.                                 core_dbs_info->freq_lo, CPUFREQ_RELATION_H);  
    11.         } else {  
    12.                 dbs_check_cpu(dbs_data, cpu);  
    13.                 if (core_dbs_info->freq_lo) {  
    14.                         /* Setup timer for SUB_SAMPLE */  
    15.                         core_dbs_info->sample_type = OD_SUB_SAMPLE;  
    16.                         delay = core_dbs_info->freq_hi_jiffies;  
    17.                 }  
    18.         }  
    19.   
    20. max_delay:  
    21.         if (!delay)  
    22.                 delay = delay_for_sampling_rate(od_tuners->sampling_rate  
    23.                                 * core_dbs_info->rate_mult);  
    24.   
    25.         gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);  
    26.         mutex_unlock(&core_dbs_info->cdbs.timer_mutex);  
    27. }  
    如 果sample_type是OD_SUB_SAMPLE时,表明上一次采样时,需要用高低两个频率来模拟实际的目标频率中的第二步:需要运行 freq_lo,并且持续时间为freq_lo_jiffies。否则,调用公共层计算负载的API:dbs_check_cpu,开始一次新的采样,当 powersave_bias没有设置时,该函数返回前,所需要的新的目标频率会被设置,考虑到powersave_bias的设置情况,判断一下如果 freq_lo被设置,说明需要用高低两个频率来模拟实际的目标频率,高频率已经在dbs_check_cpu返回前被设置(实际的设置工作是在 od_check_cpu中),所以把sample_type设置为OD_SUB_SAMPLE,以便下一次运行工作函数进行采样时可以设置低频率运行。 最后,调度工作队列在下一个采样时刻再次运行,这样,cpu的工作频率实现了在每个采样周期,根据实际的负载情况,动态地设定合适的工作频率进行运行,既 满足了性能的需求,也降低了系统的功耗,达到了cpufreq系统的最终目的,整个流程可以参考下图:

                                                                                      图 5.1  负载计算和频率选择

    展开全文
  • 本文主要讲述cpufreq动态频率调节系统,详细讲到了相关设置流程及原理,最后以编译系统apk的形式实现cpu的定频处理功能
  • Linux动态频率调节系统CPUFreq之二:核心(core)架构与API 转载 目录(?)[+] 上一节中,我们大致地讲解了一下CPUFreq在用户空间的sysfs接口和它的几个重要的数据结构,同时也提到,CPUFreq子系统...
  • 1、N频点TD-SCDMA系统中同频干扰问题  TD-SCDMA系统正在走向商用,并在多个城市组网测试,TD-SCDMA系统引入的...N频点小区实际是一个逻辑小区,但在无线资源上多了一维频率参数,在增加无线资源管理(RRM)灵活性的同
  • 文章目录基本理解cpufreq深入探究cpufreq2. 软件架构3. cpufreq_policy4. cpufreq_governor5. cpufreq_driver6. cpufreq notifiers核心(core)架构与API1. CPUFreq子系统的初始化2... 为每个cpu建立频率调整策略(p...
  • OS: Android 7.1 Board: Firefly-RK3399 Kernel: v4.4.55 ...devfreq 是内核开发者定义的一套支持动态调整设备频率和电压的的框架模型。它能有效的降 低该设备的功耗,同时兼顾其性能。 devf...
  • 概述在Linux中,内核提供了一套框架模型来完成CPU频率动态调节,以达到省电的目的。 这就是所谓的CPUFreq系统。1. sysfs接口我们先从CPUFreq提供的sysfs接口入手,直观地看看它提供了那些功能。以下是我的电脑...
  • 为了节省CPU的功耗和减少发热,我们有必要根据当前CPU的负载状态,动态地提供刚好足够的主频给CPU。在Linux中,内核的开发者定义了一套框架模型来完成这一目的,它就是CPUFreq系统。 /*****************************...

空空如也

空空如也

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

动态频率