Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 418 – 단조 시간, 성능 카운터 및 프로세스 시간 함수 추가

Author:
Cameron Simpson <cs at cskk.id.au>, Jim J. Jewett <jimjjewett at gmail.com>, Stephen J. Turnbull <stephen at xemacs.org>, Victor Stinner <vstinner at python.org>
Status:
Final
Type:
Standards Track
Created:
26-Mar-2012
Python-Version:
3.3

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP에서는 Python 3.3에 time.get_clock_info(name), time.monotonic(), time.perf_counter()time.process_time() 함수를 추가할 것을 제안합니다.

근거

프로그램이 시스템 시간을 사용하여 이벤트를 예약하거나 타임아웃을 구현하는 경우, 시스템 시간이 수동으로 변경되거나 NTP에 의해 자동으로 조정될 때 이벤트를 올바른 시점에 실행하지 못하거나 타임아웃을 너무 일찍 또는 너무 늦게 종료할 수 있습니다. 대신 시스템 시간 업데이트의 영향을 받지 않도록 단조 시계를 사용해야 합니다: time.monotonic().

함수의 성능을 측정하려면 time.clock()을 사용할 수 있지만, Windows와 Unix에서 동작이 매우 다릅니다. Windows에서는 time.clock()이 절전 중 경과한 시간을 포함하지만, Unix에서는 포함하지 않습니다. time.clock()의 해상도는 Windows에서는 매우 좋지만 Unix에서는 매우 나쁩니다. 대신 새로운 time.perf_counter()함수를 사용하여 이식 가능한 동작으로 항상 가장 정밀한 성능 카운터를 얻어야 합니다(예: 절전 중 소요된 시간 포함).

지금까지 Python은 CPU 시간을 측정하는 이식 가능한 함수를 직접 제공하지 않았습니다. Unix에서는 time.clock()을 사용할 수 있지만 해상도가 나쁩니다. Unix에서는 resource.getrusage() 또는 os.times()도 사용할 수 있지만, 커널 공간과 사용자 공간에서 소요된 시간의 합을 계산해야 합니다. 새로운 time.process_time()함수는 항상 CPU 시간을 측정하고(절전 중 경과한 시간 제외) 사용 가능한 최상의 해상도를 갖는 이식 가능한 카운터로 동작합니다.

각 운영 체제는 시계와 성능 카운터를 서로 다르게 구현하므로, 정확히 어떤 함수가 사용되는지와 해상도 같은 시계의 일부 속성을 아는 것이 유용합니다. 새로운 time.get_clock_info()함수는 각 Python 시간 함수에 대해 사용 가능한 모든 정보에 접근할 수 있게 합니다.

새 함수:

  • time.monotonic(): 시스템 시계 업데이트의 영향을 받지 않는 타임아웃 및 스케줄링
  • time.perf_counter(): 벤치마킹, 짧은 기간에 가장 정밀한 시계
  • time.process_time(): 프로파일링, 프로세스의 CPU 시간

새 함수의 사용자:

  • time.monotonic(): 타임아웃을 구현하는 concurrent.futures, multiprocessing, queue, subprocess, telnet 및 threading 모듈
  • time.perf_counter(): trace 및 timeit 모듈, pybench 프로그램
  • time.process_time(): profile 모듈
  • time.get_clock_info(): 해상도와 같은 타이머 정보를 표시하는 pybench 프로그램

time.clock()함수는 이식 가능하지 않으므로 더 이상 사용되지 않습니다. 운영 체제에 따라 동작이 다릅니다. 요구 사항에 따라 time.perf_counter() 또는 time.process_time()을 대신 사용해야 합니다. time.clock()은 더 이상 사용되지 않는 것으로 표시되지만 제거할 계획은 없습니다.

제한 사항:

  • 시스템이 일시 중단된 후 시계의 동작은 새 함수의 문서에 정의되어 있지 않습니다. 동작은 운영 체제에 따라 다릅니다. 아래의 Monotonic Clocks 절을 참조하십시오. 최근의 일부 운영 체제는 시스템 일시 중단 중 경과한 시간을 포함하는 시계와 해당 시간을 포함하지 않는 시계, 두 가지를 제공합니다. 대부분의 운영 체제는 한 종류의 시계만 제공합니다.
  • time.monotonic() 및 time.perf_counter()는 조정될 수도 있고 조정되지 않을 수도 있습니다. 예를 들어, CLOCK_MONOTONIC은 Linux에서 서서히 조정되는 반면 GetTickCount()는 Windows에서 조정되지 않습니다. time.get_clock_info('monotonic')['adjustable']을 사용하여 단조 시계를 조정할 수 있는지 확인할 수 있습니다.
  • 이 PEP에서는 time.thread_time() 함수를 제안하지 않습니다. Python 표준 라이브러리에서 필요하지도 않고 흔히 요청되는 기능도 아니기 때문입니다. 이러한 함수는 Windows와 Linux에서만 사용할 수 있습니다. Linux에서는 time.clock_gettime(CLOCK_THREAD_CPUTIME_ID)를 사용할 수 있습니다. Windows에서는 ctypes 또는 다른 모듈을 사용하여 GetThreadTimes() 함수를 호출할 수 있습니다.

Python 함수

새 함수

time.get_clock_info(name)

지정한 시계에 관한 정보를 가져옵니다. 지원되는 시계 이름은 다음과 같습니다.

  • "clock": time.clock()
  • "monotonic": time.monotonic()
  • "perf_counter": time.perf_counter()
  • "process_time": time.process_time()
  • "time": time.time()

다음 특성을 가진 time.clock_info 객체를 반환합니다.

  • implementation (str): 기반 운영 체제 함수의 이름입니다. 예: "QueryPerformanceCounter()", "clock_gettime(CLOCK_REALTIME)"입니다.
  • monotonic (bool): 시계가 뒤로 가지 않으면 True입니다.
  • adjustable (bool): 시계를 자동으로(예: NTP 데몬에 의해) 또는 시스템 관리자가 수동으로 변경할 수 있으면 True이고, 그렇지 않으면 False입니다.
  • resolution (float): 시계의 해상도(초 단위)입니다.

time.monotonic()

단조 시계입니다. 즉, 뒤로 가지 않습니다. 시스템 시계 업데이트의 영향을 받지 않습니다. 반환된 값의 기준점은 정의되지 않으므로 연속 호출 결과 간의 차이만 유효하며 초 단위의 숫자입니다.

Vista보다 오래된 Windows 버전에서는 time.monotonic()GetTickCount() 정수 오버플로(32비트, 49.7일 후 롤오버)를 감지합니다. 오버플로가 감지될 때마다 내부 에포크(기준 시간)를 232씩 증가시킵니다. 에포크는 프로세스 로컬 상태에 저장되므로 49일 넘게 실행된 두 Python 프로세스에서 time.monotonic()의 값이 서로 다를 수 있습니다. 최신 Windows 버전과 다른 운영 체제에서는 time.monotonic()이 시스템 전역입니다.

사용 가능 환경: Windows, Mac OS X, Linux, FreeBSD, OpenBSD, Solaris입니다. GNU/Hurd에서는 사용할 수 없습니다.

의사 코드 [2]:

if os.name == 'nt':
    # GetTickCount64() requires Windows Vista, Server 2008 or later
    if hasattr(_time, 'GetTickCount64'):
        def monotonic():
            return _time.GetTickCount64() * 1e-3
    else:
        def monotonic():
            ticks = _time.GetTickCount()
            if ticks < monotonic.last:
                # Integer overflow detected
                monotonic.delta += 2**32
            monotonic.last = ticks
            return (ticks + monotonic.delta) * 1e-3
        monotonic.last = 0
        monotonic.delta = 0

elif sys.platform == 'darwin':
    def monotonic():
        if monotonic.factor is None:
            factor = _time.mach_timebase_info()
            monotonic.factor = timebase[0] / timebase[1] * 1e-9
        return _time.mach_absolute_time() * monotonic.factor
    monotonic.factor = None

elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_HIGHRES"):
    def monotonic():
        return time.clock_gettime(time.CLOCK_HIGHRES)

