Linux下如何构建一个资源监视器(原理和方法)

对于Linux系统,各种关于系统内核的活动信息都可以在/proc/stat文件中找到,该文件记录了自系统第一次启动以来的所有内核的相关数据,下面对文件内容各字段做一点说明:

这些数字指明了CPU执行不同的任务所消耗的时间(从系统启动开始累计到当前时刻)。时间单位是USER_HZ或jiffies(通常是百分之一秒)。

这些数据列的含义如下,我们从左至右逐一认识:
•user:正常的进程在用户态下执行时间累积
•nice: NICED的进程在用户态下执行时间列
•system:进程在内核态的执行时间累积
•idle:空闲时间累积
•iowait :等待I / O完成时间累积
•irq :硬中断时间
•softirq:软中断时间

"intr":这行给出自系统启动以来的所有中断信息。第一个数字记录所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。

"ctxt":给出了自系统启动以来CPU发生的上下文交换的次数。

"btime":给出了从系统启动到现在为止的时间,单位为秒。

"processes (total_forks)":自系统启动以来所创建的任务的个数目。

"procs_running":当前运行队列的任务的数目。

"procs_blocked":当前被阻塞的任务的数目,等待I/O完成次数。

统计cpu利用率

typedef struct CPU_PACKED
{
	char name[20];
	uint32_t user;
	uint32_t nice;
	uint32_t system;
	uint32_t idle;

}CPU_OCCUPY;

float cal_cpuoccupy(CPU_OCCUPY* o, CPU_OCCUPY* n)
{
	uint64_t od, nd;
	uint64_t id, sd;
	float cpu_use = 0;

	od = (uint64_t)(o->user + o->nice + o->system + o->idle);
	nd = (uint64_t)(n->user + n->nice + n->system + n->idle);

	id = (uint64_t)(n->user - o->user);
	sd = (uint64_t)(n->system - o->system);

	if ((nd - od) != 0)
		cpu_use = (float)((sd + id) * 100) / (nd - od);
	else
		cpu_use = 0;
	return cpu_use;
}

void get_cpuoccupy(CPU_OCCUPY* cpust)
{
	FILE* fd = NULL;
	int n;
	char buf[256];
	CPU_OCCUPY* cpu_occupy;
	cpu_occupy = cpust;

	fd = fopen("/proc/stat", "r");
	if (!fd)
		return;

	fgets(buf, sizeof(buf), fd);
	sscanf(buf, "%s %u %u %u %u", cpust->name, &cpust->user, 
		&cpust->nice, &cpust->system, &cpust->idle);
	fclose(fd);
}

float get_cpurate()
{
	CPU_OCCUPY cpu_stat1 = { 0 };
	CPU_OCCUPY cpu_stat2 = { 0 };
	float cpu = -1;

	// 第一次获取cpu使用情况
	get_cpuoccupy(&cpu_stat1);
	if (!cpu_stat1.user)
		return -1;

	sleep(1);
	//第二次回去cpu使用情况
	get_cpuoccupy(&cpu_stat2);
	if (!cpu_stat2.user)
		return -1;

	//结算使用率
	cpu = cal_cpuoccupy(&cpu_stat1, &cpu_stat2);
	return cpu;
}

更进一步如果需要查看各进程的cpu使用情况那么就需要查看/proc/数字(pid)/stat文件了,原理同上。

统计内存使用情况:

统计内存信息就需要使用/proc/meminfo文件了,下面是该文件的一段截图:

//获取内存相关信息
typedef struct MEM_PACKED
{
	char name[20];
	uint32_t total;
	char anme2[20];
}MEM_OCCUPY;

typedef struct MEM_PACK
{
	float total;
	float used_rate;
}MEM_PACK;

MEM_PACK get_memoccupy()
{
	FILE* fd;
	int n;
	float mem_total, mem_used_rate;
	char buff[256];

	MEM_OCCUPY* mem = (MEM_OCCUPY*)new MEM_OCCUPY;
	MEM_PACK mem_pack;

	fd = fopen("/proc/meminfo", "r");

	memset(buff, 0, sizeof(buff));
	fgets(buff, sizeof(buff), fd);
	sscanf(buff, "%s %lu %s\n", mem->name, &mem->total, mem->anme2);
	mem_total = mem->total;

	fgets(buff, sizeof(buff), fd);

	memset(buff, 0, sizeof(buff));
	fgets(buff, sizeof(buff), fd);
	sscanf(buff, "%s %lu %s\n", mem->name, &mem->total, mem->anme2);
	mem_used_rate = (1 - mem->total / mem_total) * 100;

	mem_pack.total = mem_total;
	mem_pack.used_rate = mem_used_rate;

	fclose(fd);
	delete mem;
}

 获取进程相关的信息:

typedef struct Proc {
	int                 pid;
	int                 ppid;
	int                 uid;
	int                 euid;
	int                 gid;
	char                item_state;
	long                item_cutime;
	long                item_cstime;
	long                item_rss;
	int                 item_threads;
	unsigned long       item_utime;
	unsigned long       item_stime;
	unsigned long long  item_starttime;
	uint64_t            read_bytes;
	uint64_t            write_bytes;
	char                name[4096];
	char                secattr[STRLEN];
} Proc, *Proc_T;

typedef enum {
	ProcessEngine_None = 0x0,
	ProcessEngine_CollectCommandLine = 0x1
} __attribute__((__packed__)) ProcessEngine_Flags;


bool file_readProc(char* buf, int buf_size, char* name, int pid, int* bytes_read) 
{
	if (!buf || !name)
		return false;

	char filename[STRLEN];
	if (pid < 0)
		snprintf(filename, sizeof(filename), "/proc/%s", name);
	else
		snprintf(filename, sizeof(filename), "/proc/%d/%s", pid, name);

	int fd = open(filename, O_RDONLY);
	if (fd < 0) {
		return false;
	}

	bool rv = false;
	int bytes = (int)read(fd, buf, buf_size - 1);
	if (bytes >= 0) {
		if (bytes_read)
			*bytes_read = bytes;
		buf[bytes] = 0;
		rv = true;
	}
	else {
		*buf = 0;
	}

	close(fd);
	return rv;
}

static bool _parseProcPidStat(Proc_T proc) 
{
	char buf[4096];
	char* tmp = NULL;

	if (!file_readProc(buf, sizeof(buf), "stat", proc->pid, NULL)) {
		return false;
	}

	if (!(tmp = strrchr(buf, ')'))) {
		return false;
	}

	*tmp = 0;
	if (sscanf(buf, "%*d (%255s", proc->name) != 1) {
		return false;
	}

	tmp += 2;
	if (sscanf(tmp,
		"%c %d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %ld %ld %*d %*d %d %*u %llu %*u %ld %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n",
		&(proc->item_state),
		&(proc->ppid),
		&(proc->item_utime),
		&(proc->item_stime),
		&(proc->item_cutime),
		&(proc->item_cstime),
		&(proc->item_threads),
		&(proc->item_starttime),
		&(proc->item_rss)) != 9) {

		return false;
	}
	return true;
}

static bool _parseProcPidStatus(Proc_T proc) 
{
	char buf[4096];
	char* tmp = NULL;

	if (!file_readProc(buf, sizeof(buf), "status", proc->pid, NULL)) {
		return false;
	}

	if (!(tmp = strstr(buf, "Uid:"))) {
		return false;
	}

	if (sscanf(tmp + 4, "\t%d\t%d", &(proc->uid), &(proc->euid)) != 2) {
		return false;
	}

	if (!(tmp = strstr(buf, "Gid:"))) {
		return false;
	}

	if (sscanf(tmp + 4, "\t%d", &(proc->gid)) != 1) {
		return false;
	}

	return true;
}

获取磁盘使用情况:

#include <stdio.h>
#include <sys/statvfs.h>

#define SYSTEM_BITS  64
#define PATH "/"
#define KB 1024
#define MB 1024*1024
#define GB  1024*1024*1024

int main(void)
{
	int state;
	struct statvfs vfs;
	fsblkcnt_t block_size = 0;
	fsblkcnt_t block_count = 0;
	fsblkcnt_t total_size;
	fsblkcnt_t free_size;
	fsblkcnt_t used_size;
	fsblkcnt_t avail_size;

	state = statvfs(PATH, &vfs);
	if (state < 0) {
		return 0;
	}

	/* 获取一个block的大小 */
	block_size = vfs.f_bsize;
	/* 获取总容量 */
	total_size = vfs.f_blocks * block_size;
	/* 获取可用容量 */
	free_size = vfs.f_bfree * block_size;
	/* 获取使用容量 */
	used_size = (vfs.f_blocks - vfs.f_bavail) * block_size;
	/* 获取有效容量 */
	avail_size = vfs.f_bavail * block_size;

	printf("total_size	= %0.2lf  GB\n", (double)total_size / (GB));
	printf("free_size	= %0.2lf  GB\n", (double)free_size	/ (GB));
	printf("used_size	= %0.2lf  GB\n", (double)used_size	/ (GB));
	printf("avail_size	= %0.2lf  GB\n", (double)avail_size / (GB));

	return 0;
}

参考:

发布了140 篇原创文章 · 获赞 65 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/paradox_1_0/article/details/103365855