CS

OS가 관리하는 Clock & Hardware Clock

컴공오지마라 2024. 12. 15. 17:45

1. 서론

프로세스는 클락(Clock)을 통해서 시간을 알 수 있다. 이는 상대시간일 수 도 있고 절대시간 일 수 도있다. 운영체제는 상대시간은 주로 Monotonic Counter, 절대 시간은 Wall Clock을 활용하여 관리한다. 이번 글에서는 운영체제가 관리하는 시간의 종류와 관리 방법에 대해서 간단히 정리하고자 한다.

2. OS가 관리하는 시간의 종류

운영체제가 관리하는 시간은 일반적으로 다음 세 가지로 구분된다.

2.1 Wall time (Real time)

  • 실제 세계의 시간과 일치하며, 사용자가 변경이 가능하다.
  • 사용자에게 시간을 제공하거나 사용자의 행동을 시스템 내부에서 기록할때 적합하다.
  • 절대 시간을 측정할때 적합하다
    • 캘린더에 활용하는 시간
    • 백엔드 서버의 로그에 표함된 시간

2.2 Monotonic time

  • 특정 시점(시스템 부팅 시간)부터의 경과 시간을 측정한다.
  • 항상 동일한 간격으로 값이 증가하며 시간을 변경할 수 없다.
  • 절대 시간 정보는 없고, 경과 시간만 제공하므로 상대시간을 표현할때 적합하다.

2.3 Process time

  • 특정 프로세스가 CPU를 사용한 시간을 측정한다.
  • 프로세스가 사용자 모드와 커널 모드에서 실행된 시간을 측정한다. 이때, I/O 요청 등의 이유로 Block state가 되면 Process time 은 흐르지 않는다.
  • 프로세스의 CPU 사용시간 측정에 사용된다.

3. Hardware Clocks

OS는 앞에서 살펴본 시간을 관리하기 위해 하드웨어적인 시계가 필요하다. 대표적인 Hardware clock에 대해서 살펴보도록 하자.

3.1 Real Time Clock (RTC)

  • 여기서 Real time이란 앞에서 살펴본 Wall time이 가리키는 의미와 동일하다.
  • CPU의 마더보드에 포함된 배터리에 의해 동작하며 전원이 꺼지더라도 시간을 측정한다.
  • 그렇기 때문에 컴퓨터에서 실제 시간을 항상 확인할 수 있다.
  • Resolution이 높지 않아서 세밀한 시간을 측정하기에는 적합하지 않다.

3.2 High Precision Event Timer (HPET)

  • OS가 실행될 수 있도록 주기적인 인터럽트를 발생한다.
  • OS는 항상 실행되는 프로세스가 아니라, 누군가가 실행을 trigger 해야된다. (passive)하다.
    • 프로세스 실행 중간 중간에 이 인터럽트에 의해 실행된 OS가 컨텍스트 스위칭과 같은 작업들을 할 수있다. 이를 통해 OS가 프로세스를 관리하고 스케줄링 할 수 있다.

3.3 Time Stamp Counter (TSC)

  • CPU 사이클이 몇번 발생했는지 누적해서 관리하는 CPU 내부의 레지스터이다.
  • 주기적인 인터럽트를 발생하지는 못한다.
  • 앞에서 봤던 Clock 중 Resolution이 가장 높다.

4. OS가 시간을 관리하는 방법: System Clock ( Software Clock )

4.1 Wall time 성격의 System Clock

  • RTC(Real-Time Clock)를 통해 시스템은 현재 날짜와 시간을 유지하고 관리한다.
  • 운영체제는 RTC 값을 바탕으로 1970년 1월 1일 00:00:00 UTC(Unix Epoch Time)를 기준으로 경과된 시간을 초 단위 또는 마이크로초 단위로 계산한다.
  • 이를 통해 시스템의 Wall Time(실제 세계의 시각)을 제공합니다.

사용 사례

  • 시스템 시간 기록 ( unix time stamp )
  • 로그 타임스탬프

