VirtualBox

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

Last change on this file since 100240 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1/* $Id: rdtsc.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * rdtsc - Test if three consecutive rdtsc instructions return different values.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/errcore.h>
42#include <iprt/initterm.h>
43#include <iprt/message.h>
44#include <iprt/stream.h>
45#include <iprt/string.h>
46#include <iprt/time.h>
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52typedef struct RDTSCRESULT
53{
54 RTCCUINTREG uLow, uHigh;
55} RDTSCRESULT;
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61extern "C" RDTSCRESULT g_aRdTscResults[]; /* rdtsc-asm.asm */
62
63
64/*********************************************************************************************************************************
65* Internal Functions *
66*********************************************************************************************************************************/
67/**
68 * Does 3 (32-bit) or 6 (64-bit) fast TSC reads and stores the result
69 * in g_aRdTscResults, starting with the 2nd entry.
70 *
71 * Starting the result storing at g_aRdTscResults[1] make it easy to do the
72 * comparisons in a loop.
73 *
74 * @returns Number of results read into g_aRdTscResults[1] and onwards.
75 */
76DECLASM(uint32_t) DoTscReads(void);
77
78
79
80
81int main(int argc, char **argv)
82{
83 int rc = RTR3InitExe(argc, &argv, 0);
84 if (RT_FAILURE(rc))
85 return RTMsgInitFailure(rc);
86
87 /*
88 * Tunables.
89 */
90 uint64_t offJumpThreshold = _4G * 2;
91 unsigned cMaxLoops = 10000000;
92 unsigned cStatusEvery = 2000000;
93 unsigned cMinSeconds = 0;
94
95 for (int i = 1; i < argc; i++)
96 {
97 const char *psz = argv[i];
98 if (*psz == '-')
99 {
100 psz++;
101 char chOpt;
102 while ((chOpt = *psz++) != '\0')
103 {
104 /* Option value. */
105 const char *pszValue = NULL;
106 uint64_t uValue = 0;
107 switch (chOpt)
108 {
109 case 'l':
110 case 's':
111 case 'm':
112 if (*psz == '\0')
113 {
114 if (i + 1 >= argc)
115 return RTMsgSyntax("The %c option requires a value", chOpt);
116 pszValue = argv[++i];
117 }
118 else
119 pszValue = psz + (*psz == ':' || *psz == '=');
120 switch (chOpt)
121 {
122 case 'l':
123 case 's':
124 case 'm':
125 {
126 char *pszNext = NULL;
127 rc = RTStrToUInt64Ex(pszValue, &pszNext, 0, &uValue);
128 if (RT_FAILURE(rc))
129 return RTMsgSyntax("Bad number: %s (%Rrc)", pszValue, rc);
130 if (pszNext && *pszNext != '\0')
131 {
132 if (*pszNext == 'M'&& pszNext[1] == '\0')
133 uValue *= _1M;
134 else if (*pszNext == 'K' && pszNext[1] == '\0')
135 uValue *= _1K;
136 else if (*pszNext == 'G' && pszNext[1] == '\0')
137 uValue *= _1G;
138 else
139 return RTMsgSyntax("Bad value format for option %c: %s", chOpt, pszValue);
140 }
141 break;
142 }
143 }
144 break;
145 }
146
147 /* handle the option. */
148 switch (chOpt)
149 {
150 case 'l':
151 cMaxLoops = uValue;
152 break;
153
154 case 'm':
155 cMinSeconds = uValue;
156 break;
157
158 case 's':
159 cStatusEvery = uValue;
160 break;
161
162 case 'h':
163 case '?':
164 RTPrintf("usage: rdtsc [-l <loops>] [-s <loops-between-status>]\n"
165 " [-m <minimum-seconds-to-run>]\n");
166 return RTEXITCODE_SUCCESS;
167
168 default:
169 return RTMsgSyntax("Unknown option %c (argument %d)\n", chOpt, i);
170 }
171 }
172 }
173 else
174 return RTMsgSyntax("argument %d (%s): not an option\n", i, psz);
175 }
176
177 /*
178 * Do the job.
179 */
180 uint64_t const nsTsStart = RTTimeNanoTS();
181 unsigned cOuterLoops = 0;
182 unsigned cLoopsToNextStatus = cStatusEvery;
183 unsigned cRdTscInstructions = 0;
184 unsigned cBackwards = 0;
185 unsigned cSame = 0;
186 unsigned cBadValues = 0;
187 unsigned cJumps = 0;
188 uint64_t offMaxJump = 0;
189 uint64_t offMinIncr = UINT64_MAX;
190 uint64_t offMaxIncr = 0;
191
192 g_aRdTscResults[0] = g_aRdTscResults[DoTscReads() - 1];
193
194 for (;;)
195 {
196 for (unsigned iLoop = 0; iLoop < cMaxLoops; iLoop++)
197 {
198 uint32_t const cResults = DoTscReads();
199 cRdTscInstructions += cResults;
200
201 for (uint32_t i = 0; i < cResults; i++)
202 {
203 uint64_t uPrev = RT_MAKE_U64((uint32_t)g_aRdTscResults[i ].uLow, (uint32_t)g_aRdTscResults[i ].uHigh);
204 uint64_t uCur = RT_MAKE_U64((uint32_t)g_aRdTscResults[i + 1].uLow, (uint32_t)g_aRdTscResults[i + 1].uHigh);
205 if (RT_LIKELY(uCur != uPrev))
206 {
207 int64_t offDelta = uCur - uPrev;
208 if (RT_LIKELY(offDelta >= 0))
209 {
210 if (RT_LIKELY((uint64_t)offDelta < offJumpThreshold))
211 {
212 if ((uint64_t)offDelta < offMinIncr)
213 offMinIncr = offDelta;
214 if ((uint64_t)offDelta > offMaxIncr && i != 0)
215 offMaxIncr = offDelta;
216 }
217 else
218 {
219 cJumps++;
220 if ((uint64_t)offDelta > offMaxJump)
221 offMaxJump = offDelta;
222 RTPrintf("%u/%u: Jump: %#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 cBackwards++;
230 RTPrintf("%u/%u: Back: %#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 }
235 else
236 {
237 cSame++;
238 RTPrintf("%u/%u: Same: %#010x`%08x -> %#010x`%08x\n", cOuterLoops, iLoop,
239 (unsigned)g_aRdTscResults[i].uHigh, (unsigned)g_aRdTscResults[i].uLow,
240 (unsigned)g_aRdTscResults[i + 1].uHigh, (unsigned)g_aRdTscResults[i + 1].uLow);
241 }
242#if ARCH_BITS == 64
243 if ((g_aRdTscResults[i + 1].uLow >> 32) || (g_aRdTscResults[i + 1].uHigh >> 32))
244 cBadValues++;
245#endif
246 }
247
248 /* Copy the last value for the next iteration. */
249 g_aRdTscResults[0] = g_aRdTscResults[cResults];
250
251 /* Display status. */
252 if (RT_LIKELY(--cLoopsToNextStatus > 0))
253 { /* likely */ }
254 else
255 {
256 cLoopsToNextStatus = cStatusEvery;
257 RTPrintf("%u/%u: %#010x`%08x\n", cOuterLoops, iLoop,
258 (unsigned)g_aRdTscResults[cResults].uHigh, (unsigned)g_aRdTscResults[cResults].uLow);
259 }
260 }
261
262 /*
263 * Check minimum number of seconds.
264 */
265 cOuterLoops++;
266 if (!cMinSeconds)
267 break;
268 uint64_t nsElapsed = RTTimeNanoTS() - nsTsStart;
269 if (nsElapsed >= cMinSeconds * RT_NS_1SEC_64)
270 break;
271 }
272
273 /*
274 * Summary.
275 */
276 if (cBackwards == 0 && cSame == 0 && cJumps == 0 && cBadValues == 0)
277 {
278 RTPrintf("rdtsc: Success (%u RDTSC over %u*%u loops, deltas: %#x`%08x..%#x`%08x)\n",
279 cRdTscInstructions, cOuterLoops, cMaxLoops,
280 (unsigned)(offMinIncr >> 32), (unsigned)offMinIncr, (unsigned)(offMaxIncr >> 32), (unsigned)offMaxIncr);
281 return RTEXITCODE_SUCCESS;
282 }
283 RTPrintf("RDTSC instructions: %u\n", cRdTscInstructions);
284 RTPrintf("Loops: %u * %u => %u\n", cMaxLoops, cOuterLoops, cOuterLoops * cMaxLoops);
285 RTPrintf("Backwards: %u\n", cBackwards);
286 RTPrintf("Jumps: %u\n", cJumps);
287 RTPrintf("Max jumps: %#010x`%08x\n", (unsigned)(offMaxJump >> 32), (unsigned)offMaxJump);
288 RTPrintf("Same value: %u\n", cSame);
289 RTPrintf("Bad values: %u\n", cBadValues);
290 RTPrintf("Min increment: %#010x`%08x\n", (unsigned)(offMinIncr >> 32), (unsigned)offMinIncr);
291 RTPrintf("Max increment: %#010x`%08x\n", (unsigned)(offMaxIncr >> 32), (unsigned)offMaxIncr);
292 return RTEXITCODE_FAILURE;
293}
294
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