elif hasattr(time, "clock_gettime") and hasattr(time, "CLOCK_MONOTONIC"):
    def monotonic():
        return time.clock_gettime(time.CLOCK_MONOTONIC)

Windows에서는 QueryPerformanceCounter()GetTickCount()보다 해상도가 더 높음에도 사용하지 않습니다. 신뢰할 수 없고 문제가 너무 많기 때문입니다.

time.perf_counter()

짧은 기간을 측정하기 위한, 사용 가능한 가장 높은 해상도의 성능 카운터입니다. 절전 중 경과한 시간도 포함하며 시스템 전체에서 사용됩니다. 반환된 값의 기준점은 정의되지 않으므로, 연속 호출 결과 간 차이만 유효하며 초 단위 숫자입니다.

모든 플랫폼에서 사용할 수 있습니다.

의사 코드:

if os.name == 'nt':
    def _win_perf_counter():
        if _win_perf_counter.frequency is None:
            _win_perf_counter.frequency = _time.QueryPerformanceFrequency()
        return _time.QueryPerformanceCounter() / _win_perf_counter.frequency
    _win_perf_counter.frequency = None

def perf_counter():
    if perf_counter.use_performance_counter:
        try:
            return _win_perf_counter()
        except OSError:
            # QueryPerformanceFrequency() fails if the installed
            # hardware does not support a high-resolution performance
            # counter
            perf_counter.use_performance_counter = False
    if perf_counter.use_monotonic:
        # The monotonic clock is preferred over the system time
        try:
            return time.monotonic()
        except OSError:
            perf_counter.use_monotonic = False
    return time.time()
perf_counter.use_performance_counter = (os.name == 'nt')
perf_counter.use_monotonic = hasattr(time, 'monotonic')

time.process_time()

현재 프로세스의 시스템 CPU 시간과 사용자 CPU 시간의 합입니다. 절전 중 경과한 시간은 포함하지 않습니다. 정의상 프로세스 전체에서 사용됩니다. 반환된 값의 기준점은 정의되지 않으므로, 연속 호출 결과 간 차이만 유효합니다.

모든 플랫폼에서 사용할 수 있습니다.

의사 코드 [2]:

if os.name == 'nt':
    def process_time():
        handle = _time.GetCurrentProcess()
        process_times = _time.GetProcessTimes(handle)
        return (process_times['UserTime'] + process_times['KernelTime']) * 1e-7
else:
    try:
        import resource
    except ImportError:
        has_resource = False
    else:
        has_resource = True

    def process_time():
        if process_time.clock_id is not None:
            try:
                return time.clock_gettime(process_time.clock_id)
            except OSError:
                process_time.clock_id = None
        if process_time.use_getrusage:
            try:
                usage = resource.getrusage(resource.RUSAGE_SELF)
                return usage[0] + usage[1]
            except OSError:
                process_time.use_getrusage = False
        if process_time.use_times:
            try:
                times = _time.times()
                cpu_time = times.tms_utime + times.tms_stime
                return cpu_time / process_time.ticks_per_seconds
            except OSError:
                process_time.use_getrusage = False
        return _time.clock()
    if (hasattr(time, 'clock_gettime')
        and hasattr(time, 'CLOCK_PROF')):
        process_time.clock_id = time.CLOCK_PROF
    elif (hasattr(time, 'clock_gettime')
          and hasattr(time, 'CLOCK_PROCESS_CPUTIME_ID')):
        process_time.clock_id = time.CLOCK_PROCESS_CPUTIME_ID
    else:
        process_time.clock_id = None
    process_time.use_getrusage = has_resource
    process_time.use_times = hasattr(_time, 'times')
    if process_time.use_times:
        # sysconf("SC_CLK_TCK"), or the HZ constant, or 60
        process_time.ticks_per_seconds = _times.ticks_per_seconds

기존 함수

time.time()

일반적으로 일상 시간인 시스템 시간입니다. 정의상 시스템 전체에서 사용됩니다. 시스템 관리자가 수동으로 설정하거나 NTP 데몬이 자동으로 설정할 수 있습니다.

모든 플랫폼에서 사용할 수 있으며 실패하지 않습니다.

의사 코드 [2]:

if os.name == "nt":
    def time():
        return _time.GetSystemTimeAsFileTime()
else:
    def time():
        if hasattr(time, "clock_gettime"):
            try:
                return time.clock_gettime(time.CLOCK_REALTIME)
            except OSError:
                # CLOCK_REALTIME is not supported (unlikely)
                pass
        if hasattr(_time, "gettimeofday"):
            try:
                return _time.gettimeofday()
            except OSError:
                # gettimeofday() should not fail
                pass
        if hasattr(_time, "ftime"):
            return _time.ftime()
        else:
            return _time.time()

time.sleep()

지정된 초 동안 실행을 일시 중단합니다. 포착된 시그널은 해당 시그널을 처리하는 루틴의 실행 후 time.sleep()을 종료하므로 실제 일시 중단 시간은 요청한 시간보다 짧을 수 있습니다. 또한 시스템에서 다른 활동이 예약되는 방식 때문에 일시 중단 시간이 요청한 시간보다 임의의 양만큼 길어질 수 있습니다.

의사 코드 [2]:

try:
    import select
except ImportError:
    has_select = False
else:
    has_select = hasattr(select, "select")

if has_select:
    def sleep(seconds):
        return select.select([], [], [], seconds)

elif hasattr(_time, "delay"):
    def sleep(seconds):
        milliseconds = int(seconds * 1000)
        _time.delay(milliseconds)

elif os.name == "nt":
    def sleep(seconds):
        milliseconds = int(seconds * 1000)
        win32api.ResetEvent(hInterruptEvent);
        win32api.WaitForSingleObject(sleep.sigint_event, milliseconds)

    sleep.sigint_event = win32api.CreateEvent(NULL, TRUE, FALSE, FALSE)
    # SetEvent(sleep.sigint_event) will be called by the signal handler of SIGINT

elif os.name == "os2":
    def sleep(seconds):
        milliseconds = int(seconds * 1000)
        DosSleep(milliseconds)

else:
    def sleep(seconds):
        seconds = int(seconds)
        _time.sleep(seconds)

사용 중단된 함수

time.clock()

Unix에서는 현재 프로세서 시간을 초로 표현한 부동 소수점 숫자로 반환합니다. 정의상 프로세스 전체에서 사용됩니다. 해상도와, 사실상 “프로세서 시간”이라는 의미의 정확한 정의는 같은 이름의 C 함수에 따라 달라지지만, 어쨌든 Python을 벤치마킹하거나 알고리즘의 시간을 측정할 때 사용하는 함수입니다.

Windows에서 이 함수는 Win32 함수 QueryPerformanceCounter()를 기반으로 첫 호출 이후 경과한 벽시계 기준 초를 부동 소수점 수로 반환합니다. 해상도는 일반적으로 1마이크로초보다 높습니다. 시스템 전체에 적용됩니다.

의사 코드 [2]:

if os.name == 'nt':
    def clock():
        try:
            return _win_perf_counter()
        except OSError:
            # QueryPerformanceFrequency() fails if the installed
            # hardware does not support a high-resolution performance
            # counter
            pass
        return _time.clock()
else:
    clock = _time.clock

대안: API 설계

time.monotonic()의 다른 이름

  • time.counter()
  • time.metronomic()
  • time.seconds()
  • time.steady(): “steady”는 모호하며, 사람마다 의미가 다릅니다. 예를 들어 Linux에서는 CLOCK_MONOTONIC이 조정됩니다. 실제 시간을 기준 시계로 사용한다면 CLOCK_MONOTONIC이 안정적이라고 말할 수 있습니다. 그러나 CLOCK_MONOTONIC은 시스템이 일시 중단되면 일시 정지되는 반면, 실제 시간에는 일시 중단 상태에서 보낸 시간도 포함됩니다.
  • time.timeout_clock()
  • time.wallclock(): time.monotonic()은 시스템 시간, 즉 “벽시계”가 아니라 시작점이 지정되지 않은 단조 시계입니다.

단조 시계를 사용할 수 없을 때 시스템 시간으로 대체하는 time.monotonic()의 이전 버전에 대해 “time.try_monotonic()”이라는 이름도 제안되었습니다.

