VirtualBox

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

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 KB
Line 
1/* $Id: rdtsc.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * rdtsc - Test if three consecutive rdtsc instructions return different values.
4 */
5
6/*
7 * Copyright (C) 2009-2019 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 {
118 if (*pszNext == 'M'&& pszNext[1] == '\0')
119 uValue *= _1M;
120 else if (*pszNext == 'K' && pszNext[1] == '\0')
121 uValue *= _1K;
122 else if (*pszNext == 'G' && pszNext[1] == '\0')
123 uValue *= _1G;
124 else
125 {
126 printf("syntax error: Bad value format for option %c: %s\n", chOpt, pszValue);
127 return RTEXITCODE_SYNTAX;
128 }
129 }
130 break;
131 }
132 }
133 break;
134 }
135
136 /* handle the option. */
137 switch (chOpt)
138 {
139 case 'l':
140 cMaxLoops = uValue;
141 break;
142
143 case 'm':
144 cMinSeconds = uValue;
145 break;
146
147 case 's':
148 cStatusEvery = uValue;
149 break;
150
151 case 'h':
152 case '?':
153 printf("usage: rdtsc [-l <loops>] [-s <loops-between-status>]\n"
154 " [-m <minimum-seconds-to-run>]\n");
155 return RTEXITCODE_SUCCESS;
156
157 default:
158 printf("syntax error: Unknown option %c (argument %d)\n", chOpt, i);
159 return RTEXITCODE_SYNTAX;
160 }
161 }
162 }
163 else
164 {
165 printf("synatx error: argument %d (%s): not an option\n", i, psz);
166 return RTEXITCODE_SYNTAX;
167 }
168 }
169
170 /*
171 * Do the job.
172 */
173 time_t uSecStart;
174 time(&uSecStart);
175 unsigned cOuterLoops = 0;
176 unsigned cLoopsToNextStatus = cStatusEvery;
177 unsigned cRdTscInstructions = 0;
178 unsigned cBackwards = 0;
179 unsigned cSame = 0;
180 unsigned cBadValues = 0;
181 unsigned cJumps = 0;
182 uint64_t offMaxJump = 0;
183 uint64_t offMinIncr = UINT64_MAX;
184 uint64_t offMaxIncr = 0;
185
186 g_aRdTscResults[0] = g_aRdTscResults[DoTscReads() - 1];
187
188 for (;;)
189 {
190 for (unsigned iLoop = 0; iLoop < cMaxLoops; iLoop++)
191 {
192 uint32_t const cResults = DoTscReads();
193 cRdTscInstructions += cResults;
194
195 for (uint32_t i = 0; i < cResults; i++)
196 {
197 uint64_t uPrev = RT_MAKE_U64((uint32_t)g_aRdTscResults[i ].uLow, (uint32_t)g_aRdTscResults[i ].uHigh);
198 uint64_t uCur = RT_MAKE_U64((uint32_t)g_aRdTscResults[i + 1].uLow, (uint32_t)g_aRdTscResults[i + 1].uHigh);
199 if (RT_LIKELY(uCur != uPrev))
200 {
201 int64_t offDelta = uCur - uPrev;
202 if (RT_LIKELY(offDelta >= 0))
203 {
204 if (RT_LIKELY((uint64_t)offDelta < offJumpThreshold))
205 {
206 if ((uint64_t)offDelta < offMinIncr)
207 offMinIncr = offDelta;
208 if ((uint64_t)offDelta > offMaxIncr && i != 0)
209 offMaxIncr = offDelta;
210 }
211 else
212 {
213 cJumps++;
214 if ((uint64_t)offDelta > offMaxJump)
215 offMaxJump = offDelta;
216 printf("%u/%u: Jump: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
217 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
218 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
219 }
220 }
221 else
222 {
223 cBackwards++;
224 printf("%u/%u: Back: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
225 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
226 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
227 }
228 }
229 else
230 {
231 cSame++;
232 printf("%u/%u: Same: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
233 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
234 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
235 }
236#if ARCH_BITS == 64
237 if ((g_aRdTscResults[i + 1].uLow >> 32) || (g_aRdTscResults[i + 1].uHigh >> 32))
238 cBadValues++;
239#endif
240 }
241
242 /* Copy the last value for the next iteration. */
243 g_aRdTscResults[0] = g_aRdTscResults[cResults];
244
245 /* Display status. */
246 if (RT_LIKELY(--cLoopsToNextStatus > 0))
247 { /* likely */ }
248 else
249 {
250 cLoopsToNextStatus = cStatusEvery;
251 printf("%u/%u: %#010x`%08x\n", cOuterLoops, iLoop,
252 (unsigned)g_aRdTscResults[cResults].uHigh, (unsigned)g_aRdTscResults[cResults].uLow);
253 }
254 }
255
256 /*
257 * Check minimum number of seconds.
258 */
259 cOuterLoops++;
260 if (!cMinSeconds)
261 break;
262 time_t uSecNow;
263 if ( time(&uSecNow) == (time_t)-1
264 || uSecNow == (time_t)-1
265 || uSecStart == (time_t)-1
266 || uSecNow - uSecStart >= (time_t)cMinSeconds)
267 break;
268 }
269
270 /*
271 * Summary.
272 */
273 if (cBackwards == 0 && cSame == 0 && cJumps == 0 && cBadValues == 0)
274 {
275 printf("rdtsc: Success (%u RDTSC over %u*%u loops, deltas: %#x`%08x..%#x`%08x)\n",
276 cRdTscInstructions, cOuterLoops, cMaxLoops,
277 (unsigned)(offMinIncr >> 32), (unsigned)offMinIncr, (unsigned)(offMaxIncr >> 32), (unsigned)offMaxIncr);
278 return RTEXITCODE_SUCCESS;
279 }
280 printf("RDTSC instructions: %u\n", cRdTscInstructions);
281 printf("Loops: %u * %u => %u\n", cMaxLoops, cOuterLoops, cOuterLoops * cMaxLoops);
282 printf("Backwards: %u\n", cBackwards);
283 printf("Jumps: %u\n", cJumps);
284 printf("Max jumps: %#010x`%08x\n", (unsigned)(offMaxJump >> 32), (unsigned)offMaxJump);
285 printf("Same value: %u\n", cSame);
286 printf("Bad values: %u\n", cBadValues);
287 printf("Min increment: %#010x`%08x\n", (unsigned)(offMinIncr >> 32), (unsigned)offMinIncr);
288 printf("Max increment: %#010x`%08x\n", (unsigned)(offMaxIncr >> 32), (unsigned)offMaxIncr);
289 return RTEXITCODE_FAILURE;
290}
291
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