C/G/S/P states

  • intel_idle과 관련된 내용을 다루기에 앞서 P-States와 C-States에 대해서 간단히 정리
  • Intel 아키텍처 환경에서 리눅스 커널과 CPU를 알아가다보면 P/S/G/C States에 대한 학습 필요

1. P-States

  • P-States는 작업 부하에 따라서 CPU의 전압과 클럭주파수를 조절하는 정도를 정의 한 값
  • 명령어 처리(Operation)상태를 기준으로 절전 및 성능 향상을 꾀하기 위한 기법
  • 과거에는 SpeedStep이라는 기술로 소개 되었지만 정확히 같은 것은 아님
  • P-States는 단순히 클럭주파수를 조절해서 에너지 절약을 위한 방안으로만 치부되었는데 CPU가 연산처리를 할 때의 상태를 반영
  • 최근 사용되는 Intel CPU의 Turbo Boost 상태는 P-State 0(P0)를 의미

2. C-States

  • C-States는 CPU 내부의 특정 부분이 활성화되거나 낮은 성능 상태로 실행될지를 반영하는 값
  • CPU에서 사용중이 아닌 부분들을 비활성화하여 전원의 효율화를 높이기 위한 상태 값
  • P-State와 다르게 C-State는 유휴(Idle)상태를 기준으로하여 평가
  • C0는 활성화된 일반적인 상태를 의미하며, C0 상태에서 P0~Pn 상태로 나누어서 볼 수 있음
  • Nehalem Microarchitecture(네할램)부터는 C6 상태가 추가되었는데 C6는 각종 작업들을 저장하고 이미 작동을 멈춘 CPU 코어에 공급되는 전원을 차단하는 상태
  • Sandy Bridge Microarchitecture(샌디브리지)에서 C7이 추가되었고 이는 C6에서 추가로 L3캐시까지 비워버린(Flush) 상태를 의미

3. G-States

  • Global States를 의미
  • 사용자가 인지할 수 있는 상태를 반영
  • G0는 동작상태 (전원 On)
  • G1은 잠자기모드 상태
  • G3는 전원 Off 상태

4. S-States

  • Sleep States를 의미
  • G1에서 세부적인 잠자기모드 상태를 나타냄

5. Processor Power States → 상태들을 알아보기 쉽게 도식화


intel_idle → Idle 상태를 관리

  • C-States와 관련이 있는 모듈
  • intel_idle이 사용되기 이전에는 C-States를 OS에서 관리하기 위해서 acpi_idle이란 모듈이 사용
  • 기존 acpi_idle 모듈의 경우 C-State latency와 관련하여 정확도도 높지 않았고 기본적으로 BIOS 설정에 따라서 주어진 환경 내에서만 상태를 변경하는 정도로 효과 X
  • intel_idle의 경우 BIOS 설정에 직접적으로 개입하여 C-State를 조절하는 모듈
  • 서버시스템의 경우 빠른 응답속도를 목표로하기 때문에 소위 Performance 모드로 통칭되는 BIOS 설정상태를 유지하여 CPU가 잠들지 않도록 하는 설정하였지만, C-State를 커널이 개입하여 CPU 상태를 제어해 버리면 성능에 문제가 있을 수 있음
  • 하드웨어에서 Performance이지만 커널에서 C6으로 C-State가 설정되어있으면 C6 상태에 있던 CPU가 C0 상태로 만들기 위한 시간(Wake-up time)이 소모되어 성능 저하 발생
  • intel_idle 모듈 설정을 통해 BIOS 설정과 무관하게 커널의 C-State를 조절 필요

Idel 상태 관리 방법

  • intel_idle.max_cstate 파라미터를 통해 C-State의 상태를 결정하거나 비활성화하여 apci_idle 사용가능
  • 커널 부팅 파라미터에 intel_idle.max_cstate=0 값을 설정하면 apci_idle을 사용하여 하드웨어의 C-State로 부팅
  • 커널파라미터의 경우 rebooting의 부담이 있기 때문에 기존에 운영하는 장비도 적용 할 수 있도록 tuned의 profile을 이용한 설정

1.커널 매개 변수로 intel_idle.max_cstate=0을 적용

  • grub 파일을 쓰고 있다면, /etc/default/grub 파일에 intel_idle.max_cstate=0를 설정한 후 설정 적용(재부팅 가능)

  • GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rhgb quiet" 항목에 intel_idle.max_cstate=0 추가

    # /etc/default/grub 파일 수정
    $ vi /etc/default/grub
    GRUB_TIMEOUT=5
    GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
    GRUB_DEFAULT=saved
    GRUB_DISABLE_SUBMENU=true
    GRUB_TERMINAL_OUTPUT="console"
    
    # 변경 전 내용 : GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rhgb quiet"
    # 아래 변경 후 내용
    GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rhgb quiet intel_idle.max_cstate=0"
    GRUB_DISABLE_RECOVERY="true"
    
    # /etc/default/grub 파일 적용
    $ grub2-mkconfig -o /boot/grub2/grub.cfg
    $ reboot

※ 참고

  • 재부팅 후 intel_idle이 정상적으로 적용되었는지 확인 필요
    $ dmesg | grep -i intel_idle

2. tuned의 profile의 latency-performance의 profile을 이용한 설정

  • tuned의 profile 중 latency-performance의 profile을 통해 커널파라미터의 경우 리부팅의 부담을 줄이고 C-state 변경 작업 적용
  • 아래 결과를 통해 C7 상태까지 떨어지던 idle 상태가 C1이하로 내려가지 않는 것 확인
    $ tuned-adm profile latency-performance
  • latency-performance 적용 전
  • latency-performance 적용 후

