网站改版建设公司电商网站建设公司哪家好

当前位置: 首页 > news >正文

网站改版建设公司,电商网站建设公司哪家好,包装纸箱公司怎么做网站,网站建设成本注#xff1a;本文缩写说明 一、CFS组调度简介 1.1. 存在的原因 总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢#xff0c;比如多用户计算机系统每个用户的所有任务划分到一个分组中#xff0c;A用户90个相同任务#xff0c;而B…注本文缩写说明 一、CFS组调度简介 1.1. 存在的原因 总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢比如多用户计算机系统每个用户的所有任务划分到一个分组中A用户90个相同任务而B用户只有10个相同任务在CPU完全跑满的情况下那么A用户将占90%的CPU时间而B用户只占到了10%的CPU时间这对B用户显然是不公平的。再或者同一个用户既想-j64快速编译又不想被编译任务影响使用体验也可将编译任务设置到对应分组中限制其CPU资源。 1.2. 手机设备上的分组状态 /dev/cpuctl 目录使用struct task_group root_task_group 表示。其下的每一层级的子目录都抽象为一个task_group结构。有几个需要注意的点 根组下的cpu.shares 文件默认值是1024而且不支持设置。根组的负载也不会更新。根组也是一个task group根组下的任务也是被分过组的不会再属于其它组。内核线程默认在根组下其直接从根cfs_rq上分配时间片有非常大的优势若是其一直跑那在trace上看就几乎就是”一直跑”比如常见的kswapd内核线程。默认cpu.shares配置下若全是nice0的任务且只考虑单核的情况下根组下的每个任务在完全满载情况下能得到的时间片等于其它分组下所有任务能分配到的时间片的总和。 注意task和task group都是通过权重来分配时间片的但是task的权重来自其优先级而task group的权重则来自与其cgroup目录下cpu.shares文件设置的值。使能组调度后看任务分得的时间片就不能单看其prio对应的权重了还要看其task group分得的权重和本group中其它任务的运行情况。 二、任务的task group分组 CFS组调度功能主要是通过对任务进行分组体现出来的一个分组由一个struct task_group来表示。 2.1. 如何设置分组 task group分组配置接口由cpu cgroup子系统通过cgroup目录层次结构导出到用户空间。 如何从task group中移除一个任务呢没有办法直接移除的在cgroup语义下一个任务某一时刻必须属于一个task group只有通过将其echo到其它分组中才能将其从当前分组中移除。 2.2. Android中如何设置分组 Process.java中向其它模块提供 setProcessGroup(int pid, int group) 将pid进程设置进group参数指定的分组中供其它模块进行调用设置。比如OomAdjuster.java 中将任务切前/后台分别调用传参groupTHREAD_GROUP_TOP_APP/THREAD_GROUP_BACKGROUND。 libprocessgroup 中提供了一个名为 task_profiles.json 的配置文件它里面 AggregateProfiles 聚合属性字段配置了上层设置下来后的对应的行为。比如 THREAD_GROUP_TOP_APP 对应的聚合属性为 SCHED_SP_TOP_APP其中的MaxPerformance属性对应的行为就是加入到cpu top-app分组。 ”MaxPerformance”属性的配置可读性非常强可以看出是加入到cpu子系统的top-app分组中。 2.3. Android中设置为TOP-APP分组对cgroup设置了什么 因为有多个cgroup子系统除了我们正在讲的CFS组调度依附的cpu cgroup子系统外还有cpuset cgroup子系统(限制任务可运行的CPU和可使用的内存节点)blkio cgroup子系统(限制进程的块设备io)freezer cgroup子系统(提供进程冻结功能)等。上层配置分组下来可能不只切一个cgroup具体切了哪些子系统体现在集合属性 AggregateProfiles 的数组成员上比如上例中另外两个属性对应的行为分别是加入blkio子系统的根组和将任务的timer_slack_ns(一个平衡hrtimer定时唤醒及时性与功耗的参数)设置为50000ns。 2.4. 服务启动后就放在指定分组 在启动服务的时候使用 taskprofiles进行配置举例。 资料直通车Linux内核源码技术学习路线视频教程内核源码 学习直通车Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈 三、内核实现概述 上面我们讨论了对task group分组的配置本节开始将进入到内核中了解其实现。 3.1. 相关功能依赖关系 内核相关CONFIG依赖如下 图1: CGROUP提供cgroup目录层次结构的功能CGROUP_SCHED提供cpu cgroup目录层次结构如 /dev/cpuctl/top-app并为每个cpu cgroup目录提供task group的概念FAIR_GROUP_SCHED基于cpu cgroup提供的task group提供CFS任务组调度功能。图1中灰色的虚线框图是Android手机内核中默认不使能的。 3.2. task group数据结构框图 如下图2所示展示了一个task group在内核中维护的主要数据结构的框图对照着图下面概念更容易理解 由于不能确定一个分组内的任务跑在哪个CPU上因此一个task group在每个CPU上都维护了一个group cfs_rq由于task group也要参与调度(要先选中task group才能选中其group cfs_rq上的任务) 因此在每个CPU上也都维护了一个group se。task se的my_q成员为NULL而group se的my_q成员指向其对应的group cfs_rq其分组在本CPU上的就绪任务就挂在这个group cfs_rq上。task group可以嵌套由 parent/siblings/children 成员构成一个倒立树状层次结构根task group的parent指向NULL。所有CPU的根cfs_rq属于root task group。 图2: 注画图比较麻烦此图是借鉴蜗窝的。 四、相关结构体 4.1. struct task_group 一个 struct task_group 就表示一个cpu cgroup分组。在使能FAIR_GROUP_SCHED的情况下一个 struct task_group 就表示CFS组调度中的一个任务组。 css: 该task group对应的cgroup状态信息通过它依附到cgroup目录层次结构中。 se: group se是个数组指针数组大小为CPU的个数。因为一个task group中有多个任务且可以跑在所有CPU上因此需要每个CPU上都要有本task group的一个 se。 cfs_rq: group se的cfs_rq, 是本task group的在各个CPU上的cfs_rq也是个数组指针数组大小为CPU的个数。当本task group的任务就绪后就挂在这个cfs_rq上。它在各个CPU上对应的指针和task group在各个CPU上的se-my_q具有相同指向见 init_tg_cfs_entry(). shares: task group的权重默认为scale_up(1024)。和task se的权重类似值越大task group能获取的CPU时间片就越多。但是和task 不同的是task group 在每个CPU上都有一个group se因此需要按照一定规则分配给各CPU上的group se, 下面会讲解分配规则。 load_avg: 此task group的负载而且只是一个load_avg 变量(不像se和cfs_rq是一个结构)下面会对其进行讲解。注意它不是per-cpu的此task group的任务在各个CPU上进行更新时都会更新它因此需要注意对性能的影响。 parent/siblings/children: 构成task group的层次结构。 内核中有个全局变量 struct task_group root_task_group, 表示根组。其cfs_rq[]就是各个cpu的cfs_rq, 其se[]都为NULL。其权重不允许被设置见 sched_group_set_shares()。负载也不会被更新见 update_tg_load_avg()。 系统中的所有task group 结构都会被添加到task_groups链表上在CFS带宽控制时使用。 初学者可能会混淆组调度和调度组这两个概念以及 struct task_group 与struct sched_group 的区别。组调度对应struct task_group用来描述一组任务主要用于util uclamp(对一组任务的算力需求进行钳制)和CPU资源使用限制也是本文中要讲解的内容。调度组对应 struct sched_group是CPU拓扑结构sched_domain中的概念用来描述一个CPU(MC层级)/Cluster(DIE层级)的属性主要用于选核和负载均衡。 4.2. struct sched_entity 一个sched_entity 既可以表示一个task se, 又可以表示一个group se。下面主要介绍使能组调度后新增的一些成员。 load: 表示se的权重对于gse, 新建时初始化为NICE_0_LOAD, 见init_tg_cfs_entry()。 depth: 表示task group的嵌套深度根组下的se的深度为0每嵌套深一层就加1。比如/dev/cpuctl目录下有个tg1目录tg1目录下又有一个tg2目录tg1对应的group se的深度为0tg1下的task se的深度是1tg2下的task se的深度是2。更新位置见 init_tg_cfs_entry()/attach_entity_cfs_rq()。 parent: 指向父se节点, 父子se节点都是对应同一cpu的。根组下任务的指向为NULL。 cfs_rq: 该se挂载到的cfs_rq。对于根组下的任务指向rq的cfs_rq非根组的任务指向其parent-my_rq见init_tg_cfs_entry()。 my_q: 该se的cfs_rq, 只有group se才有cfs_rqtask se的为NULLentity_is_task()宏通过这个成员来判断是task se还是group se。 runnable_weight: 缓存 gse-my_q-h_nr_running 的值在计算gse的runnable负载时使用。 avg: se的负载对于tse会初始化为其权重(创建时假设其负载很高)而gse则会初始化为0见init_entity_runnable_average()。task se的和group se的有一定区别下面第五章会进行讲解。 4.3. struct cfs_rq struct cfs_rq 既可以表示per-cpu的CFS就绪队列又可以用来表示gse的my_q队列。下面列出对组调度比较关键的一些成员进行讲解。 load: 表示cfs_rq的权重无论是根cfs_rq还是grq这里的权重都等于其队列上挂的所有任务的权重之和。 nr_running: 当前层级下 task se 和 group se的个数和。 h_nr_running: 当前层级以及所有子层级下task se的个数和不包括group se。 avg: cfs_rq的负载。下面将对比task se、group se、cfs_rq讲解负载。 removed: 当一个任务退出或者唤醒后迁移到到其他cpu上的时候原来CPU的cfs rq上需要移除该任务带来的负载。这个移除动作会先把移除的负载记录在这个removed成员中在下次调用update_cfs_rq_load_avg()更新cfs_rq负载时再移除。nr表示要移除的se的个数_avg则表示要移除的各类负载之和。 tg_load_avg_contrib: 是对 grq-avg.load_avg 的一个缓存表示当前grq的load负载对tg的贡献值。用于在更新 tg-load_avg 的同时降低对 tg-load_avg 的访问次数。在计算gse从tg分得的权重配额时的近似算法中也有用到见 calc_group_shares()/update_tg_load_avg()。 propagate: 标记是否有负载需要向上层传播。下面7.3节会进行讲解。 prop_runnable_sum: 在负载沿着task group层级结构向上层传播的时候表示要上传的tse/gse的load_sum值。 h_load: 层次负载hierarchy load表示本层cfs_rq的load_avg对CPU的load_avg的贡献值主要在负载均衡路径中使用。下面会对其进行讲解。 last_h_load_update: 表示上一次更新h_load的时间点(单位jiffies)。 h_load_next: 指向子gse为了获取任务的hierarchy loadtask_h_load函数需要从顶层cfs向下依次更新各个level的cfs rq的h_load。因此这里的h_load_next就是为了形成一个从顶层cfs rq到底层cfs rq的cfs rq–se–cfs rq–se的关系链。 rq: 使能组调度后才加的这个成员若没有使能组调度的话cfs_rq就是rq的一个成员使用 container_of进行路由使能组调度后增加了一个rq成员进行cfs_rq到rq的路由。 on_list/leaf_cfs_rq_list: 尝试将叶cfs_rq串联起来在CFS负载均衡和带宽控制相关逻辑中使用。 tg: 该cfs_rq隶属的task group。 五、task group权重 task group的权重使用struct task_group 的 shares 成员来表示默认值是scale_load(1024)。可以通过cgroup目录下的cpu.shares文件进行读写echo weight cpu.shares 就是将task group权重配置为weight保存到shares 成员变量中的值是scale_load(weight)。root_task_group不支持设置权重。 不同task group的权重大小表示系统CPU跑满后哪个task group组可以跑多一些哪个task group组要跑的少一些。 5.1. gse的权重 task group在每个CPU上都有一个group se那么就需要将task group的权重 tg-shares 按照一定的规则分配到各个gse上。规则就是公式(1)

  • tg-weight * grq-load.weight* ge-load.weight —————————————– (1)* \Sum grq-load.weight 其中 tg-weight 就是tg-shares, grq-load.weight 表示tg在各个CPU上的grq的权重。也就是每个gse根据其cfs_rq的权重比例来分配tg的权重。cfs_rq的权重等于其上挂载的任务的权重之和。假设tg的权重是1024系统中只有2个CPU因此有两个gse, 若其grq上任务状态如下如下图3则gse[0]分得的权重为 1024 * (102420483072)/(10242048307210241024) 768gse[1]分得的权重为 1024 * (10241024)/(10242048307210241024) 256。 图3: gse的权重更新函数为 update_cfs_group()下面看其具体实现: tg的权重向gse[X]的分配动作是在 calc_group_shares() 中完成的。 公式(1)中使用到 \Sum grq-load.weight也就是说一个gse权重的更新需要访问各个CPU上的grq锁竞争代价比较高因此进行了一系列的近似计算。 首先进行替换
  • grq-load.weight – grq-avg.load_avg (2) 然后得到
  • tg-weight * grq-avg.load_avg* ge-load.weight —————————————- (3)* tg-load_avg** Where: tg-load_avg ~ \Sum grq-avg.load_avg 由于cfs_rq-avg.load_avg cfs_rq-avg.load_sum/divider。而 cfs_rq-avg.load_sum 等于 cfs_rq-load.weight 乘以非idle状态下的几何级数。这个近似是在tg的每个CPU上的grq的非idle状态的时间级数是相同的前提下才严格相等的。也就是说tg的任务在各个CPU上的运行状态越一致越接近这个近似值。 task group 空闲的情况下启动一个任务。grq-avg.load_avg 需要时间来建立在建立时间这种特殊情况下公式1简化为
  • tg-weight * grq-load.weight* ge-load.weight ————————————— tg-weight (4)* grp-load.weight 相当于一个单核系统下的状态了。为了让公式(3)在这种特殊情况下更贴近与公式(4)又做了一次近似得到
  • tg-weight * grq-load.weight* ge-load.weight ——————————————————————– (5)* tg-load_avg - grq-avg.load_avg grq-load.weight 但是因为grq上没有任务时grq-load.weight 可以下降到 0导致除以零需要使用 grq-avg.load_avg作为它的下限然后给出
  • tg-weight * grq-load.weight* ge-load.weight —————————————— (6)* tg_load_avg** 其中:* tg_load_avg tg-load_avg - grq-avg.load_avg max(grq-load.weight, grq-avg.load_avg) max(grq-load.weight, grq-avg.load_avg) 一般都是取grq-load.weight因为只有grq上一直有任务runningrunnable才会趋近于grq-load.weight。 calc_group_shares() 函数是通过公式(6)近似计算各个gse分得的权重 由于tg中的每个任务都对gse的权重有贡献因此grq上任务个数变更时都要更新gse的权重近似过程中使用到了se的负载在entity_tick()中也进行了一次更新。调用路径 5.2. gse上每个tse分到的权重 任务组中的任务也是按其权重比例分配gse的权重。如上图2中gse[0]的grq上挂的3个任务tse1分得的权重就是7681024/(102420483072)128, tse2分得的权重就是7682048/(102420483072)256, tse3分得的权重就是768*3072/(102420483072)384。 在tg中的任务分配tg分得的时间片的时候会使用到这个按比例分得的权重。分组嵌套的越深能按比例分得的权重就越小由此可见在高负载时task group中的任务是不利于分配时间片的。 文章篇幅过长下文继续讲解