VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/nt/nttimesources.cpp@ 60441

Last change on this file since 60441 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/* $Id: nttimesources.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * Check the various time sources on Windows NT.
4 */
5
6/*
7 * Copyright (C) 2009-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <Windows.h>
32
33#include <iprt/asm.h>
34#include <iprt/asm-amd64-x86.h>
35#include <iprt/err.h>
36#include <iprt/string.h>
37#include <iprt/test.h>
38
39
40/*********************************************************************************************************************************
41* Structures and Typedefs *
42*********************************************************************************************************************************/
43typedef struct _MY_KSYSTEM_TIME
44{
45 ULONG LowPart;
46 LONG High1Time;
47 LONG High2Time;
48} MY_KSYSTEM_TIME;
49
50typedef struct _MY_KUSER_SHARED_DATA
51{
52 ULONG TickCountLowDeprecated;
53 ULONG TickCountMultiplier;
54 volatile MY_KSYSTEM_TIME InterruptTime;
55 volatile MY_KSYSTEM_TIME SystemTime;
56 volatile MY_KSYSTEM_TIME TimeZoneBias;
57 /* The rest is not relevant. */
58} MY_KUSER_SHARED_DATA;
59
60/** The fixed pointer to the user shared data. */
61#define MY_USER_SHARED_DATA ((MY_KUSER_SHARED_DATA *)0x7ffe0000)
62
63/** Spins until GetTickCount() changes. */
64static void SpinUntilTick(void)
65{
66 /* spin till GetTickCount changes. */
67 DWORD dwMsTick = GetTickCount();
68 while (GetTickCount() == dwMsTick)
69 /* nothing */;
70}
71
72/** Delay function that tries to return right after GetTickCount changed. */
73static void DelayMillies(DWORD dwMsStart, DWORD cMillies)
74{
75 /* Delay cMillies - 1. */
76 Sleep(cMillies - 1);
77 while (GetTickCount() - dwMsStart < cMillies - 1U)
78 Sleep(1);
79
80 SpinUntilTick();
81}
82
83
84int main(int argc, char **argv)
85{
86 /*
87 * Init, create a test instance and "parse" arguments.
88 */
89 RTTEST hTest;
90 int rc = RTTestInitAndCreate("nttimesources", &hTest);
91 if (rc)
92 return rc;
93 if (argc > 1)
94 {
95 RTTestFailed(hTest, "Syntax error! no arguments expected");
96 return RTTestSummaryAndDestroy(hTest);
97 }
98
99 /*
100 * Guess MHz using GetTickCount.
101 */
102 RTTestSub(hTest, "Guess MHz");
103 DWORD dwTickStart, dwTickEnd, cMsTicks;
104 uint64_t u64TscStart, u64TscEnd, cTscTicks;
105
106 /* get a good start time. */
107 SpinUntilTick();
108 do
109 {
110 dwTickStart = GetTickCount();
111 ASMCompilerBarrier();
112 ASMSerializeInstruction();
113 u64TscStart = ASMReadTSC();
114 ASMCompilerBarrier();
115 } while (GetTickCount() != dwTickStart);
116
117 /* delay a good while. */
118 DelayMillies(dwTickStart, 256);
119
120 /* get a good end time. */
121 do
122 {
123 dwTickEnd = GetTickCount();
124 ASMCompilerBarrier();
125 ASMSerializeInstruction();
126 u64TscEnd = ASMReadTSC();
127 ASMCompilerBarrier();
128 } while (GetTickCount() != dwTickEnd);
129 cMsTicks = dwTickEnd - dwTickStart;
130 cTscTicks = u64TscEnd - u64TscStart;
131
132 /* Calc an approximate TSC frequency:
133 cTscTicks / uTscHz = cMsTicks / 1000
134 1 / uTscHz = (cMsTicks / 1000) / cTscTicks
135 uTscHz = cTscTicks / (cMsTicks / 1000) */
136 uint64_t u64TscHz = (long double)cTscTicks / ((long double)cMsTicks / 1000.0);
137 if ( u64TscHz > _1M*3
138 && u64TscHz < _1T)
139 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "u64TscHz=%'llu", u64TscHz);
140 else
141 {
142 RTTestFailed(hTest, "u64TscHz=%'llu - out of range", u64TscHz);
143 u64TscHz = 0;
144 }
145
146
147 /*
148 * Pit GetTickCount, InterruptTime, Performance Counters and TSC against each other.
149 */
150 LARGE_INTEGER PrfHz;
151 LARGE_INTEGER PrfStart, PrfEnd, cPrfTicks;
152 LARGE_INTEGER IntStart, IntEnd, cIntTicks;
153 for (uint32_t i = 0; i < 7; i++)
154 {
155 RTTestSubF(hTest, "The whole bunch - pass #%u", i + 1);
156
157 if (!QueryPerformanceFrequency(&PrfHz))
158 {
159 RTTestFailed(hTest, "QueryPerformanceFrequency failed (%u)", GetLastError());
160 return RTTestSummaryAndDestroy(hTest);
161 }
162
163 /* get a good start time. */
164 SpinUntilTick();
165 do
166 {
167 IntStart.HighPart = MY_USER_SHARED_DATA->InterruptTime.High1Time;
168 IntStart.LowPart = MY_USER_SHARED_DATA->InterruptTime.LowPart;
169 dwTickStart = GetTickCount();
170 if (!QueryPerformanceCounter(&PrfStart))
171 {
172 RTTestFailed(hTest, "QueryPerformanceCounter failed (%u)", GetLastError());
173 return RTTestSummaryAndDestroy(hTest);
174 }
175 ASMCompilerBarrier();
176 ASMSerializeInstruction();
177 u64TscStart = ASMReadTSC();
178 ASMCompilerBarrier();
179 } while ( MY_USER_SHARED_DATA->InterruptTime.High2Time != IntStart.HighPart
180 || MY_USER_SHARED_DATA->InterruptTime.LowPart != IntStart.LowPart
181 || GetTickCount() != dwTickStart);
182
183 /* delay a good while. */
184 DelayMillies(dwTickStart, 256);
185
186 /* get a good end time. */
187 do
188 {
189 IntEnd.HighPart = MY_USER_SHARED_DATA->InterruptTime.High1Time;
190 IntEnd.LowPart = MY_USER_SHARED_DATA->InterruptTime.LowPart;
191 dwTickEnd = GetTickCount();
192 if (!QueryPerformanceCounter(&PrfEnd))
193 {
194 RTTestFailed(hTest, "QueryPerformanceCounter failed (%u)", GetLastError());
195 return RTTestSummaryAndDestroy(hTest);
196 }
197 ASMCompilerBarrier();
198 ASMSerializeInstruction();
199 u64TscEnd = ASMReadTSC();
200 ASMCompilerBarrier();
201 } while ( MY_USER_SHARED_DATA->InterruptTime.High2Time != IntEnd.HighPart
202 || MY_USER_SHARED_DATA->InterruptTime.LowPart != IntEnd.LowPart
203 || GetTickCount() != dwTickEnd);
204
205 cMsTicks = dwTickEnd - dwTickStart;
206 cTscTicks = u64TscEnd - u64TscStart;
207 cIntTicks.QuadPart = IntEnd.QuadPart - IntStart.QuadPart;
208 cPrfTicks.QuadPart = PrfEnd.QuadPart - PrfStart.QuadPart;
209
210 /* Recalc to micro seconds. */
211 uint64_t u64MicroSecMs = (uint64_t)cMsTicks * 1000;
212 uint64_t u64MicroSecTsc = u64TscHz ? (long double)cTscTicks / u64TscHz * 1000000 : u64MicroSecMs;
213 uint64_t u64MicroSecInt = cIntTicks.QuadPart / 10; /* 100ns units*/
214 uint64_t u64MicroSecPrf = (long double)cPrfTicks.QuadPart / PrfHz.QuadPart * 1000000;
215
216 /* check how much they differ using the millisecond tick count as the standard candle. */
217 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, " %9llu / %7lld us - GetTickCount\n", u64MicroSecMs, 0);
218
219 int64_t off = u64MicroSecTsc - u64MicroSecMs;
220 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, " %9llu / %7lld us - TSC\n", u64MicroSecTsc, off);
221 RTTEST_CHECK(hTest, RT_ABS(off) < 50000 /*us*/); /* some extra uncertainty with TSC. */
222
223 off = u64MicroSecInt - u64MicroSecMs;
224 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, " %9llu / %7lld us - InterruptTime\n", u64MicroSecInt, off);
225 RTTEST_CHECK(hTest, RT_ABS(off) < 25000 /*us*/);
226
227 off = u64MicroSecPrf - u64MicroSecMs;
228 RTTestPrintf(hTest, RTTESTLVL_ALWAYS, " %9llu / %7lld us - QueryPerformanceCounter\n", u64MicroSecPrf, off);
229 RTTEST_CHECK(hTest, RT_ABS(off) < 25000 /*us*/);
230 }
231
232 return RTTestSummaryAndDestroy(hTest);
233}
234
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette