cpu原理

更新时间:2023-03-14 05:50:27 阅读: 评论:0

人教版一年级数学-表彰大会发言稿

cpu原理
2023年3月14日发(作者:衣服搭配)

LinuxCPU占用率原理与

精确度分析

1CPU占用率计算原理

1.1相关概念

在Linux/Unix下,CPU利用率分为用户态、系统态和空闲态,分别表示CPU处于

用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间。

下面是几个与CPU占用率相关的概念。

CPU利用率

CPU的使用情况。

用户时间(Urtime)

表示CPU执行用户进程的时间,包括nices时间。通常期望用户空间CPU越高

越好。

系统时间(Systemtime)

表示CPU在内核运行时间,包括IRQ和softirq时间。系统CPU占用率高,表明

系统某部分存在瓶颈。通常值越低越好。

等待时间(Waitingtime)

CPI在等待I/O操作完成所花费的时间。系统部应该花费大量时间来等待I/O操

作,否则就说明I/O存在瓶颈。

空闲时间(Idletime)

系统处于空闲期,等待进程运行。

Nice时间(Nicetime)

系统调整进程优先级所花费的时间。

硬中断处理时间(HardIrqtime)

系统处理硬中断所花费的时间。

软中断处理时间(SoftIrqtime)

系统处理软中断中断所花费的时间。

丢失时间(Stealtime)

被强制等待(involuntarywait)虚拟CPU的时间,此时hypervisor在为另一个虚

拟处理器服务。

下面是我们在top命令看到的CPU占用率信息及各项值含义。

Cpu(s):0.2%us,0.2%sy,0.0%ni,99.2%id,0.5%wa,0.0%hi,0.0%si,

0.0%st

us:Urtime

sy:Systemtime

ni:Nicetime

id:Idletime

wa:Waitingtime

hi:HardIrqtime

si:SoftIrqtime

st:Stealtime

1.2CPU占用率计算

LinuxCPU占用率计算,都是根据/proc/stat文件内容计算而来,下面是stat

文件内容样例,内核版本不同,会稍有不同,但内容基本一致。

CPU信息,cpu为总的信息,cpu0…cpun为各个具体CPU信息

cpu6648835

上面共有8个值(单位:ticks),分别为:

Urtime,661733Nicetime,468

Systemtime,503925Idletime,233055573

Waitingtime,548835HardIrqtime,14244

SoftIRQtime,15849Stealtime,0

CPU占用率计算公式如下:

CPU时间=ur+system+nice+idle+iowait+irq+softirq+Stl

%us=(Urtime+Nicetime)/CPU时间*100%

%sy=(Systemtime+HardIrqtime+SoftIRQtime)/CPU时间*100%

%id=(Idletime)/CPU时间*100%

%ni=(Nicetime)/CPU时间*100%

%wa=(Waitingtime)/CPU时间*100%

%hi=(HardIrqtime)/CPU时间*100%

%si=(SoftIRQtime)/CPU时间*100%

%st=(Stealtime)/CPU时间*100%

2CPU占用率内核实现

下面以RHEL6内核源码版本6x86_64为例,来介绍内核源码实现。

/proc/stat文件的创建由函数proc_stat_init()实现,在文件fs/proc/stat.c中,在内核

初始化时调用。/proc/stat文件相关函数时间均在stat.c文件中。

对/proc/stat文件的读写方法为proc_stat_operations。

00152:staticconststructfile_operationsproc_stat_operations={

00153:.open=stat_open,

00154:.read=q_read,

00155:.llek=q_lek,

00156:.relea=single_relea,

00157:};

00158:

打开文件函数stat_open(),函数首先申请大小为size的内存,来存放临时数据

(也是我们看到的stat里的最终数据)。

00128:staticintstat_open(structinode*inode,structfile*file)

00129:{

00130:unsignedsize=4096*(1+num_possible_cpus()/32);

00131:char*buf;

00132:structq_file*m;

00133:intres;

00134:

00135:/*don'taskformorethanthekmalloc()maxsize,currently128KB*/

00136:if(size>128*1024)

00137:size=128*1024;

00138:buf=kmalloc(size,GFP_KERNEL);

00139:if(!buf)

00140:return-ENOMEM;

00141:

00142:res=single_open(file,show_stat,NULL);

00143:if(!res){

00144:m=file->private_data;

00145:m->buf=buf;

00146:m->size=size;

00147:}el

00148:kfree(buf);

00149:returnres;

00150:}?endstat_open?

00151:

/proc/stat文件的数据由show_stat()函数填充。注意42行for_each_possible_cpu(i)

