성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - DateTime.Ticks의 정밀도</h1> <p> 지난 글에서,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 윈도우 운영체제의 시간 함수 (1) - GetTickCount와 timeGetTime의 차이점 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11063'>http://www.sysnet.pe.kr/2/0/11063</a> 윈도우 운영체제의 시간 함수 (2) - Sleep 함수의 동작 방식 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11065'>http://www.sysnet.pe.kr/2/0/11065</a> 윈도우 운영체제의 시간 함수 (3) - QueryInterruptTimePrecise, QueryInterruptTime 함수 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11066'>http://www.sysnet.pe.kr/2/0/11066</a> 윈도우 운영체제의 시간 함수 (4) - RTC, TSC, PM Clock, HPET Timer ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11067'>http://www.sysnet.pe.kr/2/0/11067</a> 윈도우 운영체제의 시간 함수 (5) - TSC(Time Stamp Counter)와 QueryPerformanceCounter ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11068'>http://www.sysnet.pe.kr/2/0/11068</a> </pre> <br /> 운영체제 수준에서 제공되는 시간 정밀도를 살펴봤는데요. 그럼, C#의 경우에는 어떻게 될까요? 오늘은 그 첫 번째로 <a target='tab' href='https://devblogs.microsoft.com/dotnet/announcing-dotnet-7-preview-4/#adding-microseconds-and-nanoseconds-to-timestamp-datetime-datetimeoffset-and-timeonly'>DateTime</a>.Ticks를 살펴보겠습니다.<br /> <br /> 간단하게 소스 코드를 보면, 답이 나오는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [MethodImpl(MethodImplOptions.InternalCall)] internal static extern long GetSystemTimeAsFileTime(); public static DateTime UtcNow { get { return new DateTime((ulong) ((GetSystemTimeAsFileTime() + 0x701ce1722770000L) | 0x4000000000000000L)); } } </pre> <br /> 다름 아닌 GetSystemTimeAsFileTime의 정밀도를 기반으로 만들어졌습니다. 이는 "Current timer interval"의 변화에 따라 정밀도가 변화한다는 것을 의미합니다. 즉, timeBeginPeriod/timeEndPeriod가 호출되지 않은 일반적인 윈도우 시스템의 15.625ms 기본 상태에서는 DateTime.Ticks 속성도 15.625ms 단위마다 시간이 바뀌게 된다는 것을 의미합니다.<br /> <br /> 실제로 다음과 같이 테스트해볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; class Program { static void Main(string[] args) { int count = 100000; long[] tickBuf = new long[count]; for (int i = 0; i < count; i++) { tickBuf[i] = DateTime.Now.Ticks; } long oldTime = tickBuf[0]; long elapsed; for (int i = 1; i < count; i++) { elapsed = tickBuf[i] - oldTime; oldTime = tickBuf[i]; if (elapsed != 0) { Console.WriteLine(elapsed); } } } } /* 출력 결과: 156292 */ </pre> <br /> 위에서 100,000번의 루프를 도는 동안 DateTime.Now.Ticks로 계속 시간을 재보지만 15.625ms의 타이머 간격을 가진 윈도우에서는 tickBuf 배열에 동일한 값만을 가지다가 어쩌다 시간이 바뀔 때가 되면 15.625에 가까운 시간 값이 출력됩니다.<br /> <br /> 위의 출력 결과에 보면 156,292값이 나오는데, <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/api/system.datetime.ticks#System_DateTime_Ticks'>DateTime.Ticks의 1은 100ns이므로 10,000</a>으로 나누어 15.6292ms 값이 나옵니다. (대충 값이 비슷합니다.)<br /> <br /> 물론, timeBeginPeriod / timeEndPeriod로 clockres를 조절하면 다음과 같이 1ms 수준으로 정밀도를 낮출 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Runtime.InteropServices; class Program { [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")] public static extern uint timeBeginPeriod(uint uMilliseconds); [DllImport("winmm.dll", EntryPoint = "timeEndPeriod")] public static extern uint timeEndPeriod(uint uMilliseconds); static void Main(string[] args) { timeBeginPeriod(1); int count = 100000; long[] tickBuf = new long[count]; for (int i = 0; i &lt; count; i++) { tickBuf[i] = DateTime.Now.Ticks; } long oldTime = tickBuf[0]; long elapsed; for (int i = 1; i &lt; count; i++) { elapsed = tickBuf[i] - oldTime; oldTime = tickBuf[i]; if (elapsed != 0) { Console.WriteLine(elapsed); } } timeEndPeriod(1); } } /* 출력 결과: 10013 9965 9992 10001 10007 10014 9989 10001 9998 10052 9941 10001 */ </pre> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1070&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 정리하자면!<br /> <br /> 타이머 간격이 (기본 설정인) 15.625ms인 시스템을 기준으로, DateTime.Ticks로 특정 코드의 실행 성능을 재는 경우 15ms 이내에 수행되면 측정값이 0ms로 결과가 나올 수 있습니다. 또는, 운(?) 좋게 tick이 중간에 실행하는 경우 실제로 코드 수행에 소요된 시간은 2ms인데도 15ms 이상으로 나올 수 있는 부작용도 있습니다.<br /> <br /> 따라서, DateTime.Ticks로 실행 성능을 측정하고 싶다면 초 단위 수준(또는 적어도 100ms 정도)의 정밀도가 필요한 경우가 좋습니다. <br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1348
(왼쪽의 숫자를 입력해야 합니다.)