Linux系统资源使用情况监控任务的计算方法-Linux基础
Linux系统资源使用情况监控
任务目标
在基于Linux系统的主机上,对主机运行状态进行监控linux系统内存查询命令,评判终端负载情况。相当于简单的系统资源管理器功能。该设计目标是实现对:
(1)CPU占用率
(2)系统运行时长
(3)显存占用率
(4)网路插口属性
(5)网卡速度信息
的监控。
CPU占用率
我们通过读取/proc/stat文件获取当前系统的CPU占用率。
/proc文件系统
proc是一个只存在显存当中的伪文件系统。它以文件系统的方法为内核与进程提供通讯的插口。用户和应用程序可以通过/proc得到动态的从系统内核读出的系统的信息,并可以改变内核的个别参数。
/proc/stat
/proc/stat包含了系统启动以来的许多关于kernel和系统的统计信息,其中包括CPU运行情况、中断统计、启动时间、上下文切换次数、运行中的进程等等信息。虽然,/proc/stat反映的就是CPU总的占用时间,如右图所示。
[CPU指标]:user,nice,system,idle,iowait,irq,softirq
第一行内容表示总的CPU信息,假如主机有多核,会有多个CPU0~n;
CPU借助率的估算
CPU借助率分为用户态,系统态和空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间linux查看磁盘空间,和空闲系统进程执行的时间。平常所说的CPU借助率是指:CPU执行非系统空闲进程的时间/CPU总的执行时间。
1.定义CPU信息结构体linux系统内存查询命令,用于储存各模式下的CPU使用时间。
typedef struct _CPU_PACKED { char name[16]; unsigned int user; //用户模式 unsigned int nice; //低优先级的用户模式 unsigned int system; //内核模式 unsigned int idle; //空闲处理器时间 } CPU_OCCUPY;
2.打开/proc/stat文件,借助sscanf函数读取须要的数据。
fd = fopen("/proc/stat", "r"); if (fd == NULL) { perror("open /proc/stat failedn"); exit(0); } fgets(buff, sizeof(buff), fd); sscanf(buff, "%s %u %u %u %u", cpu->name, &cpu->user, &cpu->nice, &cpu->system, &cpu->idle); fclose(fd);
估算方式:
t1:第一次采集(用户+优先级+系统+空闲)的时间过一段时间,ex:sleep(1);t2:第二次(用户+优先级+系统+空闲)的时间user:用户模式第一次和第二次的时间之差system:系统第一次和第二次的时间之差
显存、运行时长
Linux中,sysinfo是拿来获取系统相关信息的结构体。
具体定义如下:
通过sysinfo函数获取上述结构体信息。
int ret = 0; ret = sysinfo(&info); if (ret != 0) { perror("get sys_info failedn"); exit(0); }
定义主机状态信息结构体(如下),以保存主机的时长、使用率信息。
typedef struct _HOST_STATE{ int hour; int minute; double cpu_used; double mem_used ; }HOST_STATE;
系统运行时间
通过uptime参数获取
显存借助率
通过totalram、freeram参数获取
网路插口属性ifreq、ifconf结构体
ifreq结构定义在/usr/include/net/if.h,拿来配置ip地址,激活插口,配置MTU等插口信息的。其中包含了一个插口的名子和具体内容——(是个共用体,有可能是IP地址,广播地址,子网网段linux应用程序,MAC号,MTU或其他内容)。
ifreq包含在ifconf结构中。而ifconf结构一般是拿来保存所有插口的信息的。
网卡插口名称、MAC地址、IP地址就保存于以下数组中。通过ifconf结构体我们可以获取到本机当前所有活动网卡的相关属性。
/proc/net/dev
/proc/net/dev文件就是提供给用户读取或修改网路适配器及统计信息的途径
interface:插口的名子Receive:表示收包Transmit:表示收包bytes:表示收发的字节数
为了储存网卡相关信息,定义如下结构体。
同时采用数组结构动态储存网卡统计信息,以实现获取本机上的所有网卡设备。
typedef struct _NET_INTERFACE { char name[16]; char ip[16]; double d_speed; double u_speed; char mac[13]; unsigned char speed_level; struct _NET_INTERFACE *next; } NET_INTERFACE;
网速估算
定义RTX_BYTES结构体用于储存网卡特定时刻的收分包情况。
typedef struct _RTX_BYTES { long int tx_bytes; long int rx_bytes; struct timeval rtx_time; } RTX_BYTES;
通过打开/proc/net/dev文件,按行读取可获得各网卡当前时刻总的收分包信息。程序示例如下。
open_netconf(&net_dev_file); //获取时间 gettimeofday(&rtx->rtx_time, NULL); //从第三行开始读取网络接口数据 while ((read = getline(&line, &bytes_read, net_dev_file)) != -1) { if ((++i) <= 2) continue; if (strstr(line, name) != NULL) { memset(str1, 0x0, 32); memset(str2, 0x0, 32); sscanf(line, "%*s%s%*s%*s%*s%*s%*s%*s%*s%s", str1, str2); rtx->tx_bytes = atol(str2); rtx->rx_bytes = atol(str1); #if DEBUG printf("name:%8st tx:ldtrx:ldn", name, rtx->tx_bytes, rtx->rx_bytes); #endif } } fclose(net_dev_file);
网速的估算同CPU借助率估算一样,都须要通过两次采集,统计特定时间间隔内的信息来估算。
估算方式:
t1:当前时刻收分包字节数bytes1过一段时间,ex:sleep(1);t2:当前时间收分包字节数bytes2
程序示例:首先回来两次采集的间隔时长,再通过收分包字节数估算上下行网速。
long int time_lapse; time_lapse = (rtx1->rtx_time.tv_sec * 1000 + rtx1->rtx_time.tv_usec / 1000) - (rtx0->rtx_time.tv_sec * 1000 + rtx0->rtx_time.tv_usec / 1000); *d_speed = (rtx1->rx_bytes - rtx0->rx_bytes) * 1.0 / (1024 * time_lapse * 1.0 / 1000); *u_speed = (rtx1->tx_bytes - rtx0->tx_bytes) * 1.0 / (1024 * time_lapse * 1.0 / 1000);
程序流程
项目中共设计两个线程分别采集网速信息、CPU&显存&运行时长信息。整体流程如下。
main函数展示:
int nums = 0; //网卡结构体指针初始化 p_interface = (NET_INTERFACE *)malloc(sizeof(NET_INTERFACE)); //获取本机网卡数量 get_interface_info(&p_interface, &nums); printf("net_interface nums: %dn", nums); show_netinterfaces(p_interface, 0); //创建两个线程 pthread_t thread_net_id, thread_core_id; //线程1:网络信息监控线程 pthread_create(&thread_net_id, NULL, (void *)thread_net, NULL); //线程2:CPU、内存信息监控 pthread_create(&thread_core_id, NULL, (void *)thread_core, NULL);
结果展示
终端可持续实时输出CPU、内存、运行时间,网卡IP、MAC、上下行速度信息。
再与本机的监控软件信息对比,证明输出结果可信。
监控软件显示的CPU、内存使用信息:
输出本机网卡信息:
完整的项目地址github
gitee