循环,是累加计算所有CPU的数据,如我们前面的示例看到的/proc/stat文件中第一行

cpu值。

cpu6648835

00025:staticintshow_stat(structq_file*p,void*v)

00026:{

00027:inti,j;

00028:unsignedlongjif;

00029:cputime64_tur,nice,system,idle,iowait,irq,softirq,

steal;

00030:cputime64_tguest;

00031:u64sum=0;

00032:u64sum_softirq=0;

00033:unsignedintper_softirq_sums[NR_SOFTIRQS]={0};

00034:structtimespecboottime;

00035:

00036:ur=nice=system=idle=iowait=

00037:irq=softirq=steal=cputime64_zero;

00038:guest=cputime64_zero;

00039:getboottime(&boottime);

00040:jif=_c;

00041:

00042:for_each_possible_cpu(i){

00043:ur=cputime64_add(ur,kstat_cpu(i).);

00044:nice=cputime64_add(nice,kstat_cpu(i).);

00045:system=cputime64_add(system,

kstat_cpu(i).);

00046:idle=cputime64_add(idle,kstat_cpu(i).);

00047:idle=cputime64_add(idle,arch_idle_time(i));

00048:iowait=cputime64_add(iowait,

kstat_cpu(i).);

00049:irq=cputime64_add(irq,kstat_cpu(i).);

00050:softirq=cputime64_add(softirq,

kstat_cpu(i).q);

00051:steal=cputime64_add(steal,kstat_cpu(i).);

00052:guest=cputime64_add(guest,

kstat_cpu(i).);

00053:sum+=kstat_cpu_irqs_sum(i);

00054:sum+=arch_irq_stat_cpu(i);

00055:

00056:for(j=0;j

00057:unsignedintsoftirq_stat=kstat_softirqs_cpu(j,i);

00058:

00059:per_softirq_sums[j]+=softirq_stat;

00060:sum_softirq+=softirq_stat;

00061:}

00062:}

00063:sum+=arch_irq_stat();

00064:

00065:q_printf(p,

"cpu%llu%llu%llu%llu%llu%llu%llu%llu%llun",

00066:(unsignedlonglong)cputime64_to_clock_t(ur),

00067:(unsignedlonglong)cputime64_to_clock_t(nice),

00068:(unsignedlonglong)cputime64_to_clock_t(system),

00069:(unsignedlonglong)cputime64_to_clock_t(idle),

00070:(unsignedlonglong)cputime64_to_clock_t(iowait),

00071:(unsignedlonglong)cputime64_to_clock_t(irq),

00072:(unsignedlonglong)cputime64_to_clock_t(softirq),

00073:(unsignedlonglong)cputime64_to_clock_t(steal),

00074:(unsignedlonglong)cputime64_to_clock_t(guest));

计算总的CPU各个值ur、nice、system、idle、iowait、irq、softirq、steal后,

就分别计算各个CPU的使用情况(75~100行)。

00075:for_each_online_cpu(i){

00076:

00077:/*Copyvaluesheretoworkaroundgcc-2.95.3,gcc-2.96*/

00078:ur=kstat_cpu(i).;

00079:nice=kstat_cpu(i).;

00080:system=kstat_cpu(i).;

00081:idle=kstat_cpu(i).;

00082:idle=cputime64_add(idle,arch_idle_time(i));

00083:iowait=kstat_cpu(i).;

00084:irq=kstat_cpu(i).;

00085:softirq=kstat_cpu(i).q;

00086:steal=kstat_cpu(i).;

00087:guest=kstat_cpu(i).;

00088:q_printf(p,

00089:"cpu%d%llu%llu%llu%llu%llu%llu%llu%llu%llun",

00090:i,

00091:(unsignedlonglong)cputime64_to_clock_t(ur),

00092:(unsignedlonglong)cputime64_to_clock_t(nice),

00093:(unsignedlonglong)cputime64_to_clock_t(system),

00094:(unsignedlonglong)cputime64_to_clock_t(idle),

00095:(unsignedlonglong)cputime64_to_clock_t(iowait),

00096:(unsignedlonglong)cputime64_to_clock_t(irq),

00097:(unsignedlonglong)cputime64_to_clock_t(softirq),

00098:(unsignedlonglong)cputime64_to_clock_t(steal),

00099:(unsignedlonglong)cputime64_to_clock_t(guest));

00100:}

104行计算所有CPU上中断次数,104~105行计算CPU上每个中断向量的

中断次数。注意:/proc/stat文件中,将所有可能的NR_IRQS个中断向量计数

都记录下来,但我们的机器上通过只是用少量的中断向量,这就是看到/proc/stat

文件中,intr一行后面很多值为0的原因。

show_stat()函数最后获取进程切换次数nctxt、内核启动的时间btime、

所有创建的进程process、正在运行进程的数量procs_running、阻塞的进程数

量procs_blocked和所有io等待的进程数量。

00101:q_printf(p,"intr%llu",(unsignedlonglong)sum);

00102:

00103:/*sumagain?itcouldbeupdated?*/

00104:for_each_irq_nr(j)

00105:q_printf(p,"%u",kstat_irqs(j));

00106:

00107:q_printf(p,

00108:"nctxt%llun"

00109:"btime%lun"

00110:"process%lun"

00111:"procs_running%lun"

00112:"procs_blocked%lun",

00113:nr_context_switches(),

00114:(unsignedlong)jif,

00115:total_forks,

00116:nr_running(),

00117:nr_iowait());

00118:

00119:q_printf(p,"softirq%llu",(unsignedlonglong)sum_softirq);

00120:

00121:for(i=0;i

00122:q_printf(p,"%u",per_softirq_sums[i]);

00123:q_printf(p,"n");

00124:

00125:return0;

00126:}?endshow_stat?

00127:

3LinuxCPU占用率精确性分析

在使用类似top命令,观察系统及各进程CPU占用率时,可以指定刷新时间间隔,

以及时刷新和实时观察CPU占用率。

top命令默认情况下,是每3秒刷新一次。也可以通过top-d<刷新时间间隔>来

指定刷新频率,如top-d0.1或top-d0.01等。top执行时,也可以按“s”键,修改

时间间隔。

我们可以将CPU占用率刷新间隔设置很低,如0.01秒。但过低的刷新频率是否能

够更准确观察到CPU占用率?Linux系统提供的CPU占用率信息是否足够精确?

根据前面分析,我们已知Linux是根据/proc/stat文件的内容来计算CPU占用率,也

就是精确度和/proc/stat提供的数据精确度有关。那么

(1)/proc/stat文件中的内容单位是什么?

(2)多久会刷新/proc/stat中的数据?

cpu92620280700

cpu36580300

3.1/proc/stat中的数据单位精度

/proc/stat中CPU数据信息,单位是ticks。内核中有个全局变量jiffies,来记录系

统启动以来,经历的ticks数量。

cpu1130000

ticks(滴答)就是系统时钟中断的时间间隔,该值与内核中HZ值有关,即ticks=

1/HZ。HZ值的大小,在内核编译时可配置的。某台机器上是RHEL6.1内核,配置的

HZ值为1000。

[root@ssdboot]#uname-a

6.x86_64#1SMPTueMay1015:42:40EDT2011x86_64x86_64x86_64

GNU/Linux

[root@ssdboot]#6.x86_64|grepCONFIG_HZ

#CONFIG_HZ_100isnott

#CONFIG_HZ_250isnott

#CONFIG_HZ_300isnott

CONFIG_HZ_1000=y

CONFIG_HZ=1000

[root@ssdboot]

#HZ的值,就是每秒的时钟中断数量。可以观察/proc/interrupts中时钟中断值变化,

来计算HZ的值。当HZ的值为1000时,ticks的单位即为1/1000秒,即1ms。

Every5.0s:cat/proc/interrupts|grepLOC

TueMay1515:54:222012

LOC:3712695699

64358053

2261Localtimerinterrupts

3.2CPU利用率统计信息更新

在时钟中断程序中,更新CPU利用信息,即每个ticks更新一次。

include/linux/kernel_stat.h中,有相应函数接口,专门用来更新CPU利用率信息。如

account_ur_time()是更新用户态CPU信息。

00111:/*

00112:*Lock/unlockthecurrentrunqueue-toextracttaskstatistics:

00113:*/

00114:externunsignedlonglongtask_delta_exec(struct

task_struct*);

00115:

00116:externvoidaccount_ur_time(structtask_struct*,

cputime_t,cputime_t);

00117:externvoidaccount_system_time(structtask_struct*,

int,cputime_t,

00117:cputime_t);

00118:externvoidaccount_steal_time(cputime_t);

00119:externvoidaccount_idle_time(cputime_t);

00120:

00121:externvoidaccount_process_tick(structtask_struct*,

intur);

00122:externvoidaccount_steal_ticks(unsignedlongticks);

00123:externvoidaccount_idle_ticks(unsignedlongticks);

在内核中有一个perCPU变量kernel_stat,专门用来记录CPU利用信息。其定义在

include/linux/kernel_stat.h中。

00039:DECLARE_PER_CPU(structkernel_stat,kstat);

00040:

00041:#definekstat_cpu(cpu)per_cpu(kstat,cpu)

每次时钟中断时(ticks),就会更新kernel_stat变量中各个成员变量的值。/proc/stat

文件中的值,都是在程序读取时更新,内核并不会主动更新/proc/stat中的数据。

/proc/stat中的CPU信息是通过kernel_stat各个成员变量的值计算而来。

3.3CPU利用率精确性分析

通过前面分析,我们可以得出以下结论:

(1)LinuxCPU占用率是根据/proc/stat文件中的数据计算而来;

(2)/proc/stat中的数据精度为ticks,即1/HZ秒;

(3)内核每个ticks会更新一次CPU使用信息;

(4)CPU占用率的精度为1/HZ秒。

4LinuxCPU占用率是否准确?

有时偶尔会遇到类似问题:在稳定计算压力下,进程CPU占用率不稳定;或者特性

进程CPU占用率明显不准。即在系统切换次数很高时,Linux的CPU利用率计算机制可

能不准确。

那么Linux的CPU利用率计算到底是否准确?若可能不准确,则什么情况下出现这

种情况?

4.1LinuxCPU占用率不准确情形

在前面分析中,Linux内核是在每次时钟中断时更新CPU使用情况,即1/HZ秒更新

一次。时钟中断时,只会看到当前正在运行的进程信息。以下图为例,红色箭头表示时

钟中断(TimerInterrupt)。

第一次中断时,看到进程A在运行。但进程A运行时间短,进程B运行。第二次中

断时,进程C运行;在第三次中断到来时,再次调度进程A执行。第三次此中断时,进

程C运行。

按照Linux内核CPU占用率统计方法,在第1次和第2次中断期间,内核并没有看

到进程B在运行;于是就漏掉了进程B使用CPU的信息。同样道理,在第2次和第3

次中断期间,漏掉了进程B使用CPU的情况。这样,就导致了Linux内核CPU占用率

统计不准确。

发生CPU占用率不准确的原因是:在一个时钟中断周期内,发生了多次进程调度。

时钟中断的精度是1/HZ秒。

4.2top命令CPU使用率准确吗?

只有在一个时钟中断周期内发生多次进程调度,才会出现CPU占用率不准的情况。

那么top命令中CPU使用率是否准确与进程调度频率有关。

若HZ的值为250,则ticks值为4ms;若HZ值为1000,则ticks值为1ms。在HZ

为250时,只要进程的调度间隔大于4ms,CPU占用率就准确。HZ为1000时,调度

间隔大于1ms,CPU占用率计算就准确。

进程调度次数少,CPU占用率就准确;调度时间间隔小于时钟中断,就可能不准确。

那么进程调度的时机是怎样的?如何观察进程调度次数?

4.2.1进程调度时机

进程状态转换的时刻:进程终止、进程睡眠

进程要调用sleep()或exit()等函数进行状态转换,这些函数会主动调用调度程

序进行进程调度;

当前进程的时间片用完时(current->counter=0)

由于进程的时间片是由时钟中断来更新的

设备驱动程序

当设备驱动程序执行长而重复的任务时,直接调用调度程序。在每次反复循环中,

驱动程序都检查need_resched的值,如果必要,则调用调度程序schedule()主动放弃

CPU。

进程从中断、异常及系统调用返回到用户态时

不管是从中断、异常还是系统调用返回,最终都调用ret_from_sys_call(),由这

个函数进行调度标志的检测,如果必要,则调用调度程序。那么,为什么从系统调用返

回时要调用调度程序呢?这当然是从效率考虑。从系统调用返回意味着要离开内核态而

返回到用户态,而状态的转换要花费一定的时间,因此,在返回到用户态前,系统把在

内核态该处理的事全部做完。

4.2.2进程调度次数观察

可以通过vmstat命令,来观察系统中进程切换次数,cs域的值就是切换次数。HZ

的值,可以通过内核配置文件来确定,若/proc/存在,导出这个文件查看即可。

也可以通过查看/proc/sched_debug文件内容,来观察切换次数(nr_switches)。

[root@ssdproc]#watch-d-n1'cat/proc/sched_debug|grepnr_switches'

我们系统中的进程调度真的那么频繁吗?大多数情况下,Linux中的CPU占用率计

算机制是准确的。

本文发布于:2023-03-14 05:50:26,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/1678744227244502.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:cpu原理.doc

本文 PDF 下载地址:cpu原理.pdf

上一篇:蚂蚁习性
下一篇:返回列表
标签:cpu原理
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图