3. E3/E5 계열(샌디브리지)의 CPU는 바로 적용이 되었으나 C6까지있는 네할렘 CPU에는 바로 적용 불가

  • 실제 장비들을 샘플링하여 테스트 해 본 결과 tuned-adm을 설정하더라도 E3/E5 계열(샌디브리지)의 CPU는 바로 적용이 되었으나 C6까지있는 네할렘 CPU들은 적용 불가
  • 네할렘 CPU에 C6은 계속 출력되는 것 확인
  • /dev/cpu_dma_latency 장치(4바이트 값을 갖는 장치)에 직접 latency 값을 100으로 설정
    $ exec 3> /dev/cpu_dma_latency
    $ echo -ne '\0144\000\000\000' >&3
  • 네할렘 CPU에 C3까지 출력되는 것 확인 → /dev/cpu_dma_latency 변경 확인

※ 아래 참조한 자료는 RHEL6 버전으로 RHEL7을 확인 필요

  1. 참조 URL : https://lunatine.net/2015/01/06/rhel6-intel_idle-and-c-states/
  2. 리눅스 ( Tuned 데몬을 이용한 OS 튜닝) 튜닝 참고 URL : http://justinsona.blogspot.com/2016/11/tuned-os.html

P-State란

  • P-State는 시스템이 동작하는 동안, CPU의 클럭 주파수를 조절하여 어느 정도의 Performance로 CPU를 작동시킬 것인지 결정
  • Intel의 X86 프로세서에서 P-State 기능을 SpeedStep이라는 이름으로 사용
  • 리눅스는 P-State 기능을 "/sys/devices/system/cpu/cpu#/cpufreq/" 에 존재하는 파일을 이용하여 조절
  • P-State는 시스템의 클럭수를 조절하여 동적으로 전체 시스템의 전력 소모를 조절
  • CPU P-State는 Performace 상태로 정의된 voltage-frequency 제어 상태를 나타냄
  • voltage-frequency 제어에서 회로를 구동하는 전압(voltage)과 클록(clock)은 작업 부하에 따라 증가하거나 감소함
  • 운영 체제는 현재 작업 부하(workload)를 기반으로 특정 P-State를 요청
  • 프로세서는 요청을 수락하거나 거부하고, 자체 상태를 기반으로 P-State를 설정 가능
  • P-State는 프로세서가 지원하는 frequency와 수집 기간 동안 각 frequency에서 소요된 시간을 나타냄
  • P-State에서는 SpeedStep, Speed Shift가 CPU의 클럭을 관리

 

P-State 핵심

  • P-State가 CPU frequency를 떨어뜨려서 전력 소모를 줄이는 방법
  • CPU 사용량이 적을때 CPU 코어의frequency를 떨어뜨려서 적은 voltage으로 CPU를 동작할 수 있게 하기 위해 사용
  • CPU 코어 frequency와 voltage를 미리 정의 → 요청사항이 많을 때는 최대 frequency로 설정, 요청사항이 적은 때는 낮은 frequency로 동작
  • Intel 계열 CPU에서는 SpeedStep이라는 이름을 사용

  • Linux 상에서 cpufreq라는 인터페이스를 통해서 SpeedStep 기능 제어 → CPU frequency governor는 cpufreq로 frequency 결정
    1. cpufreq_performance → 전력은 많이 소비하지만 항상 최대의 성능으로 동작
    2. cpufreq_powersave → 최대한 전력을 아끼는 방법으로 동작
    3. cpufreq_ondemand → 주파수의 범위를 정해주고 부하 상황에 맞게 가변적으로 동작

 

P-State(active) 상태의 전원 관리

1. 스피트스텝(SpeedStep)

  • 스피드 스텝 기술은 P-State를 제어하는 기술
  • 인텔에서 개발한 기술
  • CPU에 걸린 부하에 따라서 자동으로 클럭을 조절해주는 기술
  • 배터리 소모량을 유연하게 조절하여 사용시간을 늘려주는 장점이 있지만, 클럭 조정시에 일시적으로 버벅임이 발생 가능
  • SpeedStep의 주요 통제권은 OS가 가지고 있음

  • 스피트스텝(SpeedStep) 작동원리
    1. 오피스 소프트웨어 이용하여 문서작업 등 비교적 부하가 낮게 걸리는 작업에서 CPU의 속도를 고의로 낮추어 작동
    2. HD급 동영상 재생 등 부하가 심하게 걸리는 작업에서는 CPU의 속도를 낮추지않는 방식으로 작동

 

2. 스피드 쉬프트(Speed Shift)

  • 스카이레이크 마이크로 아키텍쳐를 가진 CPU 이후부터는 스피드 스텝을 하드웨어 단에 적용한 스피드 시프트 기술이 적용
  • 베이스 클럭에서부터 터보 부스트 영역까지 확장된 기술
  • 마이크로프로세서 안의 PCU(Power Control Unit)이라는 하드웨어가 밀리초 단위로 정해진 알고리즘에 따라 계산하면서 최적의 CPU 클럭과 전압으로 관리
  • 스피드 쉬프트 기술을 이용하려면 OS에서 지원을 해야 사용 가능
  • 스피드 시프트를 지원하지 않는 OS에서는 스피드 스텝으로 작동
  • Speed Shift는 Speedstep과 달리 OS가 CPU 제어권을 대부분 PCU1에 넘겨 CPU의 클럭을 유동적으로 조절
  • Speedstep과 비교하여 하드웨어적인 방식을 사용하기 때문에, CPU 클럭 제어 속도가 빨라졌고, 더욱 정밀한 클럭 계산이 가능해져 더 적은 에너지를 사용
  • Speedstep이 20~30ms에 걸쳐 최대 클럭을 올릴 때, SpeedShift는 5~7ms만에 최대 클럭까지 도달 → 최대 50% 더 빠른 변속을 보여줌
  • Speedstep과 Speed Shift는 동시에 적용 X

 

