VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/cpu/rdtsc.cpp@ 72549

Last change on this file since 72549 was 72549, checked in by vboxsync, 6 years ago

ValidationKit/rdtsc: Rewrote the rdtsc testcase to (hopefully) work with more than just 32-bit MSC. Need this to test TSC during pausing of NEM/win (bugref:9044).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: rdtsc.cpp 72549 2018-06-13 17:58:19Z vboxsync $ */
2/** @file
3 * rdtsc - Test if three consecutive rdtsc instructions return different values.
4 */
5
6/*
7 * Copyright (C) 2009-2017 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 <iprt/types.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <time.h>
35
36
37/*********************************************************************************************************************************
38* Structures and Typedefs *
39*********************************************************************************************************************************/
40typedef struct RDTSCRESULT
41{
42 RTCCUINTREG uLow, uHigh;
43} RDTSCRESULT;
44
45
46/*********************************************************************************************************************************
47* Global Variables *
48*********************************************************************************************************************************/
49extern "C" RDTSCRESULT g_aRdTscResults[]; /* rdtsc-asm.asm */
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55/**
56 * Does 3 (32-bit) or 6 (64-bit) fast TSC reads and stores the result
57 * in g_aRdTscResults, starting with the 2nd entry.
58 *
59 * Starting the result storing at g_aRdTscResults[1] make it easy to do the
60 * comparisons in a loop.
61 *
62 * @returns Number of results read into g_aRdTscResults[1] and onwards.
63 */
64DECLASM(uint32_t) DoTscReads(void);
65
66
67
68
69int main(int argc, char **argv)
70{
71
72 /*
73 * Tunables.
74 */
75 uint64_t offJumpThreshold = _4G * 2;
76 unsigned cMaxLoops = 10000000;
77 unsigned cStatusEvery = 2000000;
78 unsigned cMinSeconds = 0;
79
80 for (int i = 1; i < argc; i++)
81 {
82 const char *psz = argv[i];
83 if (*psz == '-')
84 {
85 psz++;
86 char chOpt;
87 while ((chOpt = *psz++) != '\0')
88 {
89 /* Option value. */
90 const char *pszValue = NULL;
91 unsigned long uValue = 0;
92 switch (chOpt)
93 {
94 case 'l':
95 case 's':
96 case 'm':
97 if (*psz == '\0')
98 {
99 if (i + 1 >= argc)
100 {
101 printf("syntax error: The %c option requires a value\n", chOpt);
102 return RTEXITCODE_SYNTAX;
103 }
104 pszValue = argv[++i];
105 }
106 else
107 pszValue = psz + (*psz == ':' || *psz == '=');
108 switch (chOpt)
109 {
110 case 'l':
111 case 's':
112 case 'm':
113 {
114 char *pszNext = NULL;
115 uValue = strtoul(pszValue, &pszNext, 0);
116 if (pszNext && *pszNext != '\0')
117 if (*pszNext == 'M'&& pszNext[1] == '\0')
118 uValue *= _1M;
119 else if (*pszNext == 'K' && pszNext[1] == '\0')
120 uValue *= _1K;
121 else if (*pszNext == 'G' && pszNext[1] == '\0')
122 uValue *= _1G;
123 else
124 {
125 printf("syntax error: Bad value format for option %c: %s\n", chOpt, pszValue);
126 return RTEXITCODE_SYNTAX;
127 }
128 break;
129 }
130 }
131 break;
132 }
133
134 /* handle the option. */
135 switch (chOpt)
136 {
137 case 'l':
138 cMaxLoops = uValue;
139 break;
140
141 case 'm':
142 cMinSeconds = uValue;
143 break;
144
145 case 's':
146 cStatusEvery = uValue;
147 break;
148
149 case 'h':
150 case '?':
151 printf("usage: rdtsc [-l <loops>] [-s <loops-between-status>]\n"
152 " [-m <minimum-seconds-to-run>]\n");
153 return RTEXITCODE_SUCCESS;
154
155 default:
156 printf("syntax error: Unknown option %c (argument %d)\n", chOpt, i);
157 return RTEXITCODE_SYNTAX;
158 }
159 }
160 }
161 else
162 {
163 printf("synatx error: argument %d (%s): not an option\n", i, psz);
164 return RTEXITCODE_SYNTAX;
165 }
166 }
167
168 /*
169 * Do the job.
170 */
171 time_t uSecStart;
172 time(&uSecStart);
173 unsigned cOuterLoops = 0;
174 unsigned cLoopsToNextStatus = cStatusEvery;
175 unsigned cRdTscInstructions = 0;
176 unsigned cBackwards = 0;
177 unsigned cSame = 0;
178 unsigned cBadValues = 0;
179 unsigned cJumps = 0;
180 uint64_t offMaxJump = 0;
181 uint64_t offMinIncr = UINT64_MAX;
182 uint64_t offMaxIncr = 0;
183
184 g_aRdTscResults[0] = g_aRdTscResults[DoTscReads() - 1];
185
186 for (;;)
187 {
188 for (unsigned iLoop = 0; iLoop < cMaxLoops; iLoop++)
189 {
190 uint32_t const cResults = DoTscReads();
191 cRdTscInstructions += cResults;
192
193 for (uint32_t i = 0; i < cResults; i++)
194 {
195 uint64_t uPrev = RT_MAKE_U64((uint32_t)g_aRdTscResults[i ].uLow, (uint32_t)g_aRdTscResults[i ].uHigh);
196 uint64_t uCur = RT_MAKE_U64((uint32_t)g_aRdTscResults[i + 1].uLow, (uint32_t)g_aRdTscResults[i + 1].uHigh);
197 if (RT_LIKELY(uCur != uPrev))
198 {
199 int64_t offDelta = uCur - uPrev;
200 if (RT_LIKELY(offDelta >= 0))
201 {
202 if (RT_LIKELY((uint64_t)offDelta < offJumpThreshold))
203 {
204 if ((uint64_t)offDelta < offMinIncr)
205 offMinIncr = offDelta;
206 if ((uint64_t)offDelta > offMaxIncr && i != 0)
207 offMaxIncr = offDelta;
208 }
209 else
210 {
211 cJumps++;
212 if ((uint64_t)offDelta > offMaxJump)
213 offMaxJump = offDelta;
214 printf("%u/%u: Jump: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
215 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
216 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
217 }
218 }
219 else
220 {
221 cBackwards++;
222 printf("%u/%u: Back: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
223 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
224 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
225 }
226 }
227 else
228 {
229 cSame++;
230 printf("%u/%u: Same: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
231 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
232 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
233 }
234#if ARCH_BITS == 64
235 if ((g_aRdTscResults[i + 1].uLow >> 32) || (g_aRdTscResults[i + 1].uHigh >> 32))
236 cBadValues++;
237#endif
238 }
239
240 /* Copy the last value for the next iteration. */
241 g_aRdTscResults[0] = g_aRdTscResults[cResults];
242
243 /* Display status. */
244 if (RT_LIKELY(--cLoopsToNextStatus > 0))
245 { /* likely */ }
246 else
247 {
248 cLoopsToNextStatus = cStatusEvery;
249 printf("%u/%u: %#010x`%08x\n", cOuterLoops, iLoop,
250 (unsigned)g_aRdTscResults[cResults].uHigh, (unsigned)g_aRdTscResults[cResults].uLow);
251 }
252 }
253
254 /*
255 * Check minimum number of seconds.
256 */
257 cOuterLoops++;
258 if (!cMinSeconds)
259 break;
260 time_t uSecNow;
261 if ( time(&uSecNow) == -1
262 || cMinSeconds == -1
263 || uSecNow - uSecStart >= cMinSeconds)
264 break;
265 }
266
267 /*
268 * Summary.
269 */
270 if (cBackwards == 0 && cSame == 0 && cJumps == 0 && cBadValues == 0)
271 {
272 printf("rdtsc: Success (%u RDTSC over %u*%u loops, deltas: %#x`%08x..%#x`%08x)\n",
273 cRdTscInstructions, cOuterLoops, cMaxLoops,
274 (unsigned)(offMinIncr >> 32), (unsigned)offMinIncr, (unsigned)(offMaxIncr >> 32), (unsigned)offMaxIncr);
275 return RTEXITCODE_SUCCESS;
276 }
277 printf("RDTSC instructions: %u\n", cRdTscInstructions);
278 printf("Loops: %u * %u => %u\n", cMaxLoops, cOuterLoops, cOuterLoops * cMaxLoops);
279 printf("Backwards: %u\n", cBackwards);
280 printf("Jumps: %u\n", cJumps);
281 printf("Max jumps: %#010x`%08x\n", (unsigned)(offMaxJump >> 32), (unsigned)offMaxJump);
282 printf("Same value: %u\n", cSame);
283 printf("Bad values: %u\n", cBadValues);
284 printf("Min increment: %#010x`%08x\n", (unsigned)(offMinIncr >> 32), (unsigned)offMinIncr);
285 printf("Max increment: %#010x`%08x\n", (unsigned)(offMaxIncr >> 32), (unsigned)offMaxIncr);
286 return RTEXITCODE_FAILURE;
287}
288
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