time.perf_counter()의 다른 이름

  • time.high_precision()
  • time.highres()
  • time.hires()
  • time.performance_counter()
  • time.timer()

운영 체제 시계만 노출

정의하기 어려운 고수준 시계를 정의하지 않아도 되도록 운영 체제 시계만 노출하는 더 간단한 접근법을 사용할 수 있습니다. 예를 들어 time.clock_gettime() 및 관련 시계 식별자는 이미 Python 3.3에 추가되었습니다.

time.monotonic(): 시스템 시간으로 대체

단조 시계를 사용할 수 없으면 time.monotonic()은 시스템 시간으로 대체됩니다.

문제:

  • 문서에서 이러한 함수를 올바르게 정의하기 어렵습니다. 단조롭습니까? 안정적입니까? 조정됩니까?
  • 일부 사용자는 단조 시계를 사용할 수 없을 때 다른 시계를 사용할지, 오류를 표시할지, 아니면 다른 작업을 수행할지 결정하기를 원합니다.

이러한 함수를 정의하기 위한 다양한 API가 제안되었습니다.

플래그가 있는 함수 하나: time.monotonic(fallback=True)

  • time.monotonic(fallback=True)는 단조 시계를 사용할 수 없거나 단조 시계가 실패한 경우 시스템 시간으로 대체합니다.
  • time.monotonic(fallback=False)는 단조 시계가 실패하면 OSError를 발생시키고, 시스템이 단조 시계를 제공하지 않으면 NotImplementedError를 발생시킵니다.

호출자에서 상수로 전달되는 키워드 인자는 대개 좋지 않은 API입니다.

함수에서 NotImplementedError를 발생시키는 것은 Python에서 흔하지 않으므로 피해야 합니다.

time.monotonic() 함수 하나, 플래그 없음

time.monotonic()은 (time: float, is_monotonic: bool)을 반환합니다.

대안으로 함수 속성을 사용할 수 있습니다: time.monotonic.is_monotonic. time.monotonic()을 처음 호출하기 전에는 속성 값이 None입니다.

제약 조건 목록에서 시계 선택하기

제안된 PEP는 몇 가지 새로운 시계를 제공하지만, 다양한 플랫폼에서 유용한 시계를 제공하기 위해 그 보장 사항을 의도적으로 느슨하게 정의합니다. 이는 본질적으로 호출에 정책을 포함하므로 호출자가 정책을 선택해야 합니다.

“시계 선택” 방식은 대부분의 플랫폼 시계를 사용할 수 있게 하고 호출자가 그중에서 선택하도록 하여, 필요한 경우 호출자가 자체 정책을 구현할 수 있게 하는 추가 API를 제안합니다. PEP에서 제안하는 시계는 일반적인 단순 사용 사례에서도 계속 사용할 수 있을 것으로 예상됩니다.

이를 위해서는 두 가지 기능이 필요합니다. 시계 열거와 사용자가 시계의 적합성을 평가할 수 있도록 하는 시계 메타데이터입니다.

주 인터페이스는 간단한 선택을 쉽게 만드는 함수입니다. 호출자는 time.get_clock(*flags)를 일부 플래그 조합과 함께 사용할 수 있습니다. 여기에는 최소한 다음이 포함됩니다.

  • time.MONOTONIC: 시계가 뒤로 가지 않습니다.
  • time.STEADY: 시계 속도가 일정합니다.
  • time.ADJUSTED: 예를 들어 NTP에 의해 시계가 조정될 수 있습니다.
  • time.HIGHRES: 가장 높은 해상도를 가진 시계입니다.

현재 시간을 반환하는 .now() 메서드를 가진 시계 객체를 반환합니다. 시계 객체에는 시계 기능 집합을 설명하는 메타데이터가 주석으로 추가됩니다. 해당 .flags 필드에는 요청된 모든 플래그가 최소한 포함됩니다.

일치하는 시계를 찾지 못하면 time.get_clock()은 None을 반환하므로, or 연산자를 사용해 호출을 연결할 수 있습니다. 간단한 정책 결정의 예:

T = get_clock(MONOTONIC) or get_clock(STEADY) or get_clock()
t = T.now()

사용 가능한 시계에는 항상 time.time()의 래퍼가 최소한 포함되므로, 플래그 없이 마지막 호출을 사용해 항상 작동하는 시계를 얻을 수 있습니다.

시스템 시계 플래그의 예:

  • QueryPerformanceCounter: MONOTONIC | HIGHRES
  • GetTickCount: MONOTONIC | STEADY
  • CLOCK_MONOTONIC: MONOTONIC | STEADY (또는 Linux에서는 MONOTONIC만 해당)
  • CLOCK_MONOTONIC_RAW: MONOTONIC | STEADY
  • gettimeofday(): (플래그 없음)

시계 객체에는 위에 나열된 것 외의 추가 기능 플래그를 포함한 시계 플래그, 기본 OS 기능의 이름, 시계 정밀도를 비롯한 다른 메타데이터도 포함됩니다.

time.get_clock()은 여전히 단일 시계를 선택하므로, 열거 기능도 필요합니다. 가장 명확한 방법은 time.get_clocks()time.get_clock()와 동일한 시그니처로 제공하되, 요청된 플래그와 일치하는 모든 시계의 시퀀스를 반환하도록 하는 것입니다. 따라서 플래그를 지정하지 않으면 사용 가능한 모든 시계를 열거하여, 호출자가 해당 메타데이터를 바탕으로 그중 임의의 시계를 선택할 수 있습니다.

부분 구현 예제: clockutils.py.

운영 체제 버그에 대한 우회책?

Python은 시계 값과 이전 값 중 최댓값을 계산하여 단조 시계가 실제로 단조 증가하도록 보장해야 합니까?

정적 변수를 사용하여 반환된 마지막 값을 캐시하는 것은 비교적 간단하므로, 이를 사용하여 반환되는 값이 실제로 단조 증가하는지 확인하는 것도 흥미로울 수 있습니다.

  • 가상 머신은 신뢰성이 더 낮은 시계를 제공합니다.
  • QueryPerformanceCounter()에는 알려진 버그가 있습니다(아직 수정되지 않은 것은 하나뿐입니다).

Python은 특정 운영 체제 버그 하나에 대해서만 우회 처리를 제공할 수 있습니다. KB274323에는 해당 버그를 우회하는 코드 예제가 포함되어 있습니다(QueryPerformanceCounter()의 도약을 감지하기 위해 GetTickCount()를 사용합니다).

단조성 저하를 “수정하는” 데 따른 문제:

  • 시계가 실수로 한 시간 앞으로 설정되었다가 다시 되돌아오면 한 시간 동안 유용한 시계를 사용할 수 없습니다
  • 캐시는 프로세스 간에 공유되지 않으므로 서로 다른 프로세스가 동일한 시계 값을 보지 못합니다

용어집

