阿里云服务器网站:https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=qqwovx6h
文字来源:http://www.samirchen.com/linux-cpu-performance/
1、Linux 环境下查看 CPU 信息
1.1、查看 CPU 详细信息
通过 cat /proc/cpuinfo
命令,可以查看 CPU 相关的信息:
[root@rh~]$cat/proc/cpuinfo
processor:
vendor_id:GenuineIntel
cpufamily:
model:
modelname:Intel(R)Xeon(R)CPUE5620@.40GHz
stepping:
cpuMHz:1596.000
cachesize:12288KB
physicalid:
siblings:
coreid:
cpucores:
apicid:
initialapicid:
fpu:yes
fpu_exception:yes
cpuidlevel:
wp:yes
flags:fpuvmedepsetscmsrpaemcecx8apicsepmtrrpgemcacmovpatpse36clflushdtsacpimmxfxsrssesse2sshttmpbesyscallnxpdpe1gbrdtscplmconstant_tscarch_perfmonpebsbtsrep_goodxtopologynonstop_tscaperfmperfpnipclmulqdqdtes64monitords_cplvmxsmxesttm2ssse3cx16xtprpdcmpciddcasse4_1sse4_2popcntaeslahf_lmaratepbdtstpr_shadowvnmiflexpriorityeptvpid
bogomips:4800.15
clflushsize:
cache_alignment:
addresssizes:40bitsphysical,48bitsvirtual
powermanagement:
......
在查看到的相关信息中,通常有些信息比较让人迷惑,这里列出一些解释:
- physical id: 指的是物理封装的处理器的 id。
- cpu cores: 位于相同物理封装的处理器中的内核数量。
- core id: 每个内核的 id。
- siblings: 位于相同物理封装的处理器中的逻辑处理器的数量。
- processor: 逻辑处理器的 id。
我们通常可以用下面这些命令获得这些参数的信息:
[root@rh ~]$ cat /proc/cpuinfo | grep "physical id"| sort|uniq
physical id :
physical id :
[root@rh ~]$ cat /proc/cpuinfo | grep "cpu cores"| sort|uniq
cpu cores :
[root@rh ~]# cat /proc/cpuinfo | grep "core id" | sort|uniq
core id :
core id :
core id :
core id :
[root@rh ~]$ cat /proc/cpuinfo | grep "siblings"| sort|uniq
siblings :
[root@rh ~]$ cat /proc/cpuinfo | grep "processor"| sort|uniq
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
processor :
通过上面的结果,可以看出这台机器:
- 1)有 2 个物理封装的处理器(physical id 有 2 个);
- 2)每个物理封装的处理器有 4 个内核(cpu cores 为 4);
- 3)每个物理封装的处理器有 8 个逻辑处理器(siblings 为 8),可见台机器的处理器开启了超线程技术,每个内核(core)被划分为了 2 个逻辑处理器(processor);
- 4)总共有 16 个逻辑处理器(processor 有 16 个);
超线程技术
:超线程技术就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。
1.2、查看多核 CPU 信息
可以使用 mpstat
命令或 sar
命令来查看。 具体使用可以通过 man mpstat/sar
来查看。
2、在 Linux 环境下计算进程的 CPU 占用
2.1、通过 /proc/stat 文件查看所有的 CPU 活动信息
下面实例数据是内核 2.6.24-24 版本以上的:
[root@rh ~]$ cat /proc/stat
cpu
cpu0
cpu1
cpu2
cpu3
cpu4
cpu5
cpu6
cpu7
cpu8
cpu9
cpu10
cpu11
cpu12
cpu13
cpu14
cpu15
intr <...省略若干数据...>
ctxt
btime
processes
procs_running
procs_blocked
softirq
第一行的数据表示的是 CPU 总的使用情况。我们来解释一下这行数据各数值的含义:
- 1)这些数值的单位都是 jiffies,jiffies 是内核中的一个全局变量,用来记录系统启动以来产生的节拍数,在 Linux 中,一个节拍大致可以理解为操作系统进程调度的最小时间片,不同的 Linux 系统内核这个值可能不同,通常在 1ms 到 10ms 之间。
- 2)cpu 223447 240 4504182 410802165 59753 412 586209 0 0
-
user
(223447) 从系统启动开始累积到当前时刻,处于用户态的运行时间,不包含 nice 值为负的进程。 -
nice
(240) 从系统启动开始累积到当前时刻,nice 值为负的进程所占用的 CPU 时间。 -
system
(4504182) 从系统启动开始累积到当前时刻,处于核心态的运行时间。 -
idle
(410802165) 从系统启动开始累积到当前时刻,除 IO 等待时间以外的其他等待时间。 -
iowait
(59753) 从系统启动开始累积到当前时刻,IO 等待时间。(since 2.5.41) -
irq
(412) 从系统启动开始累积到当前时刻,硬中断时间。(since 2.6.0-test4) -
softirq
(586209) 从系统启动开始累积到当前时刻,软中断时间。(since 2.6.0-test4) -
stealstolen
(0) Which is the time spent in other operating systems when running in a virtualized environment.(since 2.6.11) -
guest
(0) Which is the time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.(since 2.6.24)
-
从以上信息我们可以得到总的 CPU 活动时间为:
totalCPUTime = user
+ nice
+ system
+ idle
+ iowait
+ irq
+ softirq
+ stealstolen
+ guest
2.2、通过 /proc/[PID]/stat 文件查看某一进程的 CPU 活动信息
2.2.1、存储进程信息的文件目录
Linux 系统贯彻“一切都是文件”的思想,所有的进程的运行状态也都可以通过读取文件来获取。 /proc
文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过 /proc
得到系统的信息,并可以改变内核的某些参数。
在 /proc/[PID]/
目录下的各个文件记录着 这个进程的各项运行指标。 是进程号。
2.2.2、查看进程运行的详细信息
通过查看 /proc/[PID]/stat
文件,可以进程运行的详细信息,其中就包括 CPU 占用信息。 比如:
[root@rh ~]$ cat /proc//stat
(init) S -
/proc/[PID]/stat
文件信息解释
看到上面这些信息,肯定会很迷惑,不知道每个字段都是什么意思。
1)我们可以通过 man 5 proc 命令查看文档,找到 /proc/[pid]/stat 节点,就可以看到各字段的意思了。如:
/proc/[pid]/stat
Status information about the process.Thisis used by ps().Itisdefinedin/usr/src/linux/fs/proc/array.c.
The fields,in order,with their proper scanf() format specifiers, are:
pid %d The process ID.
comm %s The filename of the executable,in parentheses.Thisis visible whether ornot the executable is swapped out.
state %c One character from the string"RSDZTW"where R is running, S is sleeping in an interruptible wait, D is waiting in uninterruptible disk sleep, Z is zombie, T is traced or stopped (on a signal),and W is paging.
ppid %d The PID of the parent.
......
2)具体解释,一个示例:
pid= 进程(包括轻量级进程,即线程)号
comm=a.out 应用程序或命令的名字。
task_state=R 任务的状态,R:runnign, S:sleeping (TASK_INTERRUPTIBLE), D:disk sleep (TASK_UNINTERRUPTIBLE), T: stopped, T:tracing stop, Z:zombie, X:dead。
ppid= 父进程ID。
pgid= 线程组号。
sid= 该任务所在的会话组 ID。
tty_nr=(pts/) 该任务的 tty 终端的设备号,INT(/)= 主设备号,(-主设备号)= 次设备号。
tty_pgrp= 终端的进程组号,当前运行在该任务所在终端的前台任务(包括 shell 应用程序)的 PID。
task->flags= 进程标志位,查看该任务的特性。
min_flt= 该任务不需要从硬盘拷数据而发生的缺页(次缺页)的次数。
cmin_flt= 累计的该任务的所有的 waited-for 进程曾经发生的次缺页的次数目。
maj_flt= 该任务需要从硬盘拷数据而发生的缺页(主缺页)的次数。
cmaj_flt= 累计的该任务的所有的 waited-for 进程曾经发生的主缺页的次数目。
utime= 该任务在用户态运行的时间,单位为 jiffies。
stime= 该任务在核心态运行的时间,单位为 jiffies。
cutime= 累计的该任务的所有的 waited-for 进程曾经在用户态运行的时间,单位为 jiffies。
cstime= 累计的该任务的所有的 waited-for 进程曾经在核心态运行的时间,单位为 jiffies。
priority= 任务的动态优先级。
nice= 任务的静态优先级。
num_threads= 该任务所在的线程组里线程的个数。
it_real_value= 由于计时间隔导致的下一个 SIGALRM 发送进程的时延,以 jiffy 为单位。
start_time= 该任务启动的时间,单位为 jiffies。
vsize=(page) 该任务的虚拟地址空间大小。
rss=(page) 该任务当前驻留物理地址空间的大小;Number of pages the process has in real memory,minu for administrative purpose. 这些页可能用于代码,数据和栈。
rlim=(bytes) 该任务能驻留物理地址空间的最大值。
start_code= 该任务在虚拟地址空间的代码段的起始地址。
end_code= 该任务在虚拟地址空间的代码段的结束地址。
start_stack= 该任务在虚拟地址空间的栈的结束地址。
kstkesp= esp( 位堆栈指针) 的当前值, 与在进程的内核堆栈页得到的一致。
kstkeip= 指向将要执行的指令的指针, EIP( 位指令指针)的当前值。
pendingsig= 待处理信号的位图,记录发送给进程的普通信号。
block_sig= 阻塞信号的位图。
sigign= 忽略的信号的位图。
sigcatch= 被俘获的信号的位图。
wchan= 如果该进程是睡眠状态,该值给出调度的调用点。
nswap 被 swapped 的页数,当前没用。
cnswap 所有子进程被 swapped 的页数的和,当前没用。
exit_signal= 该进程结束时,向父进程所发送的信号。
task_cpu(task)= 运行在哪个 CPU 上。
task_rt_priority= 实时进程的相对优先级别。
task_policy= 进程的调度策略,=非实时进程,=FIFO实时进程;=RR实时进程
2.2.3、关于进程占用 CPU 的相关信息
在上述的时间中,这些信息会在计算 CPU 占用率时用到:
-
pid
进程号。 -
utime
该任务在用户态运行的时间,单位为 jiffies。 -
stime
该任务在核心态运行的时间,单位为 jiffies。 -
cutime
累计的该任务的所有的 waited-for 进程曾经在用户态运行的时间,单位为 jiffies。 -
cstime
累计的该任务的所有的 waited-for 进程曾经在核心态运行的时间,单位为 jiffies。
该进程的 CPU 占用时间(该值包括其所有线程的 CPU 时间):
processCPUTime = utime + stime + cutime + cstime
2.3、通过 /proc/[PID]/task/[TID]/stat 文件查看某一进程下的某一线程的活动信息
该文件包含了某一轻量级进程(lwp,即通常所说的线程)所有的活动信息,该文件中的所有值都是从系统启动开始累计到当前时刻。该文件的内容格式以及各字段的含义与 /proc/[PID]/stat
文件类似。该文件中的 tid
字段表示的是轻量级线程号。
该线程的 CPU 占用时间:
threadCPUTime = utime + stime
2.4、单核情况下 CPU 使用率的计算
2.4.1、基本思想
首先,通过读取 /proc/stat
文件获取总的 CPU 时间,读取 /proc/[PID]/stat
获取进程 CPU 时间,读取 /proc/[PID]/task/[TID]/stat
获取线程 CPU 时间。然后,采样两个足够短的时间间隔的 CPU 快照与进程或线程快照来计算其 CPU 使用率。
2.4.2、计算总的 CPU 使用率 totalCPUUse
1)采样两个足够短的时间间隔的 CPU 快照,即读取 /proc/stat
文件,获取两个时间点的下列数据:
- CPUT1 (user1, nice1, system1, idle1, iowait1, irq1, softirq1, stealstolen1, guest1);
- CPUT2 (user2, nice2, system2, idle2, iowait2, irq2, softirq2, stealstolen2, guest2);
2)计算总的 CPU 时间 totalCPUTime:
- CPUTime1 = user1 + nice1 + system1 + idle1 + iowait1 + irq1 + softirq1 + stealstolen1 + guest1;
- CPUTime2 = user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2 + stealstolen2 + guest2;
totalCPUTime = CPUTime2 – CPUTime1;
3)计算 CPU 空闲时间 idleCPUTime:
idleCPUTime = idle2 – idle1;
4)计算总的 CPU 使用率 totalCPUUse:
totalCPUUse = (totalCPUTime – idleCPUTime) / totalCPUTime;
2.4.3、计算某一进程的 CPU 使用率 processCPUUse
1)采样两个足够短的时间间隔的 CPU 快照和对应的进程快照,即读取 /proc/stat
文件,获取两个时间点的下列数据:
- CPUT1 (user1, nice1, system1, idle1, iowait1, irq1, softirq1, stealstolen1, guest1);
- CPUT2 (user2, nice2, system2, idle2, iowait2, irq2, softirq2, stealstolen2, guest2);
读取 /proc/[PID]/stat
文件,获取两个时间点的下列数据:
- ProcessT1 (utime1, stime1, cutime1, cstime1);
- ProcessT2 (utime2, stime2, cutime2, cstime2);
2)计算总的 CPU 时间 totalCPUTime 和进程时间 processTime:
- CPUTime1 = user1 + nice1 + system1 + idle1 + iowait1 + irq1 + softirq1 + stealstolen1 + guest1;
- CPUTime2 = user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2 + stealstolen2 + guest2;
totalCPUTime = CPUTime2 – CPUTime1;
- processTime1 = utime1 + stime1 + cutime1 + cstime1;
- processTime2 = utime2 + stime2 + cutime1 + cstime2;
processTime = processTime2 – processTime1;
3)计算该进程的 CPU 使用率 processCPUUse:
processCPUUse = processTime / totalCPUTime;
2.4.4、计算某一线程的 CPU 使用率 threadCPUUse
1)采样两个足够短的时间间隔的 CPU 快照和对应的线程快照,即读取 /proc/stat
文件,获取两个时间点的下列数据:
- CPUT1 (user1, nice1, system1, idle1, iowait1, irq1, softirq1, stealstolen1, guest1);
- CPUT2 (user2, nice2, system2, idle2, iowait2, irq2, softirq2, stealstolen2, guest2);
读取 /proc/[PID]/task/[TID]/stat
文件,获取两个时间点的下列数据:
- threadT1 (utime1, stime1);
- threadT2 (utime2, stime2);
2)计算总的 CPU 时间 totalCPUTime 和线程时间 threadTime:
- CPUTime1 = user1 + nice1 + system1 + idle1 + iowait1 + irq1 + softirq1 + stealstolen1 + guest1;
- CPUTime2 = user2 + nice2 + system2 + idle2 + iowait2 + irq2 + softirq2 + stealstolen2 + guest2;
totalCPUTime = CPUTime2 – CPUTime1;
- threadTime1 = utime1 + stime1;
- threadTime2 = utime2 + stime2;
threadTime = threadTime2 – threadTime1;
3)计算该线程的 CPU 使用率 threadCPUUse:
threadCPUUse = threadTime / totalCPUTime;
2.5、多核情况下 CPU 使用率的计算
2.5.1、基本思想
首先,通过读取 /proc/stat
文件获取总的 CPU 时间,读取 /proc/[PID]/stat
获取进程 CPU 时间,读取 /proc/[PID]/task/[TID]/stat
获取线程 CPU 时间,读取 /proc/cpuinfo
获取 CPU 个数。
在多核情况下计算进程或线程的 CPU 使用率,用上面的方式得到的通常是相对于 CPU 所有核的总共时间的占用率,而我们通常习惯得到进程或线程对某一个单核的占用率。所以我们可以按上面的方式计算得到 CPU 占用率,然后把结果乘上 CPU 的核数,即可得到进程或线程相对于一个单核的占用率。
2.5.2、计算总的 CPU 使用率
同 2.4.2。
2.5.3、计算某一进程的 CPU 使用率 mProcessCPUUse
1)同 2.4.3 计算某一进程的 CPU 使用率 processCPUUse;
2)读取 /proc/cpuinfo 文件获取逻辑 CPU(processor) 的个数(参见 1.1): processorNum
3)多核情况下该进程的 CPU 使用率 mProcessCPUUse:
mProcessCPUUse = processCPUUse * processorNum;
2.5.4、计算某一线程的 CPU 使用率 mThreadCPUUse
1)同 2.4.4 计算某一线程的 CPU 使用率 threadCPUUse;
2)读取 /proc/cpuinfo 文件获取逻辑 CPU(processor) 的个数(参见 1.1): processorNum
3)多核情况下该线程的 CPU 使用率 mThreadCPUUse:
mThreadCPUUse = threadCPUUse * processorNum;
2.6、问题
- 1)不同内核版本 /proc/stat 文件格式不一致。/proc/stat 文件中第一行是总的 CPU 使用情况。
- 各个内核版本都有的 4 个字段:user, nice, system, idle;
- 2.5.41 版本新增字段:iowait;
- 2.6.0-test4 版本新增字段:irq, softirq;
- 2.6.11 版本新增字段:stealstolen;
- 2.6.24 版本新增字段:guest;
- 2)/proc/[PID]/task 目录是 Linux 2.6.0-test6 之后才有的功能。
- 3)关于 CPU 使用率为负的情况,解决方案是如果出现负值,连续采样计算 CPU 使用率直到为非负。
- 4)有些线程生命周期较短,可能在采样期间就已经死掉了。
2.7、一个计算总的 CPU 占用率的小程序
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<time.h>
typedefstruct procstat {
char processorName[];
unsignedint user;
unsignedint nice;
unsignedint system;
unsignedint idle;
unsignedint iowait;
unsignedint irq;
unsignedint softirq;
unsignedint stealstolen;
unsignedint guest;
}Procstat;
Procstat getCPUStatus(){
// Get "/proc/stat" info.
FILE* inputFile = NULL;
chdir("/proc");
inputFile = fopen("stat","r");
if(!inputFile){
perror("error: Can not open file.\n");
}
char buff[];
fgets(buff,sizeof(buff), inputFile);// Read 1 line.
printf(buff);
Procstat ps;
sscanf(buff,"%s %u %u %u %u %u %u %u %u %u", ps.processorName,&ps.user,&ps.nice,&ps.system,&ps.idle,&ps.iowait,&ps.irq,&ps.softirq,&ps.stealstolen,&ps.guest);// Scan from "buff".
printf("user: %u\n", ps.user);
fclose(inputFile);
return ps;
}
float calculateCPUUse(Procstat ps1,Procstat ps2){
unsignedint totalCPUTime =(ps2.user + ps2.nice + ps2.system + ps2.idle + ps2.iowait + ps2.irq + ps2.softirq + ps2.stealstolen + ps2.guest)-(ps1.user + ps1.nice + ps1.system + ps1.idle + ps1.iowait + ps1.irq + ps1.softirq + ps1.stealstolen + ps1.guest);
unsignedint idleCPUTime = ps2.idle - ps1.idle;
floatCPUUse=((float) totalCPUTime -(float) idleCPUTime)/(float) totalCPUTime;
printf("totalCPUTime: %u\nidleCPUTime: %u\n", totalCPUTime, idleCPUTime);
returnCPUUse;
}
int main(int argc,char* argv[]){
printf("Test CPU\n");
// Get processor num.
int processorNum = sysconf(_SC_NPROCESSORS_CONF);// "unistd.h" is required.
printf("Processors: %d\n", processorNum);
// Test
Procstat ps1, ps2;
int i =;
for(i =; i <=; i++){
srand((unsigned) time(NULL));
int m = rand()%;
int n =+ rand()%;
int k = m / n;
if(i ==){
ps1 = getCPUStatus();
}
if(i ==){
ps2 = getCPUStatus();
}
}
floatCPUUse= calculateCPUUse(ps1, ps2);
printf("CPUUse: %f\n",CPUUse);
return0;
}
3、Linux 环境查看进程运行相关信息
3.1、使用 ps 命令查看进程信息
几个常用参数:
-
a
: 与终端无关的所有进程。 -
u
: 有效用户(effective user)的相关进程。 -
x
: 通常与 a 参数因使用,可列出较完整的信息。 -
-e
: 选择所有进程。 -
-L
: 显示线程,一般是 LWP 或 NLWP 列。 -
-o
: 用户自定义显示选项。
示例1)列出所有当前所有正在内存中的进程
[root@rh ~]$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 10.00.?SsApr220:/sbin/init
root 20.00.? S Apr220:[kthreadd]
root 30.00.? S Apr220:[migration/]
root 40.00.? S Apr220:[ksoftirqd/]
root 50.00.? S Apr220:[migration/]
root 60.00.? S Apr220:[watchdog/]
root 70.00.? S Apr220:[migration/]
root 80.00.? S Apr220:[migration/]
......
示例2)列出进程号为 13560 这个进程的所有线程及 CPU 占用率
[root@rh ~]$ ps -eLo pid,lwp,pcpu | grep
135601356049.5
3.2、使用 top 命令查看进程信息
几个常用的参数:
-
-d
: 后面接秒数,就是整个进程画面更新的频率。默认是 5 秒。 -
-b
: 以批处理的方式执行 top,还有更多的参数可用。通常会搭配数据流重导向,将批处理的结果输出为文件。 -
-n
: 与 -b 搭配,意义是,需要进行几次 top 的输出结果。 -
-p
: 指定某个 PID 来进行观察监测。 - 在 top 执行过程中可以使用的按键命令:
-
?
: 显示在 top 中可以输入的按键命令。 -
P
: 按照 CPU 的使用资源排序显示。 -
M
: 按内存(Memory)的使用资源排序显示。 -
N
: 按 PID 来排序。 -
T
: 按该进程使用的 CPU 时间积累(TIME+)排序。 -
k
: 给某个 PID 一个信号(signal)。 -
r
: 给某个 PID 重新确定一个值。 -
1
: 显示所有 CPU 占用信息。
示例1)将 top 命令执行两次,然后将结果输出到 /top_result.data
。
[root@rh ~]$ top -b -n >/top_result.data
示例2)监测进程 13620
[root@rh ~]$ top -d -p
top -:: up days,:, users, load average:0.35,0.47,0.44
Tasks: total, running, sleeping, stopped, zombie
Cpu(s):0.1%us,3.1%sy,0.0%ni,96.5%id,0.0%wa,0.0%hi,0.3%si,0.0%st
Mem:16320632k total,1790796k used,14529836k free,233168k buffers
Swap:8232952k total,0k used,8232952k free,941540k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
test1370 R 53.40.:04.78 netperf
本文参考
http://www.blogjava.net/fjzag/articles/317773.html
http://www.brokestream.com/procstat.html