net-snmp를 통해 시스템 정보 및 실행중인 프로세스의 상태정보 얻어오고자 한다.
간단하게 구현하려고 perl로 만들어 보았으나 cpu를 3~5%나 잡아 먹는다.
2초 간격으로 클라이언트가 정보를 받아가므로 상당한 부하가 예상된다.
net-snmp에 기본적으로 설치되는 ucd-snmp(1.3.6.1.4.1.2021)를 수정해서 사용해야겠다.
우선 각종 시스템 정보 및 프로세스의 상태정보 얻기....
시스템의 cpu사용률 구하는 것은 쉬우나 임의의 프로세스 cpu사용률 구하는건 어렵다.
UCD-SNMP-MIB도 수정했으니 이제 snmpd 소스를 고쳐보자...os별로 언제 다 고쳐..orz ㅜㅜ
일단 리눅스만....>.,<
"수요일에 데모한다는데 언제 할래? 언제 할래? 언제 할래?"
[시스템 상태 및 프로세스별 cpu, mem usage 구하기]
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define KERNEL_BLOCK_SIZE 512
struct cpudata
{
unsigned long user, system, idle, nice, total;
};
struct proc_cpudata
{
unsigned long userproc, systemproc, vmem, rmem;
char pname[255];
};
struct netdata
{
unsigned long tx, rx;
};
struct diskdata
{
unsigned long disk_read, disk_write;
};
/* Get CPU data *//*{{{*/
void get_cpu_stat(struct cpudata *cpu)
{
FILE *file;
char temp[10];
char line[255];
/* CPU */
file = fopen("/proc/stat", "r");
fgets(line, 255, file);
fclose(file);
sscanf(line, "%s %lu %lu %lu %lu", temp, &cpu->user, &cpu->nice, &cpu->system,
&cpu->idle);
cpu->total = cpu->user + cpu->system + cpu->idle + cpu->nice;
}/*}}}*/
/* Get disk-related information *//*{{{*/
void get_disk_stat(struct diskdata *disk, char *diskname)
{
FILE *file;
unsigned long itemp;
char temp[255];
char line[255];
file = fopen("/proc/diskstats", "r");
if (!file)
{
fprintf(stderr, "Error: Disk usage statistics supported for 2.6 kernels only for now.\n");
}
else
{
while (!feof(file))
{
fgets(line, 255, file);
sscanf(line, "%d %d %s %lu %lu %lu %lu %lu %lu %lu",
(int*)&itemp, (int*)&itemp, temp, &itemp, &itemp, &disk->disk_read,
&itemp, &itemp, &itemp, &disk->disk_write);
if (!strncmp(temp, diskname, strlen(diskname)) &&
(strlen(temp) == strlen(diskname)))
{
break;
}
}
fclose(file);
}
}/*}}}*/
/* Get process-related information *//*{{{*/
void get_proc_cpu_stat(struct proc_cpudata *proc, int pid)
{
FILE *file;
unsigned long itemp;
char ctemp;
char line[255];
sprintf(line, "/proc/%d/stat", pid);
file = fopen(line, "r");
if (file == NULL)
{
fprintf(stderr, "Error: process (pid %d) not found!\n", pid);
exit(1);
}
fgets(line, 255, file);
fclose(file);
sscanf(line, "%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu "
"%ld %ld %ld %ld %ld %ld %lu %lu %ld",
(int*)&itemp, proc->pname, &ctemp, (int*)&itemp, (int*)&itemp, (int*)&itemp, (int*)&itemp, (int*)&itemp,
&itemp, &itemp, &itemp, &itemp, &itemp, &proc->userproc, &proc->systemproc,
&itemp, &itemp, &itemp, &itemp, &itemp, &itemp, &itemp, &proc->vmem, &proc->rmem
);
}/*}}}*/
/* Get network stats *//*{{{*/
void get_net_stat(struct netdata *net, char *interface)
{
FILE *file;
unsigned long itemp;
char temp[10];
char line[255];
file = fopen("/proc/net/dev", "r");
fgets(line, 255, file);
fgets(line, 255, file);
while (!feof(file))
{
int i;
fgets(line, 255, file);
strncpy(temp, line, 6);
sscanf(line + 7, "%lu %lu %lu %lu %lu %lu %lu %lu %lu", &net->rx,
&itemp, &itemp, &itemp, &itemp, &itemp,
&itemp, &itemp, &net->tx);
for (i=0; i < 6; i++)
if (temp[i] != ' ') break;
if (!strncmp(temp + i, interface, strlen(interface)))
break;
else
net->rx = net->tx = 0;
}
fclose(file);
}/*}}}*/
int childended = 0;
void quit(int nothing)
{
childended = 1;
}
int main(int argc, char **argv, char **env)
{
int ch;
struct cpudata oldcpu, cpu;
struct proc_cpudata oldproc, proc;
struct netdata oldnet, net;
struct diskdata initdisk, olddisk, disk;
char *progname = strdup(argv[0]);
unsigned long timer;
unsigned long disk_in = 0, disk_out = 0;
unsigned long disk_tx_read = 0, disk_tx_write = 0;
float maxuload = 0, maxsload = 0, maxpuload = 0, maxsuload = 0, usertime = 0, systemtime = 0;
int pid;
unsigned long maxrx = 0, maxtx = 0;
float time = 0;
char *interface=NULL, *diskname=NULL;
signal(SIGCHLD, quit);
while ((ch = getopt(argc, argv, "i:n:d:v")) != -1)
{
switch (ch)
{
/* Enable cache */
case 'i': timer = atoi(optarg); break;
case 'n': interface = strdup(optarg); break;
case 'd': diskname = strdup(optarg); break;
case 'v':
printf("System Monitor\n"
"Copyright, (C) Eugeni Dodonov, 2004-2005.\n"
"Version $Id: monitor.c,v 1.4 2005/09/11 03:15:44 eugeni Exp $.\n"
"Distributed under GPL license.\n\n");
exit(0);
default:
fprintf(stderr, "Invalid flag %c!\n", (char)optopt);
break;
}
}
argc -= optind;
argv += optind;
if (argc < 1)
{
fprintf(stderr, "Usage: %s [-i interval] [-n net] [-d disk] <pid>|<command>\n", progname);
exit(1);
}
if (timer <= 0)
timer = 1000000;
if (!interface)
interface = strdup("eth0");
if (!diskname)
diskname = strdup("hda");
pid = atoi(argv[0]);
/* Fork and exec *//*{{{*/
if (pid <= 0)
{
/* Program */
char *command;
char **params;
int i;
command = strdup(argv[0]);
params = (char **)malloc((argc) * sizeof(char*));
for (i=0; i < argc; i++)
{
params[i] = (char *)malloc(strlen(argv[i]));
strncpy(params[i], argv[i], strlen(argv[i]));
}
pid = fork();
if (pid < 0)
{
perror("fork");
exit(1);
}
if (pid == 0)
{
execve(command, params, env);
perror("execve");
exit(1);
}
}/*}}}*/
/* CPU */
get_cpu_stat(&oldcpu);
/* DISK */
get_disk_stat(&olddisk, diskname);
initdisk = olddisk;
/* PROC */
get_proc_cpu_stat(&oldproc, pid);
/* Network */
get_net_stat(&oldnet, interface);
while (!childended)
{
unsigned long in, out, maxvmem;
float uload, sload, procuload, procsload;
usleep(timer);
/* CPU */
get_cpu_stat(&cpu);
uload = (float) ((cpu.user - oldcpu.user) * 100) / (cpu.total - oldcpu.total);
sload = (float) ((cpu.system - oldcpu.system) * 100) / (cpu.total - oldcpu.total);
time += ((float)timer / 1000000);
/* DISK */
get_disk_stat(&disk, diskname);
disk_tx_read = disk.disk_read - olddisk.disk_read;
disk_tx_write = disk.disk_write - olddisk.disk_write;
disk_in = disk.disk_read - initdisk.disk_read;
disk_out = disk.disk_write - initdisk.disk_write;
olddisk = disk;
/* PROC */
get_proc_cpu_stat(&proc, pid);
usertime = (float)proc.userproc / 100;
systemtime = (float)proc.systemproc / 100;
/* Network */
get_net_stat(&net, interface);
in = net.rx - oldnet.rx;
out = net.tx - oldnet.tx;
oldnet = net;
/* Format and process acquired data */
if ((proc.userproc == oldproc.userproc) || (cpu.user == oldcpu.user))
procuload = 0.0;
else
{
procuload = ((float)(proc.userproc - oldproc.userproc) / (float)(cpu.user - oldcpu.user) * 100);
procuload *= uload / 100;
}
if ((proc.systemproc == oldproc.systemproc) || (cpu.system == oldcpu.system))
procsload = 0.0;
else
{
procsload = ((float)(proc.systemproc - oldproc.systemproc) / (float)(cpu.system - oldcpu.system) * 100);
procsload *= sload / 100;
}
if (procuload > 100) procuload = 100;
if (procsload > 100) procsload = 100;
if (procuload > maxpuload) maxpuload = procuload;
if (procsload > maxsuload) maxsuload = procsload;
if (uload > maxuload) maxuload = uload;
if (sload > maxsload) maxsload = sload;
if (in > maxrx) maxrx = in;
if (out > maxtx) maxtx = out;
if (proc.vmem > maxvmem) maxvmem = proc.vmem;
oldproc = proc;
oldcpu = cpu;
printf("<Stats pname=\"%s\" pid=\"%d\" time=\"%.1f\" usertime=\"%.1f\" "
"systemtime=\"%.1f\" procuserload=\"%.1f\" maxprocuserload=\"%.1f\" "
"procsysload=\"%.1f\" masprocsysload=\"%.1f\" userload=\"%.1f\" "
"maxuserload=\"%.1f\" systemload=\"%.1f\" maxsystemload=\"%.1f\" "
"vmem=\"%lu\" maxvmem=\"%lu\" rmem=\"%lu\" bytesin=\"%lu\" maxbytesin=\"%lu\" "
"bytesout=\"%lu\" maxbytesout=\"%lu\" "
"disk_throughput_read=\"%lu\" disk_throughput_write=\"%lu\" "
"disk_bytes_read=\"%lu\" disk_bytes_write=\"%lu\" "
"/>\n",
proc.pname, pid,
time, usertime, systemtime, procuload, maxpuload, procsload, maxsuload, uload, maxuload,
sload, maxsload, proc.vmem, maxvmem, proc.rmem, in, maxrx, out, maxtx,
disk_tx_read * KERNEL_BLOCK_SIZE, disk_tx_write * KERNEL_BLOCK_SIZE, disk_in * KERNEL_BLOCK_SIZE, disk_out * KERNEL_BLOCK_SIZE);
fflush(stdout);
}
return 0;
}