CPU frequency governor 이란

  • CPU는 여러 주파수에서 동작이 가능하도록 설계되어 있으나, 리눅스 커널 대부분의 cpufreq 드라이버들은 CPU를 하나의 주파수로 설정
  • CPU의 사용량이 많지 않으면 저속으로 많아지면 고속으로 동작할 필요가 있음
  • 동적 주파수 확장을 제공하기 위해서 타겟 주파수를 드라이버에 알려줄 것이 필요가 있음
  • CPU frequency governor는 CPUfreq policy내에서 무슨 주파수를 사용할 것인지 결정
  • CPUfreq policy는 주파수 제한과 사용될 governor로 구성
  • DB 서버에 CPUfreq policy가 활성화되어 있다면 CPU 주파수가 떨어질 때 쿼리 응답 속도가 갑자기 늘어난다던가 하는 이슈가 발생 가능

1. governor 종류

  1. Performance→ CPU를 최고 주파수로 설정
  2. Powersave→ CPU를 최저 주파수로 설정
  3. OnDemand→ 현재 사용량에 따라 CPU frequnecy를 설정. CPU는 주파수를 빠르게 변경할 능력이 필요

 

2. 현재 설정된 governors 확인

$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
powersave

 

3. 사용가능한 설정

$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
performance powersave

 

4. governors 변경 → /sys/devices/system/cpu/ -> cpu[n] n 수만큼 다 변경해야함

# 먼저 CPU 개수 확인
$ cat /proc/cpuinfo | grep -i "^processor"
processor       : 0
processor       : 1
processor       : 2
processor       : 3
processor       : 4
processor       : 5
processor       : 6
processor       : 7
processor       : 8
processor       : 9
processor       : 10
processor       : 11
processor       : 12
processor       : 13
processor       : 14
processor       : 15
processor       : 16
processor       : 17
processor       : 18
processor       : 19
processor       : 20
processor       : 21
processor       : 22
processor       : 23
processor       : 24
processor       : 25
processor       : 26
processor       : 27
processor       : 28
processor       : 29
processor       : 30
processor       : 31
processor       : 32
processor       : 33
processor       : 34
processor       : 35
processor       : 36
processor       : 37
processor       : 38
processor       : 39

$ echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
$ echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
$ echo performance > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor
#.... 중략....
$ echo performance > /sys/devices/system/cpu/cpu39/cpufreq/scaling_governor

 

 

CPU 및 다양한 모드와 관련된 C 상태에 대한 설명

  • CPU는 유휴 상태일 때 에너지를 절약하기 위해 CPU에 저전력 모드를 시작하도록 명령 가능
  • CPU는 여러 전력 모드를 종합적으로 "C-State" 또는 "C-Mode"라고 칭함
  • 최근에는 CPU의 전력 소비를 줄일 수 있도록 향상 → C-State는 CPU의 기능을 하나씩 종료시켜서 전력 소모를 줄임
  • CPU 내부의 유휴 장치에서 클록 신호와 전원을 차단하면 작동 → 클록을 차단하고 전압을 줄이거나 완전히 종료하여 더 많은 장치를 중지할수록 더 많은 에너지가 절약
  • C-state는 보다 공격적인 방법으로 전력소모를 최소화하여 절전모드에 주로 사용
  • CPU가 절전 모드에서 완전히 "해제"되는 데 더 많은 시간이 발생
  • C-State는 C0에서 시작 → 정상 CPU 작동 모드(100% CPU 활성화)
  • C 번호가 클수록 CPU 절전 모드가 더 길게 설정 → 즉, 더 많은 회로와 신호가 꺼져 있고 CPU가 C0 모드로 완전히 해제되는 데 더 많은 시간이 걸림
  • 각 C-State에는 이름 有 → 몇 개에는 절전 수준과 해제 시간이 각각 다른 하위 모드가 존재
  • 최근에는 C7 기술이 추가되었는데 이는 최종적으로 남아있는 L3 공유 캐시까지 작동을 멈춰, DDR3 메모리나 PCI-Express 연결과 관련된 전력도 차단

 

현재 사용 가능한 모든 C-State 모드 요약본

  • C1~C3 모드는 CPU의 클록 신호를 차단하면 작동
  • C4~C6 모드는 CPU 전압을 줄이면 작동
  • "향상된" 모드는 동시에 모두 실행 가능

 

C-states 상태

 

※ 주의 → 전력관리 기술 적용에 따라 성능 저하 발생 가능

  • CPU의 C-State 기술은 전력의 효율성을 높이기 위한 전력관리 기술들의 기반
  • CPU의 C-State 기술은 CPU 자체의 클럭이나 전압을 크게 낮추고 대기모드에 들어가는 작업을 행함
  • CPU의 클럭이나 전압을 줄여 소비전력을 줄이는 단계로 진입했다 다시 기본 클럭으로 돌아오는 과정에서의 지연이나 기본클럭 및 전압이 복귀되지 못하는 등으로 CPU 성능이나 그래픽카드 등의 성능이 저하 가능
  • CPU의 경우 전력관리 기능의 버그로 인해 성능이 제대로 나타나지 못하는 문제들이 종종 발생
  • C-state 레벨에 따라 코어 내부 클럭이 중단되거나 L1/L2 캐시 Flush 및 Off 시키는 등의 동작이 발생
  • 레벨이 높아질수록 많은 컴포넌트들이 꺼짐으로써 전력 소모량은 줄지만, 그에 비례해서 정상 상태(C0)로 복귀하는데 더 많은 리소스와 시간이 소요되는 문제
  • DB 서버에서 발생했던 connect timeout 현상의 원인 역시 높은 레벨의 C-states 상태에서 정상 상태(C0)로 복귀하면서 DB 접속(정확히는 네트워크 연결) 과정에 지연이 발생

 

 

  • turbostat 명령어는 X86 프로세서의 프로세서 topology, frequency, idle 전력 상태 통계, 온도 및 전력을 출력
  • turbostat 명령어는 전체 시스템의 카운터 결과 요약을 출력하고 제목 아래에 각 카운터 결과를 5 초마다 출력
  • turbostat 명령어는 kernel-tools 패키지에서 제공
  • 전력 사용량이나 유휴 시간이 비효율적인 서버 식별 가능
  • 시스템에서의 시스템 관리 인터럽트(SMI)의 비율 식별 가능
  • 전력 관리 튜닝 효과 확인

 

옵션

1. --Dump 옵션

  • raw 카운터 값을 표시

2. --debug 옵션

  • 추가 시스템 구성 정보를 표시
  • 내부 터보 스탯 디버그 정보가 활성화됨

3. --interval [seconds] 옵션

  • --interval 옵션 뒤에 seconds 값을 통해 출력되는 값을 설정
  • default 값은 5.0초

4. --out [output_file] 옵션

  • Turbostat 출력은 지정된 output_file에 기록
  • 파일이 이미 존재하면 잘리고 존재하지 않으면 생성

5. --Summary 옵션

  • 각 간격에 대해 출력을 1줄 시스템 요약으로 제한

 

turbostat 명령어 실행 결과

$ turbostat
Package Core    CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     SMI     POLL    C1      C1E     C6      POLL%   C1%     C1E%    C6%     CPU%c1  CPU%c6  CoreTmp PkgTmp  PkgWatt RAMWatt PKG_%   RAM_%
-       -       -       0       0.05    810     2195    2285    0       0       580     140     1364    0.00    0.57    0.40    98.98   2.96    97.00   41      43      41.72   39.62   0.00    0.00
0       0       0       0       0.05    801     2195    40      0       0       0       2       37      0.00    0.00    0.01    99.94   0.78    99.17   37      39      21.61   21.51   0.00    0.00
0       0       20      0       0.02    805     2195    30      0       0       0       2       20      0.00    0.00    0.01    99.97   0.82

 

출력 필드 설명

필드명 설명
usec
  • 각 CPU에 대해 카운터 수집 중 경과된 시간(마이크로초)
  • 기본적으로 비활성화
  • --enable usec 또는 --debug로 활성화 가능
Time_Of_Day_Seconds
  • 각 CPU 별 gettimeofday(2) 값
  • 측정 종료 시 시간
  • 기본적으로 비활성화
  • --enable Time_Of_Day_Seconds 또는 --debug로 활성화 가능
Core
  • 프로세서 코어 번호
CPU
  • Linux CPU 번호
Package
  • 프로세서 패키지 번호
  • 패키지란 두 개 이상의 독립 코어를 단일 집적 회로로 이룰 때 사용
Avg_MHz
  • 평균 클럭 속도
  • 실행된 사이클 수를 경과 시간으로 나눈 값
Busy%
  • CPU가 명령을 실행하는 시간(백분율)
Bzy_MHz
  • CPU가 idel 상태가 아닌 동안의 평균 클럭 속도
TSC_MHz
  • TSC가 실행 된 평균 MHz
  • TSC는 Time Stamp Counter의 약어
  • CPU 차원에서 제공되는 카운터
  • CPU가 리셋된 이후 동작한 CPU 사이클의 수
IRQ
  • 측정 주기 동안 CPU가 처리한 인터럽트 수
  • /proc/interrupts 이용
SMI
  • 측정 주기 동안 CPU를 지원하는 SMI 인터럽스 수
  • CPU 단위 이지만 모든 프로세서에서 SMI가 트리거 되기 때문에 모든 CPU 값이 동일해야 함
  • SMI는 System Management Interrupts의 약어
C1, C2, C3...
  • 측정 주기 동안 C1, C2, C3 idle 상태를 요구한 횟수
  • c0: CPU가 켜져 있고 미작동 상태
  • c1: 자동 정지, 프로세서가 명령을 수행 하지는 않지만 실행 상태로 즉각 돌아갈 수 있음
  • c2: 스톱 클럭, 프로세서는 몯믄 소프트웨어 표시 상태를 유지 하지만 깨우기에 시간이 더 걸림
  • c3: 딥 슬립, 프로세서는 캐시의 일관성을 유지할 필요 없지만 다른 상태 유지 관리
  • c4: 더 깊은 슬립, VCC 감소, VCC ==> main cpu voltage(전압)
  • dc4: 더 깊은 c4 슬립 VCC 감소
%c1, %c2, %c3
  • 프로세서가 C1, C2, C3 상태였던 비율
CPU%c1, CPU%c2,
CPU%c3
  • 각 idle 상태로 있는 비율
  • H/W residency counter에서 획득 한 값