4.2 Monotonic 성격의 System Clock

  • 시스템 부팅시 운영체제는 주기적인 인터럽트를 발생시키는 Hardware Clock 중에서 가장 Resolution이 높은 Clock을 이용해서 주기적으로 인터럽트가 발생되도록 한다.
  • 하드웨어 클록이 인터럽트를 발생시킬때마다, 운영체제는 카운터 값을 1씩 증가시킨다.
  • 이때의 시간 간격을 Tick 또는 Jiffy라고 하며, 이러한 Tick 값을 누적하는 카운터를 jiffies 카운터라고 한다.

Tick 값의 의미

  • Tick 또는 Jiffy의 간격에 따라서 카운터에 누적된 값의 실제 시간이 달라지게 된다.
  • 리눅스에서는 일반적으로 250 Hz, Tick의 간격 = 4ms 을 사용한다.
    • 250 HZ는 1초에 250번의 주기적인 인터럽트를 발생한다.
    • 참고로, HZ 값이 너무 빠를 경우 즉 Tick의 주기가 너무 짧을 경우 시스템 오버헤드가 커지게 되는데 대표적인 예로 Context Switch가 너무 자주 발생한다는 문제가 있다.
    • 현재 리눅스에서 일반적으로 사용하는 4ms는 이를 고려하여 설정한 최적의 값이라고 한다.

5. Sleep() 시스템 콜을 활용한 예제

5.1 Sleep() 시스템 콜을 사용해 프로그램이 잠든 시간을 확인하는 예제

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main() {
    struct timespec start, end;

    clock_gettime(CLOCK_MONOTONIC, &start);
    sleep(3);
    clock_gettime(CLOCK_MONOTONIC, &end);
    
    double elapsed_time = (end.tv_sec - start.tv_sec) + 
                          (end.tv_nsec - start.tv_nsec) / 1e9;
    printf("경과 시간: %.6f초\\n", elapsed_time);
    return 0;
}

주어진 코드는 sleep() 시스템콜을 활용하여 프로세스를 3초동안 재우고 경과시간을 확인하는 예제이다. 그런데, 실제로 실행해보면 3.001초 ~ 3.005초 정도로 약간 더 큰 값이 나오는 것이 일반적이다.

경과 시간: 3.002145초

5.2 결과 분석

우리가 호출한 시스템 콜(Sleep)은 명시한 시간이 지난 이후에 함수가 리턴되는 방식으로 동작한다. 즉 내가 원하는 시간만큼 기다리는건 보장해주는데 정확히 그 시간만큼 지난 후 프로세스가 재 실행되는건 보장해주지 못한다. 대표적인 이유로 두가지가 있는데 아래와 같다.

Time granularity

  • 코드에서 나노 sec 단위의 자료구조를 사용하더라도 OS 내부적으로 관리하고 있는 software 시간의 resoultion이 어떤 값이냐에 따라 다르다.
  • 예를 들어 Real Time, MonotonicTime 에 nano 초를 적용하려고 해도 이 Clock 들의 resoultion은 4ms 이기 때문에 실질적으로 반영되지 않는다.

Delayed scheduling

  • 명시한 시간에 정확히 맞춰 프로세스가 깨어나더라도, 바로 실행되지 않을 수 있다. 즉 Block state → Ready State로 바뀌어도 OS스케줄러의 정책에 따라 다른 프로세스가 실행될 수 있다.(Queuing dealy)

참고로, 프로세스가 시그널을 받으면 Blocked 상태에서 Ready 상태로 바뀌는데 그런 경우에는 내가 명시한 시간보다 일찍 일어나게 된다.

6. 마무리 지으며

OS에서 관리하는 시간을 사용하기위한 더욱 자세한 시스템 콜 사용법은 생략하도록 하겠다. 사용자의 요청 제한(Rate limit)을 구현할때 unix time stamp를 이용하여 사용자의 이용기록을 남길 수 있다. 이 밖에도 분산 시스템에서 동기화 등 시간은 시스템에서 중요하게 사용되므로 잘 알아두도록 하자.