VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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