CoreTmp
  • Core 당 디지털 열 세선에 의해 보고 된 섭씨 온도
PkgTtmp
  • 패키지 당 패키지 열 모니터에 의해 보고 된 섭씨 온도
GFX%rc6
  • 측정 주기 동안 GPU가 렌더링 c6 상태에 있는 시간(백분율)
  • /sys/class/drm/card0/power/rc6_residency_ms 에서 획득
GFXMHz
  • 측정이 끝날 시점의 sysfs의 스냅샷
  • /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz 에서 획득
Pkg%pc2, Pkg%pc3,
Pkg%pc6, Pkg%pc7
  • H/W 패키지 idle 상태 비율(백분율)
  • H/W residency counter에서 획득
PkgWatt
  • 전체 패키지에서 소비한 전력량(Watt)
CorWatt
  • 패키지의 core에서 소비한 전력량(Watt)
GFXWatt
  • 패키지의 그래픽 부분에서 소비한 전력량(Watt)
  • 클라이언트 프로세서에서만 사용 가능
RAMWatt
  • DRAM DIMMS에서 소비한 전력량(Watt)
  • 서버 프로세서에서만 사용 가능
PKG_%
  • RAPL throttling이 패키지에서 활성화 된 비율
  • RAPL는 Running Average Power Limit의 약어
RAM_%
  • RAPL throttling이 DRAM에서 활성화 된 비율

 

 

※ 참고

1. SMI (System Management Interrupt)

  • SMI를 통해 하드웨어가 트리거됨
  • 프로세서 칩에 물리적 핀(Pin)이 있음
  • SMI (System Management Interrupt)를 활성화되면 프로세서가 SMM으로 들어가게됨

 

2. gettimeofday(2) 함수

  • 1970-01-01 00:00:00 +0000 (UTC) 이후의 현재까지의 경과된 초와 micro초(백만분의 1초) 값을 얻는 함수
  • 정밀한 시간 정보가 필요한 경우에 사용
  • tz(timezone) 정보는 사용하지 않으므로 무시됨

 

  • 서버용으로 사용되는 시스템의 관리자는 어떤 사용자가 언제 로그인했는지 확인
  • last 명령어는 로그인 로그와 로그 아웃 로그를 확인 가능

last 명령어로 알 수 있는 정보

  1. 접속계정명
  2. 접속장치명
  3. 접속한 IP주소
  4. 접속시간
  5. 시스템 재부팅 정보

last 명령어를 통해 특정 정보 추출

1. 최근 접속정보

$ last
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:11   still logged in
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:01 - 23:10  (00:08)
root     pts/0        [서버 시스템 IP]    Mon Jun 21 22:37 - 22:37  (00:00)

2. 사용자 접속 정보

# root 사용자 접속 정보 -> 개별 사용자가 있는 경우를 제외하고 root로 접속하는 기록 출력
$ last root
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:11   still logged in
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:01 - 23:10  (00:08)
root     pts/0        [서버 시스템 IP]    Mon Jun 21 22:37 - 22:37  (00:00)

# reboot 사용자 접속 정보 -> rebooting한 기록 확인
$ last reboot
reboot   system boot  3.10.0-1160.6.1. Fri Jan 15 14:10 - 12:56 (11+22:46)
reboot   system boot  3.10.0-1160.6.1. Fri Jan 15 13:58 - 14:09  (00:11)
reboot   system boot  3.10.0-1160.6.1. Fri Jan 15 13:22 - 13:56  (00:34)

3. 지정일자 이전에 접속한 정보

# 지정일자 이전에 접속한 정보
# last -t YYYYMMDDHHMMSS 형식
$ last -t 20201210000000           # 20201210일 이전의 접속 기록만 출력
root     pts/0        [서버 시스템 IP]    Wed Dec  9 17:38 - 17:43  (00:04)
root     pts/0        [서버 시스템 IP]    Wed Dec  9 16:33 - 17:36  (01:03)
root     pts/0        [서버 시스템 IP]    Tue Dec  8 22:46 - 22:51  (00:05)

4. 원하는 행의 수만큼 출력

$ last -n 3
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:24   still logged in
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:11 - 23:22  (00:11)
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:01 - 23:10  (00:08)

wtmp begins Sat Dec  5 04:17:18 2020

5. IP주소를 제외한 정보

$ last -R
root     pts/0        Mon Jun 21 23:24   still logged in
root     pts/0        Mon Jun 21 23:11 - 23:22  (00:11)
root     pts/0        Mon Jun 21 23:01 - 23:10  (00:08)
root     pts/0        Mon Jun 21 22:37 - 22:37  (00:00)

6. IP주소를 열의 마지막에 출력

$ last -a
root     pts/0        Mon Jun 21 23:24   still logged in    [서버 시스템 IP]
root     pts/0        Mon Jun 21 23:11 - 23:22  (00:11)     [서버 시스템 IP]
root     pts/0        Mon Jun 21 23:01 - 23:10  (00:08)     [서버 시스템 IP]
root     pts/0        Mon Jun 21 22:37 - 22:37  (00:00)     [서버 시스템 IP]

7. 외부 접속 정보만을 출력

$ last -d
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:24   still logged in
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:11 - 23:22  (00:11)
root     pts/0        [서버 시스템 IP]    Mon Jun 21 23:01 - 23:10  (00:08)
root     pts/0        [서버 시스템 IP]    Mon Jun 21 22:37 - 22:37  (00:00)

  • 리눅스에서는 서버에 접속실패 정보와 접속정보를 기록