Accuracy:
주어진 측정 기기가 참값에서 보이는 측정값의 편차입니다. Accuracy and precision도 참조하십시오. 시계의 부정확성은 정밀도 부족, 드리프트 또는 시계의 초기 설정 오류로 인해 발생할 수 있습니다(예를 들어 카운터를 재설정할 때 완벽하게 동기화하기가 상당히 어렵기 때문에 스레드 타이밍은 본질적으로 부정확합니다).
Adjusted:
시계를 정확한 시간으로 재설정하는 것입니다. 이는 <Step> 또는 <Slewing>을 사용하여 수행할 수 있습니다.
민간 시간:
하루 중 시각이며 시스템 외부의 시간입니다. 10:45:13am은 민간 시간이고, 45초는 그렇지 않습니다. 기존 함수 time.localtime()time.gmtime()로 제공됩니다. 이 PEP에서는 변경되지 않습니다.
Clock:
시간을 측정하는 기기입니다. 시계마다 특성이 다릅니다. 예를 들어 나노초 단위의 <precision>은 몇 분 후에 <drift>하기 시작할 수 있지만, 정밀도가 낮은 시계는 며칠 동안 정확하게 유지될 수 있습니다. 이 PEP는 주 단위로 초를 사용하는 시계를 다룹니다.
Counter:
특정 이벤트가 발생할 때마다 증가하는 시계입니다. 카운터는 엄격히 단조 증가하지만 단조 시계는 아닙니다. 이를 사용하여 고유하고 순서가 있는 타임스탬프를 생성할 수 있지만, 이러한 타임스탬프는 <civil time>에 매핑할 수 없습니다. 틱 생성은 상당히 불규칙할 수 있으며, 동일한 밀리초 안에 여러 번 증가한 후 며칠 동안 전혀 증가하지 않을 수도 있습니다.
CPU 시간:
특정 작업에 사용된 CPU 노력의 정도를 나타내는 척도입니다. CPU 초는 흔히 정규화되므로, 가변적인 수치가 동일한 실제 1초 안에 나타날 수 있습니다. 프로파일링할 때 CPU 초가 중요할 수 있지만, 사용자 응답 시간에 직접 대응하지 않으며 (실제 시간) 초와 직접 비교할 수도 없습니다.
Drift:
시스템 외부에서 정의된 “참” 시간에 대한 누적 오차입니다. 드리프트는 부정확성이나 시계 시간이 진행되는 평균 속도와 실제 시간의 평균 속도 간 차이로 인해 발생할 수 있습니다.
Epoch:
시계의 기준점입니다. <civil time>을제공하는 시계의 경우, 이는 날짜(및 연도)가 1970년 1월 1일로 넘어갈 때의 자정인 경우가 많습니다. <clock_monotonic> 시계에서는 에포크가 정의되지 않을 수 있으며(None으로 표시됩니다),.
Latency:
지연입니다. 시계 호출이 반환될 때까지 <real time>이경과하며, 시계의 정밀도보다 더 많이 경과할 수도 있습니다.
Monotonic:
실제 사용에서 단조 증가 시계에 기대되는 특성입니다. 최대 한 방향으로만 움직이며, 시계의 경우 그 방향은 앞으로입니다. <clock>은또한 <steady>여야 하며, 초 단위로 변환할 수 있어야 합니다. 이러한 상충 관계에는 정의된 <epoch>가 없거나 <Civil Time>으로 매핑되지 않는 경우가 포함되는 경우가 많습니다.
Precision:
단일 기기가 동일한 물리적 값을 측정할 때 측정값들 사이의 편차 정도입니다. 시계의 부정확성은 시계 시간이 실제 시간에 비해 진행되는 속도의 변동으로 인해 발생할 수 있으며, 여기에는 슬루잉에 의한 시계 조정도 포함됩니다.
프로세스 시간:
프로세스가 시작된 이후 경과한 시간입니다. 이는 일반적으로 <real time>이아니라 <CPU time>으로 측정되며, 프로세스가 일시 중단된 동안에는 일반적으로 진행되지 않습니다.
실제 시간:
현실 세계의 시간입니다. 이는 <Civil time>과달리 <adjusted>되지 않지만, 그 외에는 두 시간이 보조를 맞춰 진행되어야 합니다. 이는 “Real Time [Operating] Systems”의 “real time”과 관련이 없습니다. 이러한 모호함을 피하기 위해 때때로 “wall clock time”이라고 부르지만, 안타깝게도 이는 서로 다른 모호함을 초래합니다.
Resolution:
주어진 기기가 서로 다른 측정값을 산출하게 되는 두 물리적 값 사이의 가장 작은 차이입니다.
Slew:
일반적으로 외부 기준에 대한 <drift>를보정하기 위해 시계의 속도를 약간 변경하는 것입니다.
Stability:
정확도의 지속성입니다. 예상되는 <drift>를측정한 값입니다.
Steady:
<stability>가높고 <accuracy>와<precision>도비교적 높은 시계입니다. 실제로는 <clock_monotonic> 시계를 나타내는 데 자주 사용되지만, 연속된 틱 사이의 기간이 일관적인지에 더 중점을 둡니다.
Step:
표시되는 시간의 순간적인 변화입니다. 시계의 속도를 높이거나 낮추는 것(<slew>) 대신, 단일 오프셋을 영구적으로 더합니다.
시스템 시간:
운영 체제가 나타내는 시간입니다.
스레드 시간:
스레드가 시작된 후 경과한 시간입니다. 일반적으로 <CPU time>이 아니라 <real time>으로 측정되며, 스레드가 유휴 상태일 때는 일반적으로 진행되지 않습니다.
Wallclock:
벽시계가 나타내는 시간입니다. 일반적으로 <real time>의 동의어로 사용되지만, 안타깝게도 벽시계 시간 자체가 모호합니다.

하드웨어 시계

하드웨어 시계 목록

  • HPET: 고정밀 이벤트 타이머(HPET) 칩은 최소 10MHz로 카운트하는 64비트 업 카운터(주 카운터) 하나와 최대 256개(최소 3개)의 비교기로 구성됩니다. 각 HPET에는 최대 32개의 타이머가 있을 수 있습니다. HPET로 인해 하루에 약 3초의 드리프트가 발생할 수 있습니다.
  • TSC(타임스탬프 카운터): 과거에는 내부 프로세서 클록 사이클마다 TSC가 증가했지만, 현재는 일반적으로 속도가 일정하며(프로세서가 주파수를 변경하더라도) 대개 프로세서 최대 주파수와 같습니다. 여러 코어는 서로 다른 TSC 값을 가집니다. 시스템을 최대 절전 모드로 전환하면 TSC 값이 재설정됩니다. RDTSC 명령을 사용하여 이 카운터를 읽을 수 있습니다. 전력 절약을 위한 CPU 주파수 스케일링입니다.
  • ACPI 전원 관리 타이머: 주파수가 3.5MHz(3,579,545Hz)인 ACPI 24비트 타이머입니다.
  • Cyclone: Cyclone 타이머는 IBM “Summit” 시리즈 칩셋(예: x440)을 사용하는 컴퓨터를 포함하는 IBM Extended X-Architecture(EXA) 칩셋에서 32비트 카운터를 사용합니다. IA32 및 IA64 아키텍처에서 사용할 수 있습니다.
  • PIT(프로그램 가능 인터럽트 타이머): 18.2Hz~1.2MHz 범위에서 주파수를 구성할 수 있는 Intel 8253/8254 칩셋입니다. 16비트 카운터를 사용합니다.
  • RTC(실시간 시계)입니다. 대부분의 RTC는 주파수가 32,768Hz인 수정 발진기를 사용합니다.

Linux 클록 소스

Linux 커널에는 시간 구현이 4가지 있었습니다. UTIME(1996), 타이머 휠(1997), HRT(2001), hrtimers(2007)입니다. 후자는 George Anzinger가 2001년에 시작하고 Thomas Gleixner와 Douglas Niehaus가 기여한 “high-res-timers” 프로젝트의 결과입니다. hrtimers 구현은 2007년에 출시된 Linux 2.6.21에 병합되었습니다.

hrtimers는 다양한 클록 소스를 지원합니다. 사용할 소스를 결정하기 위해 각 소스에 우선순위를 설정합니다. Linux는 다음 클록 소스를 지원합니다.

  • tsc
  • hpet
  • pit
  • pmtmr: ACPI 전원 관리 타이머
  • cyclone

고해상도 타이머는 모든 하드웨어 아키텍처에서 지원되는 것은 아닙니다. 적어도 x86/x86_64, ARM 및 PowerPC에서는 제공됩니다.

clock_getres()는 기본 클록 소스와 관계없이 CLOCK_REALTIMECLOCK_MONOTONIC에 대해 1나노초를 반환합니다. Thomas Gleixner가 작성한 Re: clock_getres() and real resolution (2월 9일 2012) 설명을 위해 참조하십시오.

/sys/devices/system/clocksource/clocksource0 디렉터리에는 유용한 파일 두 개가 있습니다.

  • available_clocksource: 사용 가능한 클록 소스 목록
  • current_clocksource: 현재 사용 중인 클록 소스입니다. 이 파일에 클록 소스의 이름을 기록하여 현재 클록 소스를 변경할 수 있습니다.

/proc/timer_list에는 모든 하드웨어 타이머 목록이 포함되어 있습니다.

