이 문서는 리눅스(:12) 운영체제(:12)를 기준으로 작성될 것이다.
리눅스 운영체제에서 시스템정보를 얻는 방법은 아래의 문서를 통해서 여러번 설명되었다. 아래의 proc 파일시스템 분석관련 문서를 읽었다면, 어렵지 않게 CPU 사용율을 측정하는 프로그램을 만들 수 있을 것이다.
2. 공유:::라이브러리(:12) 형태로 만들어진다.
3. 만들어진 모듈은 PlugIn 방식으로 동적으로 로딩될 수 있다.
Cpu 사용율은 /proc/stat 파일을 분석해서 얻어올 수 있다. 분석을 통해서 얻어올 수 있는 정보는 kernel(:12) 2.4와 2.6에 약간의 차이가 있다. 여기에서는 커널 2.4를 기준으로 설명할 것이다. 커널 2.6이라고 해도, 필드 하나가 더 추가된 것일 뿐이니, 코드를 수정하는데에는 전혀 문제가 없을 것이다. 약간의 시간을 더 투자한다면, 커널 2.4와 2.6 모두에서 작동할 수 있는 코드를 만들 수도 있을 것이다.
복잡하지 않은 코드이니 주석으로 설명을 대신하겠다.
// Standard C++ Library
#include <iostream>
// Common Library
#include <cinterface.h>
// Standard C Library
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#define K4 0
#define K6 1
using namespace std;
int isTotal=0;
int findCpu=0;
int GetCpuNum();
int Type = 0;
struct _CpuStat
{
unsigned int User;
unsigned int System;
unsigned int Idle;
};
struct _CpuStat CpuStat[2];
char *rtvstr;
int Init()
{
GetCpuNum();
rtvstr = (char *)malloc(80);
return 1;
}
int cidx = 0;
// CPU 갯수를 얻어온다.
int GetCpuNum()
{
FILE *fp;
fp = fopen("/proc/stat", "r");
char buf[80];
isTotal=0;
findCpu=0;
if (fp == NULL)
{
return 0;
}
while(fgets(buf, 80, fp))
{
if (strncmp(buf, "cpu", 3) != 0)
{
continue;
}
if (isdigit(buf[3]))
{
findCpu++;
}
else
{
isTotal = 1;
}
}
fclose(fp);
return 1;
}
// Cpu 갯수를 리턴한다.
int NumRows()
{
return findCpu;
}
// proc 파일시스템을 분석해서 Cpu 사용율 정보를 얻어온다.
// /proc/stat 의 사용율 총합라인만 읽어올 것이다.
char *Read()
{
FILE *fp;
char buf[80];
fp = fopen("/proc/stat", "r");
char cpuid[8];
int nused;
if (fp == NULL)
{
return NULL;
}
while(fgets(buf, 80, fp))
{
if (!strncmp(buf, "cpu", 3))
{
sscanf(buf, "%s %d %d %d %d",
cpuid,
&CpuStat[cidx%2].User,
&nused,
&CpuStat[cidx%2].System,
&CpuStat[cidx%2].Idle
);
break;
}
}
// 처음실행했다면, 1초를 쉰다음 재귀호출 한다.
if (!cidx)
{
sleep(1);
cidx++;
*Read();
}
cidx++;
int diff1;
int diff2;
int diff3;
int Idle, System, User;
diff1 = CpuStat[(cidx+1)%2].User - CpuStat[(cidx)%2].User;
diff2 = CpuStat[(cidx+1)%2].System - CpuStat[(cidx)%2].System;
diff3 = CpuStat[(cidx+1)%2].Idle - CpuStat[(cidx)%2].Idle;
Idle = (diff3*100)/(diff1+diff2+diff3);
System = (diff2*100)/(diff1+diff2+diff3);
User = (diff1*100)/(diff1+diff2+diff3);
sprintf(rtvstr,"CPU=%d,%d,%d\n", User,System,Idle);
return rtvstr;
}
int Clean()
{
if (rtvstr != NULL)
free(rtvstr);
rtvstr = NULL;
return 1;
}
최종목적은 PlugIn 형태로 Agent에서 로딩하고, 그 결과를 Manager에게 보내는 것이겠지만, 그건 나중일이고 일단 main 함수를 포함한 간단한 코드를 만들어서 테스트를 해보기로 했다. 얻어낸 Cpu 정보는 RRD(:12) 형태로 저장해서, 그래프로 출력할 것이다. 이를 위해서 다음과 같이 RRD 데이터베이스를 생성했다.
Contents
소개
모듈화
- 공통 인터페이스를 가지며,
2. 공유:::라이브러리(:12) 형태로 만들어진다. 3. 만들어진 모듈은 PlugIn 방식으로 동적으로 로딩될 수 있다. Cpu 사용율은 /proc/stat 파일을 분석해서 얻어올 수 있다. 분석을 통해서 얻어올 수 있는 정보는 kernel(:12) 2.4와 2.6에 약간의 차이가 있다. 여기에서는 커널 2.4를 기준으로 설명할 것이다. 커널 2.6이라고 해도, 필드 하나가 더 추가된 것일 뿐이니, 코드를 수정하는데에는 전혀 문제가 없을 것이다. 약간의 시간을 더 투자한다면, 커널 2.4와 2.6 모두에서 작동할 수 있는 코드를 만들 수도 있을 것이다. 복잡하지 않은 코드이니 주석으로 설명을 대신하겠다.// Standard C++ Library #include <iostream> // Common Library #include <cinterface.h> // Standard C Library #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <ctype.h> #define K4 0 #define K6 1 using namespace std; int isTotal=0; int findCpu=0; int GetCpuNum(); int Type = 0; struct _CpuStat { unsigned int User; unsigned int System; unsigned int Idle; }; struct _CpuStat CpuStat[2]; char *rtvstr; int Init() { GetCpuNum(); rtvstr = (char *)malloc(80); return 1; } int cidx = 0; // CPU 갯수를 얻어온다. int GetCpuNum() { FILE *fp; fp = fopen("/proc/stat", "r"); char buf[80]; isTotal=0; findCpu=0; if (fp == NULL) { return 0; } while(fgets(buf, 80, fp)) { if (strncmp(buf, "cpu", 3) != 0) { continue; } if (isdigit(buf[3])) { findCpu++; } else { isTotal = 1; } } fclose(fp); return 1; } // Cpu 갯수를 리턴한다. int NumRows() { return findCpu; } // proc 파일시스템을 분석해서 Cpu 사용율 정보를 얻어온다. // /proc/stat 의 사용율 총합라인만 읽어올 것이다. char *Read() { FILE *fp; char buf[80]; fp = fopen("/proc/stat", "r"); char cpuid[8]; int nused; if (fp == NULL) { return NULL; } while(fgets(buf, 80, fp)) { if (!strncmp(buf, "cpu", 3)) { sscanf(buf, "%s %d %d %d %d", cpuid, &CpuStat[cidx%2].User, &nused, &CpuStat[cidx%2].System, &CpuStat[cidx%2].Idle ); break; } } // 처음실행했다면, 1초를 쉰다음 재귀호출 한다. if (!cidx) { sleep(1); cidx++; *Read(); } cidx++; int diff1; int diff2; int diff3; int Idle, System, User; diff1 = CpuStat[(cidx+1)%2].User - CpuStat[(cidx)%2].User; diff2 = CpuStat[(cidx+1)%2].System - CpuStat[(cidx)%2].System; diff3 = CpuStat[(cidx+1)%2].Idle - CpuStat[(cidx)%2].Idle; Idle = (diff3*100)/(diff1+diff2+diff3); System = (diff2*100)/(diff1+diff2+diff3); User = (diff1*100)/(diff1+diff2+diff3); sprintf(rtvstr,"CPU=%d,%d,%d\n", User,System,Idle); return rtvstr; } int Clean() { if (rtvstr != NULL) free(rtvstr); rtvstr = NULL; return 1; }#include <qoscpu.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <time.h> // Read 로 읽어온, Cpu Usage 정보는 배열에 저장한다. // 저장은 5초단위로 5분동안이며, 배열의 크기는 60이 된다. // 저장된 값은 5분단위로 평균을 내기 위해서 사용된다. class CircleQueue { private: int User[60]; int System[60]; int Idle[60]; int idx; int size; public: CircleQueue() { idx = 0; size = 0; memset((void *)User, 0x00, sizeof(int)*60); memset((void *)System, 0x00, sizeof(int)*60); memset((void *)Idle, 0x00, sizeof(int)*60); } void Push(int aUser, int aSystem, int aIdle) { User[idx] = aUser; System[idx] = aSystem; Idle[idx] = aIdle; idx++; if (idx == 60) idx = 0; size++; } int Length() { if (size > 59) return 60; else return size; } int GetSystem(int index) { return System[index]; } int GetUser(int index) { return User[index]; } int GetIdle(int index) { return Idle[index]; } }; // Daemon(:12) 프로세스로 만든다. int MakeDaemon() { pid_t pid; if ((pid = fork()) < 0) { exit(0); } else if (pid != 0) exit(0); setsid(); return 1; } int main() { char *str; char *sp; CircleQueue *Cqueue; int sum; int User, System, Idle; Cqueue = new CircleQueue(); int idx = 1; char command[256]; MakeDaemon(); if (!Init()) perror("Error"); while(1) { str = Read(); sp = strstr(str, "="); User = atoi(sp+1); sp = strstr(sp+1, ","); System = atoi(sp+1); sp = strstr(sp+1, ","); Idle = atoi(sp+1); Cqueue->Push(User, System, Idle); sleep(5); idx++; User = 0; System = 0; Idle = 0; if (!(idx % 60)) { printf("Size %d\n", Cqueue->Length()); sum = 0; for(int i = 0; i < Cqueue->Length(); i++) { User += Cqueue->GetUser(i); System += Cqueue->GetSystem(i); } Idle = User+System; sprintf(command, "rrdtool update /rrd/cpuusage.rrd %d:%d:%d:%d", time((time_t *)NULL), User/Cqueue->Length(), System/Cqueue->Length(), Idle); system(command); } } return 0; }RRD를 이용한 데이터 관리
6 시간 통계
24시간 통계
Recent Posts
Archive Posts
Tags