linux内核死锁检测机制 | oenhan,Linux内核CPU负载均衡机制 | OenHan

还是神奇的进程调度问题引发的,参看Linux进程组调度机制分析,组调度机制是看清楚了,发现在重启过程中,很多内核调用栈阻塞在了double_rq_lock函数上,而double_rq_lock则是load_balance触发的,怀疑当时的核间调度出现了问题,在某个负责场景下产生了多核互锁,后面看了一下CPU负载平衡下的代码实现,写一下总结。

内核代码版本:kernel-3.0.13-0.27。

内核代码函数起自load_balance函数,从load_balance函数看引用它的函数可以一直找到schedule函数这里,便从这里开始往下看,在__schedule中有下面一句话。

1

2if (unlikely(!rq->nr_running))

idle_balance(cpu, rq);

从上面可以看出什么时候内核会尝试进行CPU负载平衡:即当前CPU运行队列为NULL的时候。

CPU负载平衡有两种方式:pull和push,即空闲CPU从其他忙的CPU队列中拉一个进程到当前CPU队列;或者忙的CPU队列将一个进程推送到空闲的CPU队列中。idle_balance干的则是pull的事情,具体push下面会提到。

在idle_balance里面,有一个proc阀门控制当前CPU是否pull:

1

2if (this_rq->avg_idle < sysctl_sched_migration_cost)

return;

sysctl_sched_migration_cost对应proc控制文件是/proc/sys/kernel/sched_migration_cost,开关代表如果CPU队列空闲了500ms(sysctl_sched_migration_cost默认值)以上,则进行pull,否则则返回。

for_each_domain(this_cpu, sd) 则是遍历当前CPU所在的调度域,可以直观的理解成一个CPU组,类似task_group,核间平衡指组内的平衡。负载平衡有一个矛盾就是:负载平衡的频度和CPU cache的命中率是矛盾的,CPU调度域就是将各个CPU分成层次不同的组,低层次搞定的平衡就绝不上升到高层次处理,避免影响cache的命中率。

图例如下;

45295758_1.jpg

最终通过load_balance进入正题。