time(7) 매뉴얼 페이지도 참조하십시오: “시간 및 타이머 개요”.

FreeBSD timecounter

kern.timecounter.choice는 사용 가능한 하드웨어 클록을 우선순위와 함께 나열합니다. sysctl 프로그램을 사용하여 timecounter를 변경할 수 있습니다. 예:

# dmesg | grep Timecounter
Timecounter "i8254" frequency 1193182 Hz quality 0
Timecounter "ACPI-safe" frequency 3579545 Hz quality 850
Timecounter "HPET" frequency 100000000 Hz quality 900
Timecounter "TSC" frequency 3411154800 Hz quality 800
Timecounters tick every 10.000 msec
# sysctl kern.timecounter.choice
kern.timecounter.choice: TSC(800) HPET(900) ACPI-safe(850) i8254(0) dummy(-1000000)
# sysctl kern.timecounter.hardware="ACPI-fast"
kern.timecounter.hardware: HPET -> ACPI-fast

사용 가능한 클록:

  • “TSC”: 프로세서의 타임스탬프 카운터
  • “HPET”: 고정밀 이벤트 타이머
  • “ACPI-fast”: ACPI 전원 관리 타이머(빠른 모드)
  • “ACPI-safe”: ACPI 전원 관리 타이머(안전 모드)
  • “i8254”: Intel 8254 칩셋을 사용하는 PIT

commit 222222은 (5월 2011) ACPI-fast timecounter 품질을 900으로 낮추고 HPET timecounter 품질을 950으로 높였습니다. “현대 플랫폼에서 HPET는 일반적으로 ACPI 타이머보다 해상도가 더 높고 지연 시간이 더 짧습니다.”

Poul-Henning Kamp가 작성한 Timecounters: Efficient and precise timekeeping in SMP kernels를 읽어 보십시오. (2002) FreeBSD 프로젝트를 위해 작성된 문서입니다.

성능

하드웨어 시계를 읽는 데는 비용이 듭니다. 다음 표는 Linux 3.3에서 3.40GHz로 동작하는 Intel Core i7-2600(8코어)의 서로 다른 하드웨어 시계 성능을 비교합니다. bench_time.c 프로그램은 이 표들을 작성하는 데 사용되었습니다.

함수 TSC ACPI PM HPET
time() 2 ns 2 ns 2 ns
CLOCK_REALTIME_COARSE 10 ns 10 ns 10 ns
CLOCK_MONOTONIC_COARSE 12 ns 13 ns 12 ns
CLOCK_THREAD_CPUTIME_ID 134 ns 135 ns 135 ns
CLOCK_PROCESS_CPUTIME_ID 127 ns 129 ns 129 ns
clock() 146 ns 146 ns 143 ns
gettimeofday() 23 ns 726 ns 637 ns
CLOCK_MONOTONIC_RAW 31 ns 716 ns 607 ns
CLOCK_REALTIME 27 ns 707 ns 629 ns
CLOCK_MONOTONIC 27 ns 723 ns 635 ns

하드웨어 가상화를 사용하는 kvm에서의 FreeBSD 8.0:

함수 TSC ACPI-Safe HPET i8254
time() 191 ns 188 ns 189 ns 188 ns
CLOCK_SECOND 187 ns 184 ns 187 ns 183 ns
CLOCK_REALTIME_FAST 189 ns 180 ns 187 ns 190 ns
CLOCK_UPTIME_FAST 191 ns 185 ns 186 ns 196 ns
CLOCK_MONOTONIC_FAST 188 ns 187 ns 188 ns 189 ns
CLOCK_THREAD_CPUTIME_ID 208 ns 206 ns 207 ns 220 ns
CLOCK_VIRTUAL 280 ns 279 ns 283 ns 296 ns
CLOCK_PROF 289 ns 280 ns 282 ns 286 ns
clock() 342 ns 340 ns 337 ns 344 ns
CLOCK_UPTIME_PRECISE 197 ns 10380 ns 4402 ns 4097 ns
CLOCK_REALTIME 196 ns 10376 ns 4337 ns 4054 ns
CLOCK_MONOTONIC_PRECISE 198 ns 10493 ns 4413 ns 3958 ns
CLOCK_UPTIME 197 ns 10523 ns 4458 ns 4058 ns
gettimeofday() 202 ns 10524 ns 4186 ns 3962 ns
CLOCK_REALTIME_PRECISE 197 ns 10599 ns 4394 ns 4060 ns
CLOCK_MONOTONIC 201 ns 10766 ns 4498 ns 3943 ns

각 함수는 100,000번 호출되었으며, 호출 전후의 시간을 구하는 데 CLOCK_MONOTONIC을 사용했습니다. 벤치마크를 5번 실행하고 최솟값을 취했습니다.

NTP 조정

NTP에는 시계를 조정하는 여러 방법이 있습니다.

  • “슬루잉”: 시계 주파수를 약간 빠르거나 느리게 변경하는 방식입니다(이는 adjtime()으로 수행합니다). 슬루율은 초당 0.5밀리초로 제한되므로, 조정 1초마다 2000초의 상각 간격이 필요합니다. 따라서 수 초에 이르는 조정은 상각하는 데 몇 시간 또는 며칠이 걸릴 수 있습니다.
  • “스테핑”: 한 번의 불연속적인 단계에서 큰 양만큼 건너뛰는 방식입니다(이는 settimeofday()로 수행합니다).

기본적으로 오프셋이 128ms 미만이면 시간을 슬루잉하지만, 그렇지 않으면 스테핑합니다.

“실제” 시간을 측정하려는 경우(그리고 CPU 사이클과 같은 시간 유사 객체를 측정하려는 것이 아닌 경우)에는 일반적으로 슬루잉이 바람직합니다(즉, CLOCK_MONOTONIC_RAW가 아닌 CLOCK_MONOTONIC을 사용해야 합니다). 이는 여러분과 NTP 연결의 반대편에 있는 시계가 시간을 유지하는 데 아마 더 능숙하기 때문입니다. 결국, 3만 5천 달러짜리 세슘 시간 측정 장비가 여러분의 PC에 있는 3달러짜리 석영 결정체보다 더 나은 일을 하고 있기를 바랍니다.

NTP 데몬의 문서에서 자세한 내용을 확인하십시오.

운영 체제 시간 함수

단조 시계

이름 C 해상도 조정됨 절전 포함 일시 중지 포함
gethrtime() 1 ns 아니요
CLOCK_HIGHRES 1 ns 아니요
CLOCK_MONOTONIC 1 ns Linux에서 서서히 조정됨 아니요
CLOCK_MONOTONIC_COARSE 1 ns Linux에서 서서히 조정됨 아니요
CLOCK_MONOTONIC_RAW 1 ns 아니요 아니요
CLOCK_BOOTTIME 1 ns ?
CLOCK_UPTIME 1 ns 아니요 ?
mach_absolute_time() 1 ns 아니요 아니요
QueryPerformanceCounter() - 아니요 ?
GetTickCount[64]() 1 ms 아니요
timeGetTime() 1 ms 아니요 ?

“C Resolution” 열은 기반 C 구조체의 해상도입니다.

x86_64에서 클록 해상도의 예는 다음과 같습니다.

이름 운영 체제 운영 체제 해상도 Python 해상도
QueryPerformanceCounter Windows Seven 10 ns 10 ns
CLOCK_HIGHRES SunOS 5.11 2 ns 265 ns
CLOCK_MONOTONIC Linux 3.0 1 ns 322 ns
CLOCK_MONOTONIC_RAW Linux 3.3 1 ns 628 ns
CLOCK_BOOTTIME Linux 3.3 1 ns 628 ns
mach_absolute_time() Mac OS 10.6 1 ns 3 µs
CLOCK_MONOTONIC FreeBSD 8.2 11 ns 5 µs
CLOCK_MONOTONIC OpenBSD 5.0 10 ms 5 µs
CLOCK_UPTIME FreeBSD 8.2 11 ns 6 µs
CLOCK_MONOTONIC_COARSE Linux 3.3 1 ms 1 ms
CLOCK_MONOTONIC_COARSE Linux 3.0 4 ms 4 ms
GetTickCount64() Windows Seven 16 ms 15 ms

