Linux多核运行机制(SMP)

news/2024/5/3 17:38:53/文章来源:https://blog.csdn.net/code_lyb/article/details/128048254

一、Linux内核兼容多处理器要求

        有多个 CPU 处理器 的 系统中 , Linux 内核需要处理的问题 :

                1、公平共享 : CPU 的负载 , 需要公平地共享 , 不能出现某个CPU空闲 , 造成资源浪费。

                2、可设置进程 与 CPU 亲和性 : 可以为 某些类型的 进程 与 指定的 处理器设置亲和性 , 可以针对性地匹配 进程与处理器 。

                3、进程迁移 : Linux 内核可以将进程在不同的CPU处理器之间进行迁移 。

        Linux 内核 的SMP对称多处理器结构调度,核心就是将进程迁移到合适的 处理器上 , 并且可以保持各个处理器的负载均衡。

二、UP

        UP(Uni-Processor):系统只有一个处理器单元,即单核CPU系统。

三、SMP

3.1、概念

        对称多处理器结构 , 英文名称为 " Symmetrical Multi-Processing " , 简称 SMP 。

        SMP 又称为 UMA , 全称 " Uniform Memory Access " , 中文名称 " 统一内存访问架构 " 。

        在 " 对称多处理器结构 " 的 系统中 , 所有的处理器单元的地位都是平等的 , 一般指的是服务器设备上 , 运行的 多个 CPU , 没有 主次/从属 关系,都是平等的。

        这些处理器 共享 所有的设备资源 , 所有的资源对处理器单元具有相同的可访问性 , 如 : 磁盘 , 内存 , 总线等 ,多个CPU处理器共享相同的物理内存 , 每个 CPU 访问相同的物理地址 , 所消耗的时间是相同的 ;

        要注意,这里提到的“处理器单元”是指“logic CPU”,而不是“physical CPU”。举个例子,如果一个“physical CPU”包含2个core,并且一个core包含2个hardware thread。则一个“处理器单元”就是一个hardware thread。

3.2、SMP的优势与缺陷

        优点 :避免了 结构障碍 , 其最大的特点是 所有的资源共享。

        缺点:SMP 架构的系统 , 扩展能力有限 , 有瓶颈限制。

        如 : 内存瓶颈限制 , 每个 CPU 处理器必须通过 相同的总线 访问 相同的内存资源 , 如果 CPU 数量不断增加 , 使用同一条总线 , 就会导致 内存访问冲突 ; 这样就降低了 CPU 的性能 ;

        通过实践证明 , SMP 架构的系统 , 使用2 ~ 4个 CPU , 可以达到利用率最高 , 如果 CPU 再多 , 其利用率就会降低 , 浪费处理器的性能 。

3.3、SMP启动

        SMP结构中的CPU都是平等的,没有主次之分,这是基于系统中有多个进程的前提下说的。

        在同一时间,一个进程只能由一个CPU执行。

        系统启动对于SMP结构来说是一个特例,因为在这个阶段系统里只有一个CPU,也就是说在刚刚上电或者总清时只有一个CPU来执行系统引导和初始化。

        这个CPU被称为“引导处理器”,即BP,其余的处理器处于暂停状态,称为“应用处理器”,即AP。

         "引导处理器"完成整个系统的引导和初始化,并创建起多个进程,从而可以由多个处理器同时参与处理时,才启动所有的"应用处理器",让他们完成自身的初始化以后,投入运行。

                1、BP先完成自身初始化,然后从start_kernel()调用smp_init()进行SMP结构初始化。

                2、smp_init()的主体是smp_boot_cpus(),依次调用do_boot_cpu()启动各个AP。

                3、AP通过执行trampoline.S的一段跳板程序进入startup_32()完成一些基本初始化。

                4、AP进入start_secondary()做进一步初始化工作,进入自旋(全局变量smp_commenced是否变为1),等待一个统一的“起跑”命令。

                5、BP完成所有AP启动后,调用smp_commence()发出该起跑命令。

                6、每个CPU进入cpu_idle(),等待调度。

3.4、SMP拓扑关系构建

        系统启动时开始构建CPU拓扑关系。

        ARM中,4核处理器示意图如下所示:

         上述4核处理器最后生成的调度域与调度组的拓扑关系图如下图如示:

3.5、SMP调度机制分析

        1、首先,load_balance()调用find_busiest_queue()来选出最忙的运行队列,在这个队列中具有最多的进程数。这个最忙的运行队列应该至少比当前的队列多出25%的进程数量。如果不存在具备这样条件的队列,find_busiest_queue()函数NULL,同时load_balance()也返回。如果存在,那么将返回这个最忙的运行时队列。

        2、然后,load_balance()函数从这个最忙的运行时队列中选出将要进行负载平衡的优先级数组(priority array)。选取优先级数组原则是,首先考虑过期数组(expired array),因为这个数组中的进程相对来说已经很长时间没有运行了,所以它们极有可能不在处理器缓冲中。如果过期数组(expired priority array)为空,那就只能选择活跃数组(active array)。

        3、下一步,load_balance()找出具有最高优先级(最小的数字)链表,因为把高优先级的进程分发出去比分发低优先级的更重要。

        4、为了能够找出一个没有运行,可以迁移并且没有被缓冲的进程,函数将分析每一个该队列中的进程。如果有一个进程符合标准,pull_task()函数将把这个进程从最忙的运行时队列迁移到目前正在运行的队列。

        5、只要这个运行时队列还处于不平衡的状态,函数将重复执行3和4,直到将多余进程从最忙的队列中迁移至目前正在运行的队列。最后,系统又处于平衡状态,当前运行队列解锁。load_balance()返回。

3.6、SMP调度时机

        1、scheduler_tick

        2、try_to_wake_up(优先选择在唤醒的CPU上运行)。

        3、exec系统调用启动一个新进程时。

3.6.1、scheduler_tick

        系统的软中断触发会周期性的调度scheduler_tick函数,每个cpu都有一个时钟中断,都会被周期性的调度到scheduler_tick函数。

/** This function gets called by the timer code, with HZ frequency.* We call it with interrupts disabled.*/
void scheduler_tick(void)
{int cpu = smp_processor_id();struct rq *rq = cpu_rq(cpu);struct task_struct *curr = rq->curr;struct rq_flags rf;sched_clock_tick();rq_lock(rq, &rf);walt_set_window_start(rq, &rf);walt_update_task_ravg(rq->curr, rq, TASK_UPDATE,walt_ktime_clock(), 0);update_rq_clock(rq);curr->sched_class->task_tick(rq, curr, 0);cpu_load_update_active(rq);calc_global_load_tick(rq);psi_task_tick(rq);rq_unlock(rq, &rf);perf_event_task_tick();#ifdef CONFIG_SMPrq->idle_balance = idle_cpu(cpu);trigger_load_balance(rq);
#endifrq_last_tick_reset(rq);if (curr->sched_class == &fair_sched_class)check_for_migration(rq, curr);
}

        scheduler_tick主要完成的任务如下:

                1、更新WALT统计的。

                2、更新系统时钟。

                3、更新PELT方式统计的cpu级别的负载统计。

                4、更新系统级的负载统计。

                5、触发负载均衡trigger_load_balance。

/** Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.*/
void trigger_load_balance(struct rq *rq)
{/* Don't need to rebalance while attached to NULL domain */if (unlikely(on_null_domain(rq)))return;/*
#define time_after_eq(a,b)    \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(a) - (long)(b) >= 0)) 
在宏中,参数 a 是 jiffies 在某个时刻的快照,如果 a 所代表的时间比 b 靠后或者相等,那么返回真
*/if (time_after_eq(jiffies, rq->next_balance))raise_softirq(SCHED_SOFTIRQ);
#ifdef CONFIG_NO_HZ_COMMONif (nohz_kick_needed(rq, false))nohz_balancer_kick(false);
#endif
}

        绑定的软中断的处理函数run_rebalance_domains。CONFIG_NO_HZ_COMMON这个宏是已经定义的。

