Notice
Recent Posts
Recent Comments
Today
Total
03-28 07:54
Archives
관리 메뉴

Jeongchul Kim

CPU 프로파일링 proc stat python 프로그램 본문

Linux

CPU 프로파일링 proc stat python 프로그램

김 정출 2018. 11. 22. 22:45


CPU 프로파일링 /proc/stat python 프로그램


이번 포스팅에서는 CPU 사용량을 알아보기 위해 /proc/stat을 이용한 방법을 살펴봅시다.

https://www.kernel.org/doc/Documentation/filesystems/proc.txt


/proc/stat

/proc/stat은 cat을 이용해 확인을 해볼 수 있습니다. cpu를 보면 N개의 core가 있다면 0부터 N-1까지 ”cpuN”이 보이실 겁니다. 그리고 cpu는 집계된 정보가 보입니다.


AWS EC2 인스턴스(instance)의 t2.micro는 cpu core 1를 가지고 있어 cpu0가 보입니다.

$ cat /proc/stat


자세히 살펴보죠.

CPU 프로파일리을 보기 위해 우리가 필요한 것은 cpu, cpuN이 되겠습니다.

각 row의 column을 살펴봅시다.


1. user : 유저(user) 모드에서 실행되는 normal 프로세스

2. nice : 유저(user) 모드에서 실행되는 nice 프로세스

- nice는 Unix, Linux와 같은 운영 체제(OS)에서 발생하는 프로그램으로 같은 이름의 커널(kernel) 호출(call)에 직접 매핑되며, 우선 순위를 가진 utility나, 쉘 스크립트(shell script)를 호출하는데 사용되므로, 다른 프로세스보다 CPU 시간을 적절히 제공합니다. niceness에 따라 -20(제일 높은 우선권) 부터 19(제일 낮은 우선권)을 주며, 0을 기본값(default)으로 가지며, 부모 프로세스로 부터 상속 받습니다. 여러 프로세스가 CPU의 양보다 많은 자원을 요구할 때 유용합니다. 우선 순위가 높은 프로세스는 우선 순위가 낮은 프로세스보다 CPU 시간을 할당합니다. https://en.wikipedia.org/wiki/Nice_(Unix)

3. system : 커널(kernel) 모드에서 실행되는 프로세스

4. idle : CPU IDLE 상태 https://en.wikipedia.org/wiki/Idle_(CPU)

5. iowait : I/O가 완료될 때까지 기다리는 시간

- 멀티 core CPU에서는 I/O가 완료될 때까지 기다리는 작업을 CPU에서 실행하지 않기 때문에 각 CPU의 연산을 계산하기 어렵습니다.

- /proc/stat/에 있는 iowait 필드의 값은 특정 상황에서 감소됩니다.

- 이에 따라 /proc/stat/에 있는 iowait을 신뢰하기 힘듭니다.

6. irq : IRQ(Interrupt request) 인터럽트(interrupt) 요청은 실행 중인 프로그램을 일시적 중단하고 Interrupt를 처리할 수 있도록 프로세서(processor)에 보내는 하드웨어 신호입니다. https://en.wikipedia.org/wiki/Interrupt_request_(PC_architecture)

7. softirq

8. steal : involuntary wait

9. guest : 실행 중인 normal guest

- virtual CPU에서 실행되는 hypervisor

10. guest_nice : 실행 중인 nice guest


CPU 사용량

자 이제 CPU 사용량(%)를 구해봅시다.

https://github.com/hishamhm/htop/blob/e0209da88faf3b390d71ff174065abd407abfdfd/ProcessList.c


htop source 코드를 살펴봅시다.


// Guest time is already accounted in usertime
usertime = usertime - guest;  # As you see here, it subtracts guest from user time
nicetime = nicetime - guestnice;  # and guest_nice from nice time
// Fields existing on kernels >= 2.6
// (and RHEL's patched kernel 2.4...)
idlealltime = idletime + ioWait;  # ioWait is added in the idleTime
systemalltime = systemtime + irq + softIrq;
virtalltime = guest + guestnice;
totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;


수식적으로 위의 코드를 이용해 계산할 수 있습니다.

CPU 사용량의 %를 구하기 위해 이전 시간(previous : p로 표기)과 현재시간(current : c로 표기)의 /proc/stat 의 값들이 필요합니다.


previous_idle  = p_idle + p_iowait
current_idle = c_idle + c_iowait

