vperf/src/ProcessInfo.c

235 lines
7.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by Iain on 2021/7/17.
//
#include "ProcessInfo.h"
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#define LOG
#define BUFFER_SIZE_PROC_STAT 1024
#define BUFFER_SIZE_PROC_STATUS 128
#define STAT_UTIME 13
#define STAT_STIME 14
#define STAT_VSZ 22
#define STAT_RSS 23
extern Proc_Info Proc_List[LIMIT_PROCESS_NUMBER];
inline void freeProcInfo(Proc_Info *proc) {
int i;
proc->pid = 0;
proc->point = 0;
strcpy(proc->name, "");
for (i = 0; i < UPDATE_FREQUENCY; i++) {
proc->cpuInfo[i].utime = 0;
proc->cpuInfo[i].stime = 0;
proc->memInfo[i].vsz = 0;
proc->memInfo[i].vsz = 0;
}
return;
}
void freeProcInfoList() {
int i;
for (i = 0; i < LIMIT_PROCESS_NUMBER; i++) {
freeProcInfo(&Proc_List[i]);
}
return;
}
int foundProcNode(unsigned int pid) {
int i;
for (i = 0; i < LIMIT_PROCESS_NUMBER; i++) {
if ((Proc_List + i)->pid == pid) {
return i;
}
}
return -1;
}
int foundFreeProcNode() {
int i;
i = foundProcNode(0);
if (i == -1) {
perror("No free procInfo node in procList");
}
return i;
}
int setFreeProcNode(unsigned int pid) {
//found PID name
char buf[BUFFER_SIZE_PROC_STATUS] = {0};
char PID_name[LIMIT_PROCESS_Name_Length] = {0};
char file_path[64] = {0};
sprintf(file_path, "/proc/%d/status", pid);
FILE *fp;
if ((fp = fopen(file_path, "r")) == NULL) {
perror("fail to read /proc/PID/status");
return -1;
}
fgets(buf, BUFFER_SIZE_PROC_STATUS, fp);
#if defined(LOG)
printf("/proc/%d/status: %s", pid, buf);
#endif
sscanf(buf, "Name: %s", PID_name);
//compare PID name with whitelist
//check PID in ProcList
if (foundProcNode(pid) == -1) {
return -1;
}
//found free Proc Node
int i = foundFreeProcNode();
//set Proc Info
Proc_List[i].pid = pid;
strcpy(Proc_List[i].name, PID_name);
}
//unsigned int *getProcess() {
// DIR *dir;
// struct dirent *entry;
// unsigned int id = 0;
// static unsigned int ids[LIMIT_PROCESS_NUMBER] = {0};
//
// if ((dir = opendir("/proc/")) == NULL) {
// perror("cannot access /proc directory");
// exit(-1);
// }
//
// int index = 0;
// int i;
// unsigned int temp;
// while ((direntp = readdir(dirp)) != NULL) {
// id = atoi(direntp->d_name);
// if (id > 0) {
// for (i = 0; i < index; i++) {
// if (ids[i] > id) {
// temp = id;
// id = ids[i];
// ids[i] = temp;
// }
// }
// ids[index] = id;
// index++;
// }
// }
// closedir(dirp);
// return &ids[0];
//}
//update process cpu time and mem info by /proc/PID/stat
//example: 1 (systemd) S 0 1 1 0 -1 4194560 16465 675919 50 519 44 100 678 258 20 0 1 0 13 44421120 1253 18446744073709551615 94869015482368 94869016924823 140724538057904 0 0 0 671173123 4096 1260 1 0 0 17 0 0 0 14 0 0 94869019025816 94869019170360 94869036843008 140724538064796 140724538064863 140724538064863 140724538064863 0
/* pid 进程ID 0
* comm task_struct结构体的进程名
* state 进程状态, 此处为S
* ppid 父进程ID 父进程是指通过fork方式通过clone并非父进程
* pgrp 进程组ID
* session 进程会话组ID
* tty_nr 当前进程的tty终点设备号
* tpgid 控制进程终端的前台进程号
* flags 进程标识位定义在include/linux/sched.h中的PF
* minflt 次要缺页中断的次数,即无需从磁盘加载内存页. 比如COW和匿名页
* cminfl 当前进程等待子进程的minflt
* majflt 主要缺页中断的次数,需要从磁盘加载内存页. 比如map文件
* majflt 当前进程等待子进程的majflt
* utime 该进程处于用户态的时间单位jiffies 13
* stime 该进程处于内核态的时间单位jiffies 14
* cutime 当前进程等待子进程的utime
* cstime 当前进程等待子进程的utime
* priority 进程优先级, 此次等于10.
* nice nice值取值范围[19, -20],此处等于-10
* num_threads 线程个数, 此处等于221
* itrealvalue 该字段已废弃恒等于0
* starttime 自系统启动后的进程创建时间单位jiffies
* vsize 进程的虚拟内存大小单位为bytes 22
* rss 进程独占内存单位pages4K 23
* rsslim rss大小上限
* start_code 该任务在虚拟地址空间的代码段的起始地址
* end_code 该任务在虚拟地址空间的代码段的结束地址。
* start_stack 该任务在虚拟地址空间的栈的结束地址。
* kstkesp esp(32 位堆栈指针) 的当前值, 与在进程的内核堆栈页得到的一致。
* kstkeip 指向将要执行的指令的指针, EIP(32 位指令指针)的当前值。
* pendingsig 待处理信号的位图,记录发送给进程的普通信号。
* block_sig 阻塞信号的位图。
* sigign 忽略的信号的位图。
* sigcatch 被俘获的信号的位图。
* wchan 如果该进程是睡眠状态,该值给出调度的调用点。
* nswap 被swapped的页数当前没用。
* cnswap 所有子进程被swapped 的页数的和,当前没用。
* exit_signal 该进程结束时,向父进程所发送的信号。
* task_cpu 运行在哪个 CPU 上。
* task_rt_priority 实时进程的相对优先级别。
* task_policy 进程的调度策略0=非实时进程1=FIFO实时进程2=RR实时进程
* blio_ticks 等待阻塞IO的时间
* gtime guest time of the task in jiffies
* cgtime guest time of the task children in jiffies
* start_data address above which program data+bss is placed
* end_data address below which program data+bss is placed
* start_brk address above which program heap can be expanded with br
*/
int updateProcInfo(Proc_Info *proc) {
char file_path[64] = {0};
char buffer[BUFFER_SIZE_PROC_STAT] = {0};
sprintf(file_path, "/proc/%d/stat", proc->pid);
FILE *fd = NULL;
fd = fopen(file_path, "r");
if (fd == NULL) {
return -1;
}
unsigned long utime, stime, vsz, rss;
fgets(buffer, BUFFER_SIZE_PROC_STAT, fd);
// 14 utime 15 stime 23 24 vsz rss
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
sscanf(buffer, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu ",
&utime, &stime, &vsz, &rss);
#if defined(LOG)
printf("ProcInfo:PID=%d,Name=%s,utime=%ld,stime=%ld,vsz=%ld,rss=%ld\n", proc->pid, proc->name, utime, stime, vsz,
rss);
#endif
proc->point++;
proc->point %= UPDATE_FREQUENCY;
proc->cpuInfo[proc->point].utime = utime;
proc->cpuInfo[proc->point].stime = stime;
proc->memInfo[proc->point].vsz = vsz;
proc->memInfo[proc->point].rss = rss * 4;
fclose(fd);
return 0;
}
void updateProcList() {
#if defined(LOG)
printf("/****** Proc Info ******/\n");
int i;
for (i = 0; i < LIMIT_PROCESS_NUMBER; i++) {
printf("id=%d,", Proc_List[i].pid);
}
printf("\n");
#endif
setFreeProcNode(1);
setFreeProcNode(101);
char file_path[64] = {0};
int currentProcNode;
for (currentProcNode = 0; currentProcNode < LIMIT_PROCESS_NUMBER; currentProcNode++) {
//check PID
if (Proc_List[currentProcNode].pid != 0) {
if (updateProcInfo(&Proc_List[currentProcNode]) == -1) {
//check path exist
sprintf(file_path, "/proc/%d", Proc_List[currentProcNode].pid);
if (access(file_path, F_OK)) {
freeProcInfo(&Proc_List[currentProcNode]);
}
};
}
}
return;
}