접속 실패 로그 확인 → btmp

  • ssh 접속 시도 실패 로그는 /var/log/btmp 파일에 특수하게 저장

  • /var/log/btmp는 바이너리 파일로 이루짐

  • /var/log/btmp 파일을 보기 위해서는 last -f 명령을 이용하여 확인 가능

  • lastb 명령어는 last -f /var/log/btmp와 동일한 결과 출력

    $ last -f /var/log/btmp
    root     ssh:notty    [시스템 IP]    Tue May 25 03:07 - 09:57  (06:50)
    root     ssh:notty    [시스템 IP]    Tue May 25 03:07 - 03:07  (00:00)
    root     ssh:notty    [시스템 IP]    Tue May 25 00:52 - 03:07  (02:15)
    
    $ lastb
    lastb
    root     ssh:notty    [시스템 IP]    Tue May 25 03:07 - 03:07  (00:00)
    root     ssh:notty    [시스템 IP]    Tue May 25 03:07 - 03:07  (00:00)
    root     ssh:notty    [시스템 IP]    Tue May 25 00:52 - 00:52  (00:00)



접속정보 기록 확인 → wtmp

  • 성공한 로그인/로그아웃 정보 및 시스템의 boot/shutdown의 히스트리 정보를 파일로 저장
  • /var/log/wtmp는 바이너리 파일로 이루짐
  • /var/log/wtmp 파일을 보기 위해서는 last -f 명령을 이용하여 확인 가능
  • last 명령어는 last -f /var/log/wtmp와 동일한 결과 출력
    $ last -f /var/log/wtmp
    root     pts/0        [시스템 IP]    Mon Jun 21 23:11   still logged in
    root     pts/0        [시스템 IP]    Mon Jun 21 23:01 - 23:10  (00:08)
    root     pts/0        [시스템 IP]    Mon Jun 21 22:37 - 22:37  (00:00)
    root     pts/0        [시스템 IP]    Mon Jun 21 22:31 - 22:36  (00:05)


시스템에 현재 로그인한 사용자들에 대한 상태 정보 → utmp

  • 로그파일은 binary 파일로 되어 있어 직접 확인 불가능 → 아래 명령어로 확인 가능
  • 로그파일 확인 명령어 : w, who, finger

1. w 명령어

  • utmp를 참조하여 출력
  • 현재 시스템에 성공적으로 로그인한 사용자정보, 시스템로드 정보 및 uptime 정보 출력
    $ w
    23:34:07 up 145 days, 10:36,  1 user,  load average: 0.00, 0.01, 0.05
    USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
    root     pts/0      [시스템 IP]        23:24    7.00s  0.06s  0.02s w

2. who 명령어

  • utmp를 참조하여 출력
  • 현재 시스템에 성공적으로 로그인한 사용자의 정보와 접속한 Client IP를 출력
    $ who
    root     pts/0        2021-06-21 23:24 ([시스템 IP])

3. finger 명령어

  • 사용자 계정 정보와 최근 로그인 정보, 이메일, 예약 작업 정보 등을 볼 수 있는 명령어

  • yum install finger -y로 finger 명령어 설치

    # finger 패키지가 없는 경우 다운 필요
    $ yum install -y finger
    
    # root 사용자 계정 정보 확인
    $ finger root
    Login: root                               Name: root
    Directory: /root                        Shell: /bin/bash
    On since Mon Jun 21 23:24 (KST) on pts/0 from [시스템 IP]
     4 seconds idle
    New mail received Tue May 25 03:08 2021 (KST)
       Unread since Sat Jan 30 21:53 2021 (KST)
    No Plan.



lastlog 명령어

  • 각 사용자들이 언제 마지막으로 접속하였는가를 확인
  • /etc/passwd 파일에 정의되어 있는 모든 사용자들의 마지막 접속정보를 확인
  • lastlog는 /var/log/lastlog 파일의 정보를 출력

1. /etc/passwd 파일에 정의된 모든 사용자의 마지막 접속 정보 확인

$ lastlog
Username         Port     From             Latest
root               pts/0    [시스템 IP]    Mon Jun 21 23:24:25 +0900 2021
bin                                               **Never logged in**
daemon                                        **Never logged in**
[...생략...]

2. 사용자의 마지막 접속 정보

# lastlog -u userid
$ lastlog -u root
Username         Port     From             Latest
root             pts/0    [시스템 IP]    Mon Jun 21 23:48:26 +0900 2021

3. N일 이전에 접속한 정보

# lastlog -b N -> N일 이후에 접속한 기록이 있는 사용자는 제외
$ lastlog -b 10
Username         Port     From             Latest
bin                                            **Never logged in**
daemon                                     **Never logged in**
[...생략...]

4. D일 부터 현재까지 접속한 정보

# lastlog -t D
$ lastlog -t 5
Username         Port     From             Latest
root             pts/0    [시스템 IP]    Mon Jun 21 23:48:26 +0900 2021

  • 기본적으로 캐시를 생각하면, 빠르게 읽기 위해서 사용하는 저장공간으로 생각
  • 캐시는 쓰기 명령을 수행할 때도 사용 → 아래의 그림처럼 캐시에 Write Buffer라는 걸 두어서 쓰기 성능 향상에 사용
  • Write Buffer는 CPU가 쓰기 명령 수행 중에 좀 더 효율적으로 다른 일을 할 수 있도록 해줌
  • 쓰기 버퍼 방식은 크게 두 가지가 존재 → Write Through와 Write Back