previous_non_idle = p_user + p_nice + p_system + p_irq + p_softirq + p_steal
current_non_idle = c_user + c_nice + c_system + c_irq + c_softirq + c_steal

previous_total = previous_idle + previous_non_idle
current_total = current_idle + current_non_idle

diff_total = current_total - previous_total
diff_idle = current_idle - previous_idle

cpu_usage_percentage = diff_total - diff_idle / diff_total


결론적으로 정리하면 이전과 현재의 /proc/stat에서 guest와 guest_nice를 제외한 모든 column의 값에서 user + nice + system + irq + softirq + steal의 비율을 계산한 값입니다.


python 코드를 살펴보시죠.

https://github.com/KimJeongChul/linux_resource_profiling/blob/master/cpu_profiling.py


#!/usr/bin/python
import sys
import math

실제 cpu_workload 함수에 workload code를 작성해주시면 될 것 같습니다.

저는 math 라이브러리를 이용해 cosin, sin, square root를 구하여 cpu에 작업을 할당했습니다.


def cpu_workload(N):
   # Define CPU Workload
   # EXAMPLE math library
   for i in range(0, N):
       cos_i = math.cos(i)
       sin_i = math.sin(i)
       sqrt_i = math.sqrt(i)

get_cpu_time 함수는 /proc/stat 을 읽어와  split으로 분리하고 dictionary에 idle_time(idle+iowait)과 total(user+nice+system+irq+softirq+ steal + idel_time)을 저장하여 리턴합니다.


def get_cpu_time():
   cpu_infos = {}
   with open('/proc/stat', 'r') as file_stat:
       """
       cpu : user nice system idle iowait irq softirq steal guest guest_nice
       cpu0 : ...
       idle_time = idle + iowait
       non_idle_time = user + nice + system + irq + softirq + steal
       total = idle_time + non_idle_time
       previous_total = previous_idle + previous_non_idle
       current_total = current_idle + current_non_idle
       diff_total = current_total - previous_total
       diff_idle = current_idle - previous_idle
       cpu_usage_percentage = ( diff_total - diff_idle )/ diff_total * 100
"""
       cpu_lines = []
for lines in file_stat.readlines():
           for line in lines.split('\n'):
               if line.startswith('cpu'):
                   cpu_lines.append(line.split(' '))
for cpu_line in cpu_lines:
           if '' in cpu_line :
               cpu_line.remove('') # First row(cpu) exist '' and Remove ''
           cpu_id = cpu_line[0]
           cpu_line = [float(item) for item in cpu_line[1:]]
           user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice = cpu_line

           idle_time = idle + iowait
           non_idle_time = user + nice + system + irq + softirq + steal
           total = idle_time + non_idle_time

           cpu_infos.update({cpu_id : {'total' : total, 'idle' : idle_time }})
   return cpu_infos

get_cpu_usage_percentage 함수는 workload 시작 전과 시작 후를 가져와 percentage를 계산하여 리턴합니다.


def get_cpu_usage_percentage():
   start = get_cpu_time()
   cpu_workload(10 ** 6)
   end = get_cpu_time()

   cpu_usages = {}
   for cpu in start:
       diff_total = end[cpu]['total'] - start[cpu]['total']
       diff_idle = end[cpu]['idle'] - start[cpu]['idle']
       cpu_usage_percentage = (diff_total - diff_idle) / diff_total * 100
cpu_usages.update({cpu : cpu_usage_percentage})
   return cpu_usages

def main():
   result = get_cpu_usage_percentage()
   print(result)


if __name__ == '__main__':
   main()


여기까지 cpu profiling 하는 법이 될 것 같습니다.


AWS EC2 t2.micro 에서 실행 시 다음과 같습니다.


AWS EC2 m5.xlarge 에서 실행 시 다음과 같습니다. python이 multi-threading을 고려한 병렬 처리 프로그래밍이 아니기 때문에 하나의 core에서만 100% 사용되는 것을 볼 수 있습니다.


이상으로 포스팅을 마치겠습니다.



'Linux' 카테고리의 다른 글

Ubuntu 1604 opencv install  (0) 2017.06.08
Linux 14.04 Tensorflow GPU Install  (0) 2017.06.08
Linux 14.04 OpenCV2 Install  (0) 2017.06.08
CentOS7 OpenStack in WINDOW 10 Virtual Box  (0) 2016.11.29
BSD Socket - server & multi-client file transfer  (0) 2016.11.22
Comments