首先通过find_busiest_group获取当前调度域中的最忙的调度组,首先update_sd_lb_stats更新sd的状态,也就是遍历对应的sd,将sds里面的结构体数据填满,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22struct sd_lb_stats {

struct sched_group *busiest;/* Busiest group in this sd */

struct sched_group *this;/* Local group in this sd */

unsignedlong total_load;/* Total load of all groups in sd */

unsignedlong total_pwr;/*   Total power of all groups in sd */

unsignedlong avg_load;/* Average load across all groups in sd */

/** Statistics of this group */

unsignedlong this_load;//当前调度组的负载

unsignedlong this_load_per_task;//当前调度组的平均负载

unsignedlong this_nr_running;//当前调度组内运行队列中进程的总数

unsignedlong this_has_capacity;

unsignedint  this_idle_cpus;

/* Statistics of the busiest group */

unsignedint  busiest_idle_cpus;

unsignedlong max_load;//最忙的组的负载量

unsignedlong busiest_load_per_task;//最忙的组中平均每个任务的负载量

unsignedlong busiest_nr_running;//最忙的组中所有运行队列中进程的个数

unsignedlong busiest_group_capacity;

unsignedlong busiest_has_capacity;

unsignedint  busiest_group_weight;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26do

{

local_group = cpumask_test_cpu(this_cpu, sched_group_cpus(sg));

if (local_group) {

//如果是当前CPU上的group,则进行赋值

sds->this_load = sgs.avg_load;

sds->this = sg;

sds->this_nr_running = sgs.sum_nr_running;

sds->this_load_per_task = sgs.sum_weighted_load;

sds->this_has_capacity = sgs.group_has_capacity;

sds->this_idle_cpus = sgs.idle_cpus;

}else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {

//在update_sd_pick_busiest判断当前sgs的是否超过了之前的最大值,如果是

//则将sgs值赋给sds

sds->max_load = sgs.avg_load;

sds->busiest = sg;

sds->busiest_nr_running = sgs.sum_nr_running;

sds->busiest_idle_cpus = sgs.idle_cpus;

sds->busiest_group_capacity = sgs.group_capacity;

sds->busiest_load_per_task = sgs.sum_weighted_load;

sds->busiest_has_capacity = sgs.group_has_capacity;

sds->busiest_group_weight = sgs.group_weight;

sds->group_imb = sgs.group_imb;

}

sg = sg->next;

}while (sg != sd->groups);

决定选择调度域中最忙的组的参照标准是该组内所有 CPU上负载(load) 的和, 找到组中找到忙的运行队列的参照标准是该CPU运行队列的长度, 即负载,并且 load 值越大就表示越忙。在平衡的过程中,通过比较当前队列与以前记录的busiest 的负载情况,及时更新这些变量,让 busiest 始终指向域内最忙的一组,以便于查找。

调度域的平均负载计算

1

2

3sds.avg_load = (SCHED_POWER_SCALE * sds.total_load) / sds.total_pwr;

if (sds.this_load >= sds.avg_load)

goto out_balanced;

在比较负载大小的过程中, 当发现当前运行的CPU所在的组中busiest为空时,或者当前正在运行的 CPU队列就是最忙的时, 或者当前 CPU队列的负载不小于本组内的平均负载时,或者不平衡的额度不大时,都会返回 NULL 值,即组组之间不需要进行平衡;当最忙的组的负载小于该调度域的平均负载时,只需要进行小范围的负载平衡;当要转移的任务量小于每个进程的平均负载时,如此便拿到了最忙的调度组。

然后find_busiest_queue中找到最忙的调度队列,遍历该组中的所有 CPU 队列,经过依次比较各个队列的负载,找到最忙的那个队列。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31for_each_cpu(i, sched_group_cpus(group)) {

/*rq->cpu_power表示所在处理器的计算能力,在函式sched_init初始化时,会把这值设定为SCHED_LOAD_SCALE (=Nice 0的Load Weight=1024).并可透过函式update_cpu_power (in kernel/sched_fair.c)更新这个值.*/

unsignedlong power = power_of(i);

unsignedlong capacity = DIV_ROUND_CLOSEST(power,SCHED_POWER_SCALE);

unsignedlong wl;

if (!cpumask_test_cpu(i, cpus))

continue;

rq = cpu_rq(i);

/*获取队列负载cpu_rq(cpu)->load.weight;*/

wl = weighted_cpuload(i);

/*

* When comparing with imbalance, use weighted_cpuload()

* which is not scaled with the cpu power.

*/

if (capacity && rq->nr_running == 1 && wl > imbalance)

continue;

/*

* For the load comparisons with the other cpu's, consider

* the weighted_cpuload() scaled with the cpu power, so that

* the load can be moved away from the cpu that is potentially

* running at a lower capacity.

*/

wl = (wl * SCHED_POWER_SCALE) / power;

if (wl > max_load) {

max_load = wl;

busiest = rq;

}

通过上面的计算,便拿到了最忙队列。

当busiest->nr_running运行数大于1的时候,进行pull操作,pull前对move_tasks,先进行double_rq_lock加锁处理。

1

2

3

4double_rq_lock(this_rq, busiest);

ld_moved = move_tasks(this_rq, this_cpu, busiest,

imbalance, sd, idle, &all_pinned);

double_rq_unlock(this_rq, busiest);

move_tasks进程pull task是允许失败的,即move_tasks->balance_tasks,在此处,有sysctl_sched_nr_migrate开关控制进程迁移个数,对应proc的是/proc/sys/kernel/sched_nr_migrate。

下面有can_migrate_task函数检查选定的进程是否可以进行迁移,迁移失败的原因有3个,1.迁移的进程处于运行状态;2.进程被绑核了,不能迁移到目标CPU上;3.进程的cache仍然是hot,此处也是为了保证cache命中率。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17/*关于cache cold的情况下,如果迁移失败的个数太多,仍然进行迁移

* Aggressive migration if:

* 1) task is cache cold, or

* 2) too many balance attempts have failed.

*/

tsk_cache_hot = task_hot(p, rq->clock_task, sd);

if (!tsk_cache_hot ||

sd->nr_balance_failed > sd->cache_nice_tries) {

#ifdef CONFIG_SCHEDSTATS

if (tsk_cache_hot) {

schedstat_inc(sd, lb_hot_gained[idle]);

schedstat_inc(p, se.statistics.nr_forced_migrations);

}

#endif

return 1;

}

判断进程cache是否有效,判断条件,进程的运行的时间大于proc控制开关sysctl_sched_migration_cost,对应目录/proc/sys/kernel/sched_migration_cost_ns

1

2

3

4

5

6

7static int

task_hot(struct task_struct *p, u64 now,struct sched_domain *sd)

{

s64 delta;

delta = now - p->se.exec_start;

return delta < (s64)sysctl_sched_migration_cost;

}

在load_balance中,move_tasks返回失败也就是ld_moved==0,其中sd->nr_balance_failed++对应can_migrate_task中的"too many balance attempts have failed",然后busiest->active_balance = 1设置,active_balance = 1。

1

2

3

4

5if (active_balance)

//如果pull失败了,开始触发push操作

stop_one_cpu_nowait(cpu_of(busiest),

active_load_balance_cpu_stop, busiest,

&busiest->active_balance_work);

push整个触发操作代码机制比较绕,stop_one_cpu_nowait把active_load_balance_cpu_stop添加到cpu_stopper每CPU变量的任务队列里面,如下:

1

2

3

4

5

6void stop_one_cpu_nowait(unsignedint cpu, cpu_stop_fn_t fn,void *arg,

struct cpu_stop_work *work_buf)

{

*work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, };

cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf);

}