Write Through

  • Write Through라는 용어는 쓰루 패스와 마찬가지로 Memory에 뭔가를 쓰기 명령을 수행할 때, Cache와 Memory 값을 일치 시켜주는 방식
  • CPU가 주기억장치(RAM) 또는 디스크(Disk)로 데이터를 기입하고자 할 때 데이터는 먼저 캐시로 기입 → 데이터가 캐시 됨과 동시에 주기억장치(RAM) 또는 디스크(Disk)로 업데이트하는 구조
  • 데이터 로스의 리스크가 있으면 안되는 상황에서는 Write Through를 사용하는 것이 바람직

Write Through 장점

  • 캐시와 메모리에 업데이트를 같이 하여, 데이터 일관성을 유지할 수 있어서 안정적
  • inconsistency(불일치)현상이 발생 X

Write Through 단점

  • 속도가 느린 주기억장치 또는 디스크로 동시에 데이터를 기록
  • 완료될 때까지 CPU가 대기하는 시간이 필요하기 때문에 성능이 떨어짐

Write Through를 사용하여 데이터를 처리하는 구조


Write Back

  • CPU 데이터를 사용할 때 데이터는 먼저 캐시로 기록되는데, 캐시 내에 일시적으로 저장된 후에 블록 단위에 캐시로부터 해제되는 때(캐시안에 있는 내용을 버릴시) 에만 주기억장치 또는 보조기억장치에 기록되는 방식
  • 데이터를 쓸 때 메모리에는 쓰지 않고 캐시에만 업데이트를 하다가 필요할 때에만 주기억장치나 보조기억장치에 기록하는 방법
  • 데이터 로스의 리스크를 조금 감수하더라도 빠른 서비스를 요하는 상황에서는 Write Back을 사용하는 것이 바람직

Write Back 장점

  • Write Through보다 훨씬 빠름

Write Back 단점

  • 속도가 빠른 대신에 캐시에 업데이트 하고 메모리에는 바로 업데이트를 하지 않기 때문에 캐시와 메모리가 서로 값이 다른 경우가 발생 가능
  • inconsistency(불일치)
  • 캐시에만 써놓고 Device에 값을 안넘기는 경우가 발생하여서 문제 발생 가능
  • Write Back 문제를 해결하기 위하여 Cache Flush 또는 Cache clean을 사용

Write Back을 사용하여 데이터를 처리하는 구조

※ 참조

  • Cache Flush는 Cache Invalidate(캐시 무효화)로 Cache 안의 내용을 마치 Reset하듯이 정리함
  • Cache Clean은 Cache에 있던 내용을 Memory에도 update해줌

Write Back과 Write Through의 성능 차이가 큼(데이터 베이스 로드 처리량 비교)


  • 프로세스에서 중요한 요소 → VIRT, RES, SHR
  • 현재 프로세스가 사용하고 있는 메모리와 관련된 값
  • 프로세스는 task를 의미

VIRT → task가 사용하는 virtual memory의 전체 용량을 의미

  • 프로세스에 할당된 가상 메모리 전체의 크기
  • VIRT는 프로그램이 현재 얼마나 많은 메모리를 접근할 수 있는지를 출력
  • VIRT는 물리 메모리의 사용한 공간을 의미하지는 않음
  • VIRT = SWAP + RES
  • VIRT는 실제로는 할당되지 않은 가상의 공간(swap)이기 때문에 VIRT의 해당 값이 크다고 해도 문제되지는 않음

1. VIRT의 Memory Commit

  • 프로세스가 커널로부터 사용을 예약 받은 메모리 → 프로세스는 malloc()과 같은 시스템 콜로 자신이 필요로 하는 메모리의 영역을 할당해 줄것을 요청
  • 프로세스가 요청한 내용은 커널이 가용할 수 있는 공간이 있다면 성공 메시지와 함께 해당 프로세스가 사용할 수 있도록 가상의 메모리 주소를 전달
  • malloc을 통해 할당 받은 가상 메모리는 물리 메모리에 해당 영역이 할당된 상태는 아님

2. VIRT의 malloc 테스트 코드 → malloc_test.c 파일을 생성

$ vi malloc_test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

# define MEGABYTE 1024*1024

int main(){
    void *myblock = NULL;
    int count = 0;

    while(1){
        myblock = (void *) malloc(MEGABYTE);
        if(!myblock){
            printf("Error!");
            break;
         }
        printf("Currently allocating %d MB\n", (++count)*MEGABYTE);
        sleep(1);
    }
    exit(0);
}

# malloc_test 파일을 malloc_test 실행 파일로 만듦
$ gcc -o malloc_test malloc_test.c
$ ls -al
-rwxr-xr-x  1 root root 8520 Oct 11 17:53 malloc_test
-rw-r--r--  1 root root  395 Oct 11 17:47 malloc_test.c

3. VIRT의 malloc 테스트 실행 결과

  • malloc() 으로 메모리 영역을 요청한 후에 아무것도 하지 않음

  • top 명령으로 해당 프로세스의 변화 확인 → 시간이 지나면서 VIRT는 계속해서 높아지지만, RES는 늘어나지 않음

    # 위에서 생성한 malloc_test 실행파일 실행
    $ ./malloc_test
    Currently allocating 1 MB
    Currently allocating 2 MB
    Currently allocating 3 MB
    Currently allocating 4 MB
    Currently allocating 5 MB
    # [...생략...]
    
    # 다른 터미널로 해당 내용 확인
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   33000    348    276 S   0.0  0.0   0:00.00 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   40196    608    400 S   0.0  0.0   0:00.00 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   47392    608    400 S   0.0  0.0   0:00.00 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    65246 root      20   0   55616    608    400 S   0.0  0.0   0:00.00 malloc_test