/** run_rebalance_domains is triggered when needed from the scheduler tick.* Also triggered for nohz idle balancing (with nohz_balancing_kick set).*/
static __latent_entropy void run_rebalance_domains(struct softirq_action *h)
{struct rq *this_rq = this_rq();enum cpu_idle_type idle = this_rq->idle_balance ?CPU_IDLE : CPU_NOT_IDLE;/** If this cpu has a pending nohz_balance_kick, then do the* balancing on behalf of the other idle cpus whose ticks are* stopped. Do nohz_idle_balance *before* rebalance_domains to* give the idle cpus a chance to load balance. Else we may* load balance only within the local sched_domain hierarchy* and abort nohz_idle_balance altogether if we pull some load.*/nohz_idle_balance(this_rq, idle);update_blocked_averages(this_rq->cpu);
#ifdef CONFIG_NO_HZ_COMMONif (!test_bit(NOHZ_STATS_KICK, nohz_flags(this_rq->cpu)))rebalance_domains(this_rq, idle);clear_bit(NOHZ_STATS_KICK, nohz_flags(this_rq->cpu));
#elserebalance_domains(this_rq, idle);
#endif
}
/** It checks each scheduling domain to see if it is due to be balanced,* and initiates a balancing operation if so.** Balancing parameters are set up in init_sched_domains.*//*
根据domain级别,从下往上扫描每一级sched_domain。
如果这个domain balance之间间隔时间到了,就进行load_balance操作,
不同级别的domain时间间隔不同,而且级别越高,间隔越长,因为迁移task代价越来越大。
*/
static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle)
{int continue_balancing = 1;int cpu = rq->cpu;unsigned long interval;struct sched_domain *sd;/* Earliest time when we have to do rebalance again *//* 默认本cpu rq下一次的balance时间为60 tick以后 */unsigned long next_balance = jiffies + 60*HZ;int update_next_balance = 0;int need_serialize, need_decay = 0;u64 max_cost = 0;rcu_read_lock();/* (2) 对本cpu每个层次的schedule_domain进行扫描 */for_each_domain(cpu, sd) {//遍历该cpu的所有调度域,从最低一级到最高一级。/** Decay the newidle max times here because this is a regular* visit to all the domains. Decay ~1% per second.*/// max_newidle_lb_cost 是做load balance所花时间。如上面注释所说,max_newidle_lb_cost每个1s衰减1%// next_decay_max_lb_cost 是下一次进行衰减的时间// 老化公式: new = old * (253/256)if (time_after(jiffies, sd->next_decay_max_lb_cost)) {sd->max_newidle_lb_cost =(sd->max_newidle_lb_cost * 253) / 256;sd->next_decay_max_lb_cost = jiffies + HZ;need_decay = 1;}max_cost += sd->max_newidle_lb_cost;if (energy_aware() && !sd_overutilized(sd) && !sd->parent)continue;if (!(sd->flags & SD_LOAD_BALANCE)) {//该调度域被指定不进行负载均衡if (time_after_eq(jiffies,sd->groups->sgc->next_update))update_group_capacity(sd, cpu);continue;}/** Stop the load balance at this level. There is another* CPU in our sched group which is doing load balancing more* actively.*//* (4) 如果continue_balancing = 0,指示停止当前层级的load balance因为shed_group中其他的cpu正在这个层次做load_balance*/if (!continue_balancing) {if (need_decay)continue;break;}/* (5) 计算当前层次schedule_domain的balance间隔时间 */interval = get_sd_balance_interval(sd, idle != CPU_IDLE);/* (6) 如果需要串行化(SD_SERIALIZE),做balance之前需要持锁 */need_serialize = sd->flags & SD_SERIALIZE;if (need_serialize) {if (!spin_trylock(&balancing))goto out;}/* (7) 如果本sd的balance间隔时间已到,进行实际的load_balance() *///load_balance检查该cpu在这一层的调度域中是否存在负载不平衡的情况,如果存在该cpu会分担负载最重的那个cpu的一些任务if (time_after_eq(jiffies, sd->last_balance + interval)) {if (load_balance(cpu, rq, sd, idle, &continue_balancing)) {/** The LBF_DST_PINNED logic could have changed* env->dst_cpu, so we can't know our idle* state even if we migrated tasks. Update it.*/idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE;}sd->last_balance = jiffies;interval = get_sd_balance_interval(sd, idle != CPU_IDLE);}if (need_serialize)spin_unlock(&balancing);
out://到达执行load balance的时间if (time_after(next_balance, sd->last_balance + interval)) {next_balance = sd->last_balance + interval;update_next_balance = 1;}}if (need_decay) {/** Ensure the rq-wide value also decays but keep it at a* reasonable floor to avoid funnies with rq->avg_idle.*/rq->max_idle_balance_cost =max((u64)sysctl_sched_migration_cost, max_cost);}rcu_read_unlock();/** next_balance will be updated only when there is a need.* When the cpu is attached to null domain for ex, it will not be* updated.*//* (8.1) 更新rq的balance时间 */if (likely(update_next_balance)) {rq->next_balance = next_balance;#ifdef CONFIG_NO_HZ_COMMON/** If this CPU has been elected to perform the nohz idle* balance. Other idle CPUs have already rebalanced with* nohz_idle_balance() and nohz.next_balance has been* updated accordingly. This CPU is now running the idle load* balance for itself and we need to update the* nohz.next_balance accordingly.*/if ((idle == CPU_IDLE) && time_after(nohz.next_balance, rq->next_balance))nohz.next_balance = rq->next_balance;
#endif}
}

 四、常用命令

4.1、查看逻辑CPU个数

        方法一:cat /proc/cpuinfo

 processor : 11vendor_id : GenuineIntelcpu family : 6model : 62model name : Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHzstepping : 4microcode : 1064cpu MHz : 2100.170cache size : 15360 KBphysical id : 0siblings : 12core id : 5cpu cores : 6apicid : 11initial apicid : 11fpu : yesfpu_exception : yescpuid level : 13wp : yesflags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat xsaveopt pln pts dts tpr_shadow vnmi flexpriority ept vpid fsgsbase smep ermsbogomips : 4200.34clflush size : 64cache_alignment : 64address sizes : 46 bits physical, 48 bits virtualpower management:

        可以看出有12个逻辑CPU。因为processor从0开始,到11结束,说明有12个。

        方法二:cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c

[root@localhost ~]# cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c12  Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz

4.2、查看每个CPU核心数

        cat /proc/cpuinfo |grep “cores”

[root@localhost ~]# cat /proc/cpuinfo |grep "cores"
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6
cpu cores : 6

        可以看到,12个逻辑CPU中,每个CPU都是6核。其实在查看CPU基本信息里,有个cpu cores:6,直接就显示是6个。 

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

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

相关文章

数据结构与算法之让我们种下一棵字典树(Java/C++双语言实现)

⭐️前面的话⭐️ 本篇文章将介绍一种经常使用的数据结构——字典树,它又称Tire树,前缀树,字典树,顾名思义,是关于“字典”的一棵树。这个词典中的每个“单词”就是从根节点出发一直到某一个目标节点的路径&#xff0…

CSRF漏洞简介

今天继续给大家介绍渗透测试相关知识,本文主要内容是CSRF漏洞原理、产生与危害。 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后果自负! 再次强调:严禁对未…

C语言 * 数组的解析 *

目录 一:一维数组的创建和初始化 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 二:二维数组的创建和初始化 2.1 数组的创建 2.2 数组的初始化 2.3 一维数组的使用 2.4 一维数组在内存中的存储 2.5 数组越…

【蓝桥杯选拔赛真题30】python计算倒数和 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python计算倒数和 一、题目要求 1、编程实现 2、输入输出 3、评分标准

从01背包说起(上)

目录 引入 1.什么是动态规划? 2.什么是背包问题? 3.什么是01背包? 模板题 1.题面 2.思路 Ⅰ为何不可用贪心 Ⅱ状态转移方程 3.代码 下期预告 引入 1.什么是动态规划? 动态规划(英语:Dynamic programming&#xff0…

收到多个20k+的offer!选哪一个呢?

“收到offer了!”最近,黑马老师收到最多的消息就属这句了。随着黑马各个学科迎来毕业,班主任收到的喜讯越来越多。班主任说,没有比在接近年底时收到学生就业喜讯更让人开心的事了。今天,播妞给大家带来的是黑马HTML&am…

就两秒?这说出去谁信啊!

文 | xiaoyi(转载请后台联系)关注公众号:小一的学习笔记截止发文,北上广深一共有6510条公交线路为了获取上面的这些线路信息,我写了一个爬虫,大概用了2秒左右就搞定,真爽!说出来你们…

【项目实战:核酸检测平台】第三章 利其器

第三章 利其器 摘要:俗话说的好工欲善其事,必先利其器,框架搭的好,开发起来很舒服,搭的不好,开发起来就很痛苦。 一个程序员只会写业务代码,最多算是个码农,搭框架的本事、遇到难题的解决能力…

第八章 兼容多种模块标准的软件包封装

第八章 如何封装兼容多种JS模块标准的软件包? 为了方便用户使用,一款成熟的类库都会提供多种模块封装形式,比如大家最常用到的 Vue,就提供了cjs、esm、umd 等多种封装模式,并且还会提供对应的压缩版本,方便…

微服务之间,最佳的调用方式是什么?

在微服务架构中,需要调用很多服务才能完成一项功能。服务之间如何互相调用就变成微服务架构中的一个关键问题。服务调用有两种方式,一种是RPC方式,另一种是事件驱动(Event-driven)方式,也就是发消息方式。消…

MySQL海量数据优化(理论+实战) 吊打面试官

一、准备表数据 咱们建一张用户表,表中的字段有用户ID、用户名、地址、记录创建时间,如图所示 ​OK,接下来准备写一个存储过程插入一百万条数据 CREATE TABLE t_user (id int NOT NULL,user_name varchar(32) CHARACTER SET utf8 COLLATE ut…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java线上学习系统8e88w

做毕业设计一定要选好题目。毕设想简单,其实很简单。这里给几点建议: 1:首先,学会收集整理,年年专业都一样,岁岁毕业人不同。很多人在做毕业设计的时候,都犯了一个错误,那就是不借鉴…

路由策略和路由控制

路由策略和路由控制 路由策略 针对路由的发布,接收,引入进行控制,从而影响数据的路径或者可达性 路由匹配工具 ACL:访问前缀列表 一个ACL用多条规则组成,不同规则之间通过rule id进行区分,默认rule 步…

[附源码]java毕业设计智慧农业销售平台

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

XSS测试绕过WAF思路

今天继续给大家介绍渗透测试相关知识,本文主要内容是XSS测试绕过WAF思路。 免责声明: 本文所介绍的内容仅做学习交流使用,严禁利用文中技术进行非法行为,否则造成一切严重后果自负! 再次强调:严禁对未授权设…

【C/C++】万字图文详解C语言文件操作 完美装饰课设大作业

目标导航 写在前面 为什么使用文件? 什么是文件? 程序文件 数据文件 认识文件名 文件的打开和关闭 文件指针 文件的打开和关闭 1.以"r"(只读)的方式打开文件 2.以"w"(只写)…

178:vue+openlayers 加载多种形式Esri地图

第178个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+openlayers中绘制自定义图形,利用Geojson的writeFeatures,来生成geojson格式的数据,然后使用file-saver来导出geojson。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果OpenStreetM…

进程的初识

目录预备知识 -> 操作系统操作系统的定义操作系统的定位进程进程的概念进程调度的过程进程的管理描述组织PCB描述进程的特征进程调度的相关属性进程的状态优先级上下文记账信息预备知识 -> 操作系统 操作系统的定义 操作系统是一个搞管理的软件 对上,要对硬…

基于android的个性闹铃的设计与开发(闹铃,日历,计时器,备忘录)

目 录 摘 要 2 Abstract 2 1 选题的背景和意义 5 1.1 选题的背景 5 1.2 国内外研究现状 5 1.2.1 国内外手机系统现状 5 1.2.2 国内外手机应用现状 7 1.2.3 发展趋势 7 2 需求分析 9 2.1 系统需求 9 2.2 需求分析 9 2.3 约束与限制 10 3 总体设计 11 3.1 系统结构图 11 3.2 总体…

网站被大量cc攻击导致打不开怎么解决

家好,今天小蚁君给大家分享一个昨天接入我们防护的客户,说下这个客户特点, 网站业务,由于源服务器是在阿里云,防护阈值很低,基本上是无防御的,随便压测一下就死,通过朋友介绍过来&am…