“OS Resolution”은 운영 체제가 공표하는 해상도입니다. “Python Resolution”은 clock_resolution.py 프로그램을 사용하여 Python에서 계산한 time 함수에 대한 두 호출 사이의 가장 작은 차이입니다.

mach_absolute_time

Mac OS X는 단조 시계인 mach_absolute_time()을 제공합니다. 시스템 부팅 이후 경과한 절대 시간을 기반으로 합니다. 조정되지 않으며 설정할 수 없습니다.

mach_timebase_info()는 시계 값을 나노초 단위의 수로 변환하는 분수를 제공합니다. Technical Q&A QA1398도 참조하십시오.

mach_absolute_time()은 PowerPC CPU에서는 절전 중에 중지되지만 Intel CPU에서는 중지되지 않습니다: Different behaviour of mach_absolute_time() on i386/ppc을 참조하십시오.

CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, CLOCK_BOOTTIME

CLOCK_MONOTONIC 및 CLOCK_MONOTONIC_RAW는 지정되지 않은 일부 시작 시점 이후의 단조 시간을 나타냅니다. 설정할 수 없습니다. 해상도는 clock_getres()를 사용하여 읽을 수 있습니다.

문서: 운영 체제의 매뉴얼 페이지를 참조하십시오. 예시는 다음과 같습니다:

CLOCK_MONOTONIC은 최소한 다음 운영 체제에서 사용할 수 있습니다:

  • DragonFly BSD, FreeBSD >= 5.0, OpenBSD, NetBSD
  • Linux
  • Solaris

다음 운영 체제는 CLOCK_MONOTONIC을 지원하지 않습니다:

Linux에서는 NTP가 CLOCK_MONOTONIC의 속도를 조정할 수 있지만(서서히 변경), 시간을 뒤로 이동시킬 수는 없습니다.

CLOCK_MONOTONIC_RAW는 Linux에만 해당합니다. CLOCK_MONOTONIC과 유사하지만 NTP 조정의 영향을 받지 않는 원시 하드웨어 기반 시간에 액세스할 수 있습니다. CLOCK_MONOTONIC_RAW에는 Linux 2.6.28 이상이 필요합니다.

Linux 2.6.39 및 glibc 2.14에서는 새로운 시계인 CLOCK_BOOTTIME을 도입합니다. CLOCK_BOOTTIME은 일시 중단 상태에서 보낸 시간도 포함한다는 점을 제외하면 CLOCK_MONOTONIC과 동일합니다. Waking systems from suspend (2011년 3월)도 참조하십시오.

CLOCK_MONOTONIC은 시스템이 일시 중단된 동안 멈춥니다.

Linux는 Linux 2.6.32부터 CLOCK_MONOTONIC_COARSE도 제공합니다. CLOCK_MONOTONIC과 비슷하지만, 정밀도가 낮고 더 빠릅니다.

시스템이 지정된 클록을 지원하지 않으면 표준 C 라이브러리가 해당 클록을 지원하더라도 clock_gettime()은 실패합니다. 예를 들어 CLOCK_MONOTONIC_RAW에는 커널 버전 2.6.28 이상이 필요합니다.

Windows: QueryPerformanceCounter

고해상도 성능 카운터입니다. 단조 증가합니다. 카운터의 주파수는 QueryPerformanceFrequency()를 사용하여 읽을 수 있습니다. 분해능은 1 / QueryPerformanceFrequency()입니다.

분해능은 훨씬 높지만 GetTickCount() 및 timeGetTime() 클록보다 장기 정밀도가 낮습니다. 예를 들어 저정밀도 클록에 비해 드리프트가 발생합니다.

문서:

QueryPerformanceCounter에서 사용하는 하드웨어 클록:

  • Windows XP: Intel 프로세서의 RDTSC 명령어이며, 클록 주파수는 프로세서의 주파수입니다(200MHz에서 3GHz 사이이며, 현재는 일반적으로 1GHz보다 높습니다).
  • Windows 2000: ACPI 전원 관리 타이머이며, 주파수 = 3,549,545Hz입니다. boot.ini의 “/usepmtimer” 플래그를 통해 강제로 사용할 수 있습니다.

QueryPerformanceFrequency()는 한 번만 호출해야 합니다. 시스템이 실행 중인 동안에는 주파수가 변경되지 않습니다. 설치된 하드웨어가 고해상도 성능 카운터를 지원하지 않으면 실패합니다.

QueryPerformanceCounter()는 조정할 수 없습니다. SetSystemTimeAdjustment()는 시스템 시간만 조정합니다.