而cpu_stopper则是cpu_stop_init函数通过cpu_stop_cpu_callback创建的migration内核线程,触发任务队列调度。因为migration内核线程是绑定每个核心上的,进程迁移失败的1和3问题就可以通过push解决。active_load_balance_cpu_stop则调用move_one_task函数迁移指定的进程。

上面描述的则是整个pull和push的过程,需要补充的pull触发除了schedule后触发,还有scheduler_tick通过触发中断,调用run_rebalance_domains再调用rebalance_domains触发,不再细数。

1

2

3

4void __init sched_init(void)

{

open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558028.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux下IPROTO_TCP,TCP/IP协议栈在Linux内核中的运行时序分析

可选题目三&#xff1a;TCP/IP协议栈在Linux内核中的运行时序分析在深入理解Linux内核任务调度(中断处理、softirg、tasklet、wq、内核线程等)机制的基础上&#xff0c;分析梳理send和recv过程中TCP/IP协议栈相关的运行任务实体及相互协作的时序分析。编译、部署、运行、测评、…

vs2019Linux守护,Visual Studio 2019将支援Ninja显着提升Linux专案建置效率

微软更新Visual Studio 2019&#xff0c;新增多个可提升Linux开发体验的功能&#xff0c;包括在Linux上支援建置系统Ninja&#xff0c;以及更完整地支援gdbserver&#xff0c;而且现在开发者也可以使用连接管理器(Connection Manager)&#xff0c;编辑和配置预设的远端连接。使…

c语言程序中必不可少的,C语言程序设计(第3章程序控制语句)2

3.2 数据的输入与输出在程序的运行过程中&#xff0c;往往需要由用户输入一些数据&#xff0c;而程序运算所得到的计算结果等又需要输出给用户&#xff0c;由此实现人与计算机之间的交互&#xff0c;所以在程序设计中&#xff0c;输入输出语句是一类必不可少的重要语句&#xf…

android 九宫格封装,Android 九宫格布局

演示image需求满足0-9个图的适配图数量演示1image2image3image4image5image6image7image8image9image使用手动设置android:layout_width"match_parent"android:layout_height"wrap_content"app:ngl_gridSpace"10dp"app:ngl_oneChildHeight"…

android放大镜无广告,Android放大镜的实现代码

快三个月了没写博客了&#xff0c;因为工作调动&#xff0c;很多经验、心得都没有时间记录下来。现在时间稍微充裕了点&#xff0c;我会尽量抽时间将之前想写而没写的东西补上。进入正题。去年某个时候&#xff0c;我偶然看到一篇文章&#xff0c;讲android里面放大镜的实现。文…

鸿蒙和宙斯谁厉害,漫威宇宙宙斯vs奥丁,到底谁更强

宙斯在漫威里&#xff0c;是希腊神话中的众神之王&#xff0c;奥林匹斯十二主神之一&#xff0c;也是奥林匹斯大部分神和神奇女侠戴安娜的父亲&#xff0c;同时也是沙赞的力量来源之一能力&#xff1a;不朽(只有宙斯的血能杀死宙斯)宙斯神力雷霆之怒控制天气宙斯的力量并不是某…

背计算机专业英语词汇,计算机专业英语词汇1500词(五)

201. exit n. & vi. 出口&#xff1b;退出202. report vt. & n. 报告&#xff0c;报表203. execution n. 执行204. backup n. 备份&#xff0c;后备&#xff0c;后援205. version n. 版本206. find v. 寻找&#xff0c;发现207. pointer n. 指针&#xff0c;指示字208.…

优考试在线考试系统计算机,使用优考试在线考试系统解决企业员工考核评比

随着信息时代的高速发展&#xff0c;很多实体传统的东西已经慢慢搬到网络上了&#xff0c;在线考试就是在其中发展的很迅速的一种&#xff0c;企业的员工考核、员工的培训、评比都可以使用企业在线考试系统来解决了&#xff0c;电脑微信小程序手机考试相结合&#xff0c;让考试…

计算机专业申请phd美国,美国计算机专业博士的申请个人陈述范文

美国计算机专业博士的申请个人陈述范文2020-08-24 618人阅读摘要:美国计算机专业博士的申请个人陈述范文美国计算机专业博士申请个人陈述范文共享&#xff0c;公文个人陈述是美国博士申请公文中非常关键的构成部分&#xff0c;针对计划申请办理美国计算机专业博士研究生的同学们…

计算机桌面壁纸怎样拉伸,win10桌面壁纸怎么拉伸?手把手教你拉伸win10桌面壁纸的方法...

现在大家喜欢用自己拍摄的照片做电脑桌面壁纸&#xff0c;设置好win10桌面壁纸后&#xff0c;总感觉壁纸很显大&#xff0c;想要重新拉伸一下。那么win10桌面壁纸如何拉伸&#xff1f;针对此疑问&#xff0c;小编手把手教你拉伸win10桌面壁纸的方法。1、首先来看一下原因&#…

html+dom+深入,DOM 深入学习 - 1

本文章记录本人在深入学习Javascirpt DOM中看书理解到的一些东西&#xff0c;加深记忆和并且整理记录下来&#xff0c;方便之后的复习。DOM 版本w3c 指定的DOM规范包括多个版本&#xff0c;不同的版本(或称知为级别)又包含不同的子规法和模块&#xff0c;不同浏览器对DOM的支持…

计算机应用常用的30个函数,Excel中常用函数的使用

&#xff29;&#xff33;&#xff33;&#xff2e;&#xff11;&#xff10;&#xff10;&#xff19;—&#xff13;&#xff10;“咖船&#xff52;&#xff2b;&#xff4e;&#xff4f;别&#xff42;内&#xff45;&#xff41;&#xff4e;&#xff44;伯叻肋叻电奠知识…

cam350怎么看顶层_厉害的人是怎么分析问题的?(实操干货)

“经常做一个方案&#xff0c;几十页PPT还没把问题讲清楚&#xff0c;老板一个问题就貌似发现了关键&#xff0c;这到底是一种怎么样的思维方式&#xff1f;”我在职场这么多年&#xff0c;也遇到过很多次这样的问题。在我初入职场时&#xff0c;经领导点拨后&#xff0c;也产生…

抓球球的机器人应该怎么玩_王者荣耀:在游戏中当自己优势队友劣势的时候应该怎么玩?...

游戏里时常会有这么一种情况出现&#xff0c;我们疯狂Carry&#xff0c;一看战绩十几杠几&#xff0c;C得不行&#xff0c;但是队伍就是要输&#xff0c;颓势总是无法挽回。今天我就给大家说一下&#xff0c;是什么样的原因导致这种情况的发生。队友劣势的原因分析&#xff1a;…

ajax获得excel文件流在前端打开_主流前端技术讲解,面试必考!

Vue.js是Web前端的一个框架&#xff0c;用来快速开发单页面应用。当Vue.js开发变成主流的时候&#xff0c;许多公司的技术团队都打算把下一个新项目换成用Vue.js来开发。但是当我们详细了解Vue.js以后&#xff0c;会发现一个很尴尬的问题&#xff0c;那就是Vue.js的页面是采用客…

计算机无法用telnet,telnet不是内部或外部命令解决办法 Windows10开启Telnet功能方法...

一般情况下&#xff0c;Windows10正式版系统的telnet服务都是处于关闭状态的&#xff0c;需要我们手动开启才可以。telnet服务可以调试端口&#xff0c;其重要性不容小视。今天&#xff0c;就告诉教大家Windows如何配置telnet服务&#xff1f;虽然说今天以Windows10来示例&…

计算机主板另一个名称,主板名称太复杂 看这几点就秒懂了

现在的主板厂商特看重个性化和市场细分&#xff0c;恨不得给每个人定制最适合的主板&#xff0c;所以主板型号多到爆&#xff0c;名称还都特别长&#xff0c;看得人眼晕还看不懂。其实这些名字虽然拉拉杂杂一长串&#xff0c;但都带有很好理解的“关键词”&#xff0c;只要扫一…

亚马逊产品描述计算机语言编辑,亚马逊Listing产品描述编辑讲解

烂人的虚伪我从头看到尾优质答主01-24TA获得超过2782个赞自建listing&#xff0c;就是根据自己的产品&#xff0c;自己打造产品客户端的展示内容&#xff0c;让顾客了解自己的产品&#xff0c;有下单的欲望&#xff01;建好如果效果不好&#xff0c;还要进行优化&#xff0c;最…

计算机的硬盘 内存在哪查到,电脑硬盘内存怎么查看

电脑硬盘内存怎么查看在我们买电脑的时候我们一般都会选择去看看电脑硬盘内存的大小。那么电脑硬盘内存怎么查看呢?下面就由jy135小编来告诉大家吧&#xff0c;欢迎阅读。方法一、在电脑系统中查看1、这里以 Windows7 系统为例&#xff0c;选中桌面的“计算机”图标&#xff0…

linux messages 时间错乱_BATJ 常考的 21 条 Linux 命令,速度收藏!

来源: http://t.cn/EqTIhES一、文件和目录1. cd命令(它用于切换当前目录&#xff0c;它的参数是要切换到的目录的路径&#xff0c;可以是绝对路径&#xff0c;也可以是相对路径)cd /home 进入 / home 目录cd .. 返回上一级目录 cd ../.. 返回上两级目录 …