Programming Language/C#

[C#] Stopwatch 클래스 이해하기

  • -
using System.Diagnostics

 

Stopwatch 클래스로 어느 간격에 대한 경과 시간을 측정할 수 있다.

 

일반적으로 Start 메서드를 호출한 다음 Stop 메서드를 호출하고,

이후 Elapsed 속성을 사용하여 경과 시간을 확인할 수 있다.

 

Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 1000000000; ++i) { } sw.Stop(); Console.WriteLine($"Elapsed: {sw.Elapsed}"); Console.WriteLine($"ElapsedMilliseconds: {sw.ElapsedMilliseconds}"); Console.WriteLine($"ElapsedTicks: {sw.ElapsedTicks}");

 

 

Stopwatch는 기본 타이머 메커니즘에서 타이머 Tick을 카운트하여 경과 시간을 측정한다.

Tick은 Stopwatch 타이머가 측정할 수 있는 가장 작은 시간 단위이며, 내부 시스템 시간을 측정하는 임의의 시간 단위이다. 

 

ElapsedTicks는 경과된 틱 수를 나타낸다. 이를 Frequency 필드로 나눠 초 단위로 변환한다.

 

즉, Frequency초당 몇 번의 Tick이 흐르는지를 나타내고, 이는 타이머 정밀도와 resolution 나타낸다.

 

(Stopwatch의 Tick은 DateTime의 Tick과는 다르다.)

public static readonly long Frequency = QueryPerformanceFrequency(); public static readonly bool IsHighResolution = true;
private static unsafe long QueryPerformanceFrequency() { long resolution; Interop.BOOL result = Interop.Kernel32.QueryPerformanceFrequency(&resolution); // The P/Invoke is documented to never fail on Windows XP or later Debug.Assert(result != Interop.BOOL.FALSE); return resolution; }

 

위는 Windows 환경에서의 Frequency이다.

 

설치된 하드웨어 및 운영 체제가 high resolution 성능 카운터를 지원하는 경우 Frequency 값은 해당 카운터의 주파수를 반영하고, 그렇지 않으면 시스템 타이머 주파수를 기준으로 한다.

 

시스템이 실행되는 동안에는 Frequency 값은 일정하게 유지된다. (readonly)

 

출력해보면 다음과 같다.

 

Console.WriteLine($"Frequency: {Stopwatch.Frequency}");

 

 

처음 출력된 결과로 보자면, ElapsedTick가 11,904,240이고 Frequency는 10,000,000였으므로

11,904,240 / 10,000,000 = 1.190424 초가 되는 것이다.

 

Frequency가 1000만이면 1초당 1000만 번의 틱이 흐르는 것이고, 10억 나노초당 1000만 틱이므로,

100나노초당 1틱이라고 할 수 있다.

 

 

Stopwatch.Start()

public void Start() { if (!_isRunning) { _startTimeStamp = GetTimestamp(); _isRunning = true; } }

 

타이머를 시작한다.

isRunning이 true면 무시한다.

 

 

Stopwatch.Stop()

public void Stop() { if (_isRunning) { long endTimeStamp = GetTimestamp(); long elapsedThisPeriod = endTimeStamp - _startTimeStamp; _elapsed += elapsedThisPeriod; _isRunning = false; if (_elapsed < 0) { _elapsed = 0; } } }

 

타이머를 멈추고 경과된 시간을 _elased에 저장한다.

isRunning이 false면 무시한다.

if (_elapsed < 0) 문이 존재하는 이유는 아래의 이유와 같이 버그 예외처리다.

짧은 기간을 측정할 때 Stopwatch.Elapsed 속성은 음수 값을 반환할 수 있습니다.
이는 가변 속도 CPU를 사용하는 컴퓨터의 기본 입력/출력 시스템(BIOS) 또는 하드웨어 추상화 계층(HAL)의 버그 때문입니다. (예: 인텔 스피드스텝) 

 

 

Stopwatch.Reset()

public void Reset() { _elapsed = 0; _isRunning = false; _startTimeStamp = 0; }

 

타이머를 멈추고 모든 필드를 0으로 초기화한다.

 

Stopwatch.StartNew()

public static Stopwatch StartNew() { Stopwatch s = new Stopwatch(); s.Start(); return s; }

 

인스턴스를 생성해서 Start하는 코드로 두 줄을 쓰기 싫다면, static 메소드로 제공된 위의 메소드를 사용하면 된다.

 

 

Stopwatch.Restart()

// Convenience method for replacing {sw.Reset(); sw.Start();} with a single sw.Restart() public void Restart() { _elapsed = 0; _startTimeStamp = GetTimestamp(); _isRunning = true; }

이것도 주석과 같이 Reset과 Start하는 코드로 두 줄을 쓰기 싫으면 해당 메소드를 사용하면 된다.

 

 

https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=net-8.0

 

Stopwatch Class (System.Diagnostics)

Provides a set of methods and properties that you can use to accurately measure elapsed time.

learn.microsoft.com

https://superuser.com/questions/101183/what-is-a-cpu-tick

 

What is a CPU tick?

Question: How is a CPU tick calculated and what does it represent? Does a single tick equate to 10 miliseconds thus if some thread reported not called for (5 * 10 ticks = 500 ticks) does this mean...

superuser.com

 

개인 공부용 포스팅인 점을 참고하시고, 잘못된 부분이 있다면 댓글로 남겨주시면 감사드리겠습니다.

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.