RES → task가 사용하고 있는 physical memory의 양을 의미

  • RES는 VIRT가 사용하고 있는 실제 물리 메모리의 크기
  • 일반적으로 RES는 VIRT보다 작은 값을 출력
  • RES는 실제로 메모리를 쓰고 있음
  • RES는 SWAP 값 제외
  • RES는 메모리 점유율이 높은 프로세스를 찾기 위해서는 RES 영역이 높은 프로세스를 찾아야함

1. 프로세스가 VIRT 할당 받은 메모리를 RES에 올려서 사용

  • 프로세스가 할당받은 메모리 영역에 실제로 쓰기 작업을 하면 Page fault가 발생
  • Page fault가 발생하면 커널은 실제 물리 메모리에 프로세스의 가상 메모리 공간을 매핑 → Page Table이라고 불리는 커널의 전역 변수로 관리
  • 물리 메모리에 바인딩된영역이 RES로 계산

2. RES의 malloc 테스트 → 이전의 malloc_test.c 파일을 수정

$ vi malloc_test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

# define MEGABYTE 1024*1024

int main(){
    void *myblock = NULL;
    int count = 0;

    while(1){
        myblock = (void *) malloc(MEGABYTE);
        if(!myblock){
            printf("Error!");
            break;
         }
        printf("Currently allocating %d MB\n", (++count)*MEGABYTE);
        memset(myblock, 1, MEGABYTE);
        sleep(1);
    }
    exit(0);
}

# malloc_test 파일을 malloc_test 실행 파일로 만듦
$ gcc -o malloc_test malloc_test.c
$ ls -al
-rwxr-xr-x  1 root root 8568 Oct 11 18:02 malloc_test
-rw-r--r--  1 root root  433 Oct 11 18:01 malloc_test.c

3. RES의 malloc 테스트 실행 결과

  • malloc()을 단독으로 요청하는 것이 아니라 할당 받은 메모리에 쓰기함 → RES 영역이 VIRT 영역 늘어나는 비율과 비슷하게 늘어남

  • 메모리 사용과 관련해서 VIRT 뿐만 아니라 실제 메모리를 쓰는 RES를 확인할 수 있음

  • top 명령으로 해당 프로세스의 변화 확인 → 시간이 지나면서 VIRT과 함께 RES가 계속해서 높아짐

    # 위에서 생성한 malloc_test 실행파일 실행
    $ ./malloc_test
    Currently allocating 1 MB
    Currently allocating 2 MB
    Currently allocating 3 MB
    Currently allocating 4 MB
    Currently allocating 5 MB
    # [...생략...]
    
    # 다른 터미널로 해당 내용 확인
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   21692  17772    400 S   0.0  0.0   0:00.01 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   35056  31236    400 S   0.0  0.0   0:00.04 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   45336  41532    400 S   0.0  0.0   0:00.05 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   57672  53940    400 S   0.0  0.0   0:00.07 malloc_test
    
    $ top -b -n 1 | grep -i malloc
    66652 root      20   0   62812  58956    400 S   0.0  0.0   0:00.08 malloc_test

※ Page Faults

  • 프로그램이 자신의 주소 공간에는 존재하지만 시스템의 RAM에는 현재 없는 데이터나 코드에 접근 시도하였을 경우 발생하는 현상
  • Page Faults 발생하면 운영 체제는 데이터를 메모리로 가져와서 Page Faults가 전혀 발생하지 않은 것처럼 프로그램이 계속적으로 작동하게 해줌

※ Page Table

  • 가상 주소와 물리 메모리 주소의 매핑 테이블
  • 프로세스마다 하나씩 존재하게 되며, 메인 메모리 (RAM)에 상주
  • 많은 프로세스가 구동될 수록, 페이지 테이블로 인한 메인 메모리 사용이 커짐을 의미


SHR → 다른 프로세스와 공유하고 있는 shared memory의 양을 의미

  • SHR는 공유하고 있는 메모리 크기
  • SHR 영역에 대표적으로 등록되는 내용은 라이브러리(library) → 대부분의 리눅스 프로세스는 glibc라는 라이브러리를 참고하기에 해당 라이브러리를 공유 메모리에 올려서 사용
  • 공유메모리에 올려놓고 사용하지 않고, 사용하는 프로세스마다 glibc의 내용을 메모리에 올려서 사용하는 것은 공간 낭비
  • 커널은 공유메모리라는 개념을 도입했고, 다수의 프로세스가 함께 사용하는 라이브러리는 공유메모리 영역에 올려서 함께 사용하도록 구현
  • VIRT는 실제는 할당되지 않는 가상공간이기 때문에 해당 값이 크다고 해도 문제가 되지 않음
  • 실제 사용하고 있는 메모리는 RES 영역이기 때문에 메모리 점유율이 높은 프로세스를 찾기 위해서는 RES 영역이 높은 프로세스를 찾아야함
  • 매핑된 라이브러리 전체는 VIRT와 SHR에 포함되어도, 실제 사용 중인 함수가 있는 일부 메모리만 RES에 포함
  • 커널은 메모리 낭비를 막기위해 공유 메모리라는 개념을 도입했고, 다수의 프로세스가 함께 사용하는 라이브러리는 공유 메모리 영역에 올려서 함께 사용하도록 구현

+ Recent posts