2019. 9. 20. 17:01 기타 상식
프로그램에서 CPU 시간정보 얻는법
프로그래밍 중 매 Tick 마다 혹은 매 초마다 특정 루틴을 실행해야하거나
프로그램이 실행된 시작 시간 혹은 지금까지의 가동 시간 등을 알아야 하는 경우가 생기기 마련이다.
이런 경우 각 언어, 플랫폼마다 여러 방식으로 확인할 수 있는 방법이 있는데 이 방법들에 대해서 알아보자.
우선 C 혹은 C++의 경우 주로 사용하는 방법은 QueryPerformanceFrequency 함수등과 관련된 방법이다.
참고 : http://egloos.zum.com/NeoTrinity/v/943773
일단 주요 원리는 특정 루틴의 호출 시점, 종료시점에서 시간을 측정해서 시간 경과를 측정하는 것이다.
개인적으로 Clock() 함수 혹은 timeGetTime() 함수는 사용해보지 않았기 때문에
QueryPerformanceFrequency / QueryPerformanceCounter 함수와 관련된 내용만 적어보려고 한다.
우선 두 함수 모두 Windows.h 에 포함된 함수이며 각각 CPU의 현재의 연산주기, 연산횟수를 얻어오는데 쓰인다.
[계산주기, 횟수라고 한것은 영어 원문에선 performance-counter라고 되어 있음]
위 두가지를 사용하여 시간을 측정하는 방법은 아래의 순서로 진행된다.
1. 우선 QueryPerformanceFrequency를 통해서 현재 프로그램이 돌아가는 장치의 계산주기를 얻는다.
2. QueryPerformanceCounter 함수를 특정 로직의 앞, 뒤에서 호출하여 start, end 시의 계산 횟수를 구한다.
* 이 때 end-start 를 통해서 특정 로직의 수행시 cpu가 몇번의 계산을 했는지 알 수 있다.[deltaCount]
3. 위의 deltaCount의 값을 계산주기로 나누면 경과한 시간을 알 수 있다.
* 계산주기=[계산횟수/시간] 이기 때문에 경과시간 = deltaCount / (계산횟수 / 단위시간) 이 된다.
그렇다면 C#의 경우는 어떤 방법들이 있을까?
우선 C#에서도 C++에서 사용하는 QueryPerformanceCounter 함수들을 사용하는 방법도 있다.
이 경우, DllImport를 사용하여 QueryPerformanceCounter, QueryPerformanceFrequency를선언하면 된다.
public class QueryPerfCounter
{
[DllImport("KERNEL32")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
private long start;
private long stop;
private long frequency;
double multiplier = 1.0e6; // usecs / sec
public QueryPerfCounter()
{
if (QueryPerformanceFrequency(out frequency) == false)
{
// Frequency not supported
throw new Win32Exception();
}
}
public void Start()
{
QueryPerformanceCounter(out start);
}
public void Stop()
{
QueryPerformanceCounter(out stop);
}
public double Duration(int iterations)
{
return ((((stop - start) * multiplier) / frequency) / iterations);
}
이 방법보다 좀더 간편한 방법으로는 stopwatch를 사용하는 방법이다.
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Thread.Sleep(10000);
stopWatch.Stop();
// Get the elapsed time as a TimeSpan value.
TimeSpan ts = stopWatch.Elapsed;
// Format and display the TimeSpan value.
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
}
}
내부적으로는 위의 dll을 사용하는 방식과 별 차이는 없다고 한다.
* stopwatch는 .Net2.0 버전 이후부터 지원
* 밑의 DateTime 보다는 정밀하게 측정이 가능하다고 함.
마지막으로 제일 간단한 방법으로는 DateTime을 통한 Tick값 비교이다.
DateTime StartTime = DateTime.Now;
//Code
TimeSpan ts = DateTime.Now.Subtract(StartTime);
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine(elapsedTime, "RunTime");
* 다만, 이 방법의 경우 외부 프로세스의 영향 혹은 메모리 스왑등에 영향을 받아 함수의 첫 실행 시 소요시간이 그 이후 소요시간보다 크게 측정되는 문제가 있다고 한다.
'기타 상식' 카테고리의 다른 글
SaaS/PaaS/IaaS란? (0) | 2020.05.29 |
---|---|
software license 에 대하여. (0) | 2020.05.27 |
함수 호출 정보에 관하여 (0) | 2019.09.05 |
게임에서의 랜덤값에 대해서 (0) | 2019.09.02 |
FirebaseMessage 란? (0) | 2019.07.31 |