버그:

  • 하드웨어 버그로 인해 성능 카운터 값이 예기치 않게 앞으로 도약할 수 있습니다. KB274323을 참조하십시오.
  • VirtualBox에서는 하위 부분이 오버플로될 때마다 QueryPerformanceCounter()가 상위 부분을 증가시키지 않습니다. Monotonic timers (2009)를 참조하십시오.
  • VirtualBox의 HPET 가상화 장치에 버그가 있어 QueryPerformanceCounter()가 약 42초만큼 앞으로 도약했습니다(issue #8707).
  • Windows XP에는 버그가 있었습니다(KB896256 참조). 다중 프로세서 컴퓨터에서 QueryPerformanceCounter()가 각 프로세서마다 서로 다른 값을 반환했습니다. 이 버그는 Windows XP SP2에서 수정되었습니다.
  • 가변 주파수 프로세서 관련 문제: 메모리 소비를 줄이기 위해 작업 부하에 따라 주파수가 변경됩니다.
  • Chromium은 “QueryPerformanceCounter is unreliable”이기 때문에 Athlon X2 CPU(모델 15)에서 QueryPerformanceCounter()를 사용하지 않습니다(Chromium 소스 코드의 base/time_win.cc 참조).

Windows: GetTickCount(), GetTickCount64()

GetTickCount() 및 GetTickCount64()는 단조적이며 실패할 수 없고 SetSystemTimeAdjustment()에 의해 조정되지 않습니다. MSDN 문서: GetTickCount(), GetTickCount64(). 해상도는 GetSystemTimeAdjustment()를 사용하여 읽을 수 있습니다.

GetTickCount() 또는 GetTickCount64()로 가져온 경과 시간에는 시스템이 절전 또는 최대 절전 모드에서 보내는 시간이 포함됩니다.

GetTickCount64()는 Windows Vista 및 Windows Server 2008에 추가되었습니다.

문서화되지 않은 NtSetTimerResolution() 함수를 사용하여 정밀도를 향상할 수 있습니다. 이 문서화되지 않은 함수를 사용하는 애플리케이션이 있으며, 예를 들면 Timer Resolution이 있습니다.

WaitForSingleObject()는 GetTickCount()와 동일한 타이머를 동일한 정밀도로 사용합니다.

Windows: timeGetTime

timeGetTime 함수는 시스템 시간을 밀리초 단위로 가져옵니다. 시스템 시간은 Windows가 시작된 후 경과한 시간입니다. timeGetTime() 문서를 참조하십시오.

timeGetTime()의 반환 형식은 32비트 부호 없는 정수입니다. GetTickCount()와 마찬가지로 timeGetTime()은 2^32밀리초(49.7일) 후에 오버플로됩니다.

timeGetTime()으로 가져온 경과 시간에는 시스템이 절전 모드에서 보내는 시간이 포함됩니다.

timeGetTime 함수의 기본 정밀도는 컴퓨터에 따라 5밀리초 이상일 수 있습니다.

timeBeginPeriod()를 사용하여 timeGetTime()의 정밀도를 최대 1밀리초까지 높일 수 있지만, 전력 소비에 부정적인 영향을 줍니다. timeBeginPeriod()를 호출하면 CreateWaitableTimer(), WaitForSingleObject() 및 Sleep()과 같은 일부 다른 시간 측정 호출의 세분성에도 영향을 줍니다.

Note

timeGetTime() 및 timeBeginPeriod()는 Windows 멀티미디어 라이브러리의 일부이므로, 프로그램을 winmm에 링크하거나 라이브러리를 동적으로 로드해야 합니다.

Solaris: CLOCK_HIGHRES

Solaris OS에는 최적의 하드웨어 소스를 사용하려고 시도하며 나노초에 가까운 해상도를 제공할 수 있는 CLOCK_HIGHRES 타이머가 있습니다. CLOCK_HIGHRES는 조정할 수 없는 고해상도 클록입니다. CLOCK_HIGHRES 값을 갖는 clockid_t로 생성된 타이머의 경우 시스템은 최적의 하드웨어 소스를 사용하려고 시도합니다.

CLOCK_HIGHRES의 해상도는 clock_getres()를 사용하여 읽을 수 있습니다.

Solaris: gethrtime

gethrtime() 함수는 현재의 고해상도 실시간을 반환합니다. 시간은 과거의 임의의 시점 이후 경과한 나노초로 표현되며, 하루 중 시각과 어떤 방식으로도 연관되지 않으므로 adjtime() 또는 settimeofday()를 통한 재설정이나 드리프트의 영향을 받지 않습니다. 저렴하고 정확한 구간 시간 측정이 필요한 성능 측정 작업에 hires 타이머가 이상적으로 적합합니다.

gethrtime()의 선형성은 일시 중지-재개 주기(Bug 4272663)를 거치는 동안 유지되지 않습니다.

Solaris 11의 gethrtime() 매뉴얼 페이지를 참조하십시오.

Solaris에서 gethrtime()은 clock_gettime(CLOCK_MONOTONIC)과 동일합니다.

시스템 시간

이름 C 해상도 절전 포함 일시 중단 포함
CLOCK_REALTIME 1 ns
CLOCK_REALTIME_COARSE 1 ns
GetSystemTimeAsFileTime 100 ns
gettimeofday() 1 µs
ftime() 1 ms
time() 1초

“C 해상도” 열은 기반이 되는 C 구조체의 해상도입니다.

x86_64에서의 클록 해상도 예시는 다음과 같습니다:

이름 운영 체제 운영 체제 해상도 Python 해상도
CLOCK_REALTIME SunOS 5.11 10 ms 238 ns
CLOCK_REALTIME Linux 3.0 1 ns 238 ns
gettimeofday() Mac OS 10.6 1 µs 4 µs
CLOCK_REALTIME FreeBSD 8.2 11 ns 6 µs
CLOCK_REALTIME OpenBSD 5.0 10 ms 5 µs
CLOCK_REALTIME_COARSE Linux 3.3 1 ms 1 ms
CLOCK_REALTIME_COARSE Linux 3.0 4 ms 4 ms
GetSystemTimeAsFileTime() Windows Seven 16 ms 1 ms
ftime() Windows Seven - 1 ms

“OS Resolution”은 운영 체제가 알리는 해상도입니다. “Python Resolution”은 clock_resolution.py 프로그램을 사용하여 Python에서 계산한 time 함수에 대한 두 호출 사이의 최소 차이입니다.

Windows: GetSystemTimeAsFileTime

GetSystemTimeAsFileTime(), ftime() 및 time()을 사용하여 시스템 시간을 읽을 수 있습니다. GetSystemTimeAdjustment()를 사용하여 시스템 시간의 해상도를 읽을 수 있습니다.

GetSystemTimeAsFileTime() documentation을 읽으십시오.

SetSystemTime()을 사용하여 시스템 시간을 설정할 수 있습니다.

UNIX의 시스템 시간

gettimeofday(), ftime(), time() 및 clock_gettime(CLOCK_REALTIME)은 시스템 시간을 반환합니다. clock_getres()를 사용하여 CLOCK_REALTIME의 해상도를 읽을 수 있습니다.

settimeofday() 또는 clock_settime(CLOCK_REALTIME)을 사용하여 시스템 시간을 설정할 수 있습니다.

Linux는 Linux 2.6.32부터 CLOCK_REALTIME_COARSE도 제공합니다. 이는 CLOCK_REALTIME과 유사하지만 정확도가 낮고 더 빠릅니다.

Alexander Shishkin은 시스템 시계가 변경될 때 알림을 받도록 Linux용 API를 제안했습니다: timerfd: add TFD_NOTIFY_CLOCK_SET to watch for clock changes (2011년 3월의 API 네 번째 버전). 이 API는 아직 채택되지 않았지만 CLOCK_BOOTTIME이 유사한 기능을 제공합니다.

프로세스 시간

프로세스 시간은 설정할 수 없습니다. 단조 증가하지 않습니다. 프로세스가 유휴 상태인 동안 시계가 멈춥니다.

이름 C 해상도 Sleep 포함 Suspend 포함
GetProcessTimes() 100 ns 아니요 아니요
CLOCK_PROCESS_CPUTIME_ID 1 ns 아니요 아니요
getrusage(RUSAGE_SELF) 1 µs 아니요 아니요
times() - 아니요 아니요
clock() - Windows에서는 예, 그 외에는 아니요 아니요

“C 해상도” 열은 기반 C 구조체의 해상도입니다.

x86_64에서 clock 해상도의 예시는 다음과 같습니다.

이름 운영 체제 운영 체제 해상도 Python 해상도
CLOCK_PROCESS_CPUTIME_ID Linux 3.3 1 ns 1 ns
CLOCK_PROF FreeBSD 8.2 10 ms 1 µs
getrusage(RUSAGE_SELF) FreeBSD 8.2 - 1 µs
getrusage(RUSAGE_SELF) SunOS 5.11 - 1 µs
CLOCK_PROCESS_CPUTIME_ID Linux 3.0 1 ns 1 µs
getrusage(RUSAGE_SELF) Mac OS 10.6 - 5 µs
clock() Mac OS 10.6 1 µs 5 µs
CLOCK_PROF OpenBSD 5.0 - 5 µs
getrusage(RUSAGE_SELF) Linux 3.0 - 4 ms
getrusage(RUSAGE_SELF) OpenBSD 5.0 - 8 ms
clock() FreeBSD 8.2 8 ms 8 ms
clock() Linux 3.0 1 µs 10 ms
times() Linux 3.0 10 ms 10 ms
clock() OpenBSD 5.0 10 ms 10 ms
times() OpenBSD 5.0 10 ms 10 ms
times() Mac OS 10.6 10 ms 10 ms
clock() SunOS 5.11 1 µs 10 ms
times() SunOS 5.11 1 µs 10 ms
GetProcessTimes() Windows Seven 16 ms 16 ms
clock() Windows Seven 1 ms 1 ms

“OS Resolution”은 운영 체제가 공표하는 해상도입니다. “Python Resolution”은 clock_resolution.py 프로그램을 사용하여 Python에서 계산한 time 함수에 대한 두 호출 사이의 가장 작은 차이입니다.

함수

  • Windows: GetProcessTimes()입니다. 해상도는 GetSystemTimeAdjustment()를 사용하여 읽을 수 있습니다.
  • clock_gettime(CLOCK_PROCESS_CPUTIME_ID): CPU에서 측정한 프로세스별 고해상도 타이머입니다. 해상도는 clock_getres()를 사용하여 읽을 수 있습니다.
  • clock()입니다. 분해능은 1 / CLOCKS_PER_SEC입니다.
    • Windows: 프로세스 시작 이후 경과한 실제 시계 시간입니다(경과 시간을 초 단위로 나타낸 값에 CLOCKS_PER_SEC를 곱한 값입니다). 수면 중 경과한 시간도 포함합니다. 실패할 수 있습니다.
    • UNIX: 프로그램이 사용한 프로세서 시간의 근삿값을 반환합니다.
  • getrusage(RUSAGE_SELF)는 현재 프로세스의 리소스 사용량 구조체를 반환합니다. ru_utime은 사용자 CPU 시간이고 ru_stime은 시스템 CPU 시간입니다.
  • times(): 프로세스 시간 구조체입니다. 분해능은 1 / ticks_per_seconds이며, 여기서 ticks_per_seconds는 sysconf(_SC_CLK_TCK) 또는 HZ 상수입니다.

Python 소스 코드에는 프로세스 시간(CPU 시간)을 가져오는 이식 가능한 라이브러리인 Tools/pybench/systimes.py가 포함되어 있습니다.

QueryProcessCycleTime() function (모든 스레드의 사이클 시간 합계) 및 clock_getcpuclockid()도 참조하십시오.

스레드 시간

스레드 시간은 설정할 수 없습니다. 단조 증가하지 않습니다. 스레드가 유휴 상태인 동안 시계가 멈춥니다.

이름 C 분해능 수면 포함 일시 중단 포함
CLOCK_THREAD_CPUTIME_ID 1 ns 에포크 변경
GetThreadTimes() 100 ns 아니요 ?

“C Resolution” 열은 기반이 되는 C 구조체의 분해능입니다.

x86_64에서 시계 분해능의 예:

이름 운영 체제 OS 해상도 Python 해상도
CLOCK_THREAD_CPUTIME_ID FreeBSD 8.2 1 µs 1 µs
CLOCK_THREAD_CPUTIME_ID Linux 3.3 1 ns 649 ns
GetThreadTimes() Windows Seven 16 ms 16 ms

“OS Resolution”은 운영 체제가 알리는 해상도입니다. “Python Resolution”은 clock_resolution.py 프로그램을 사용하여 Python에서 계산한 time 함수에 대한 두 호출 사이의 최소 차이입니다.

함수

  • Windows: GetThreadTimes(). GetSystemTimeAdjustment()를 사용하여 해상도를 읽을 수 있습니다.
  • clock_gettime(CLOCK_THREAD_CPUTIME_ID): 스레드별 CPU 시간 클록입니다. 초 수가 아니라 CPU 사이클 수를 사용합니다. clock_getres()를 사용하여 해상도를 읽을 수 있습니다.

QueryThreadCycleTime() function (지정된 스레드의 사이클 시간)과 pthread_getcpuclockid()도 참조하십시오.

Windows: QueryUnbiasedInterruptTime

편향된 인터럽트 시간과 현재 절전 편향량으로부터 현재 편향되지 않은 인터럽트 시간을 가져옵니다. 이 시간은 전원 관리에 따른 절전 전환의 영향을 받지 않습니다.

QueryUnbiasedInterruptTime 함수로 가져온 경과 시간에는 시스템이 작업 상태에 있는 동안의 시간만 포함됩니다. QueryUnbiasedInterruptTime()은 단조롭지 않습니다.

QueryUnbiasedInterruptTime()은 Windows 7에서 도입되었습니다.

QueryIdleProcessorCycleTime() function (각 프로세서의 유휴 스레드에 대한 사이클 시간)도 참조하십시오.

절전

프로세스의 실행을 주어진 초 수만큼 일시 중지합니다. Sleep은 시스템 시간 업데이트의 영향을 받지 않습니다. 시스템이 일시 중단되는 동안 Sleep이 일시 중지됩니다. 예를 들어 프로세스가 60초 동안 Sleep 중이고 Sleep 도중 시스템이 30초 동안 일시 중단되면, 실제 시간 기준 Sleep 기간은 90초입니다.

Sleep은 시그널로 중단될 수 있습니다. 함수는 EINTR과 함께 실패합니다.

이름 C 해상도
nanosleep() 1 ns
clock_nanosleep() 1 ns
usleep() 1 µs
delay() 1 µs
sleep() 1 sec

기타 함수:

이름 C 해상도
sigtimedwait() 1 ns
pthread_cond_timedwait() 1 ns
sem_timedwait() 1 ns
select() 1 µs
epoll() 1 ms
poll() 1 ms
WaitForSingleObject() 1 ms

“C Resolution” 열은 기반 C 구조체의 해상도입니다.

함수

clock_nanosleep

clock_nanosleep(clock_id, flags, nanoseconds, remaining): Linux manpage of clock_nanosleep()입니다.

flags가 TIMER_ABSTIME이면 request는 clock_id로 측정되는 절대 시간으로 해석됩니다. request가 클록의 현재 값보다 작거나 같으면 clock_nanosleep()은 호출 스레드를 일시 중단하지 않고 즉시 반환합니다.

POSIX.1은 clock_settime(2)을 통해 CLOCK_REALTIME 클록의 값을 변경해도 상대 clock_nanosleep()에서 블록된 스레드에는 아무런 영향을 주지 않아야 한다고 규정합니다.

select()

select(nfds, readfds, writefds, exceptfs, timeout).

Linux 2.6.28부터 select()는 시간 초과를 처리할 때 고해상도 타이머를 사용합니다. 프로세스에는 시간 초과의 정밀도를 구성하는 “slack” 속성이 있으며, 기본 slack은 50마이크로초입니다. Linux 2.6.28 이전에는 select()의 시간 초과가 jiffy 수준의 해상도로 주 타이밍 서브시스템에 의해 처리되었습니다. High- (but not too high-) resolution timeoutsTimer slack도 읽어 보십시오.

기타 함수

  • poll(), epoll()
  • sigtimedwait()입니다. POSIX: “단조 클록 옵션이 지원되면 timeout 인자로 지정된 시간 간격을 측정하는 데 CLOCK_MONOTONIC 클록을 사용해야 합니다.”
  • pthread_cond_timedwait(), pthread_condattr_setclock(). “클록 속성의 기본값은 시스템 시간을 참조해야 합니다.”
  • sem_timedwait(): “타이머 옵션이 지원되면 시간 초과는 CLOCK_REALTIME 클록을 기반으로 해야 합니다. 타이머 옵션이 지원되지 않으면 시간 초과는 time() 함수가 반환하는 시스템 시간을 기반으로 해야 합니다. 시간 초과의 정밀도는 해당 시간 초과가 기반으로 하는 클록의 정밀도여야 합니다.”
  • WaitForSingleObject(): GetTickCount()와 동일한 정밀도의 동일한 타이머를 사용합니다.

시스템 대기 모드

ACPI 전원 상태 “S3”은 시스템 대기 모드이며, “Suspend to RAM”이라고도 합니다. RAM에는 계속 전원이 공급됩니다.

Windows에서는 전원 관리 이벤트(예: 소유자 상태가 변경됨)를 알리기 위해 WM_POWERBROADCAST 메시지를 Windows 애플리케이션으로 보냅니다.

Mac OS X에서는 잠자기 및 깨우기 알림 등록 및 등록 해제 (기술 Q&A QA1340)를 읽으십시오.

각주

링크

관련 Python 이슈:

단조 시계를 제공하는 라이브러리:

  • Java: System.nanoTime
  • Qt 라이브러리: QElapsedTimer
  • glib 라이브러리: g_get_monotonic_time ()은 Windows에서 GetTickCount64()/GetTickCount()를 사용하고, UNIX에서 clock_gettime(CLOCK_MONOTONIC)을 사용하며, 그렇지 않으면 시스템 시계로 대체합니다.
  • python-monotonic-time (github)
  • Monoclock.nano_count()은 clock_gettime(CLOCK_MONOTONIC)을 사용하고 나노초 수를 반환합니다.
  • Thomas Habets가 제공하는 monotonic_clock
  • Perl: Time::HiRes는 clock_gettime(CLOCK_MONOTONIC)을 제공합니다.
  • Ruby: AbsoluteTime.now: clock_gettime(CLOCK_MONOTONIC), mach_absolute_time() 또는 gettimeofday()를 사용합니다. “AbsoluteTime.monotonic?” 메서드는 AbsoluteTime.now가 단조인지 여부를 나타냅니다.
  • libpthread: Windows용 POSIX 스레드 라이브러리입니다 (clock.c).
  • Boost.Chrono는 다음을 사용합니다.
    • system_clock:
      • mac = gettimeofday()
      • posix = clock_gettime(CLOCK_REALTIME)
      • win = GetSystemTimeAsFileTime()
    • steady_clock:
      • mac = mach_absolute_time()
      • posix = clock_gettime(CLOCK_MONOTONIC)
      • win = QueryPerformanceCounter()
    • high_resolution_clock:
      • steady_clock, 사용 가능하면 system_clock, 그렇지 않으면

시간:

승인

이 PEP는 2012-04-28에 Guido van Rossum에 의해 승인되었습니다 [1]. 이후 PEP 구현이 저장소에 커밋되었습니다.

참고 자료