VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3-timing-1-32.c32@ 96455

Last change on this file since 96455 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: 13.0 KB
Line 
1/* $Id: bs3-timing-1-32.c32 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * BS3Kit - bs3-timinig-1, 32-bit C code.
4 */
5
6/*
7 * Copyright (C) 2007-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#ifndef STANDALONE_EXECUTABLE
42# include <bs3kit.h>
43#endif
44#include <iprt/asm-amd64-x86.h>
45#include <iprt/asm-math.h>
46#include <iprt/asm.h>
47#include <iprt/uint128.h>
48
49
50/*********************************************************************************************************************************
51* Structures and Typedefs *
52*********************************************************************************************************************************/
53/** TSC timing results. */
54typedef struct BS3TIMING1RESULT
55{
56 /** Number of nanoseconds elapsed while testing. */
57 uint64_t cNsElapsed;
58 /** Number of CPU ticks elapsed while testing. */
59 uint64_t cTicksElapsed;
60 /** The minium number of ticks between TSC reads. */
61 uint64_t cTicksMin;
62 /** The maximum number of ticks between TSC reads. */
63 uint64_t cTicksMax;
64 /** The sum of all TSC read deltas. */
65 uint64_t cTicksSum;
66 /** Number of loops (TSC read deltas). */
67 uint64_t cTotalLoops;
68 /** Number of times TSC moved backwards. */
69 uint64_t cBackwards;
70 /** Approx log2(cTicks) distribution. */
71 uint64_t aDistribution[65];
72} BS3TIMING1RESULT;
73
74
75/*********************************************************************************************************************************
76* Global Variables *
77*********************************************************************************************************************************/
78/** The total result. */
79static BS3TIMING1RESULT g_TotalResult;
80
81/** Set if history wrapped (i.e. table is full). */
82static bool g_fBigHistoryWrapped = false;
83/** The next history entry. */
84static uint32_t g_iBigHistory;
85/** History of large gaps. */
86static struct { uint64_t uTsc, cTicksDelta; } g_aBigHistory[384];
87
88
89
90/**
91 * Pretty prints
92 */
93static void bs3Timing1_PrintTicks(uint64_t cTicks, uint64_t uCpuFreq)
94{
95 if (uCpuFreq > _128M)
96 {
97 if (cTicks >= uCpuFreq * 1000)
98 Bs3TestPrintf("%'RU64s", cTicks / uCpuFreq);
99 else
100 {
101 const char *pszUnit;
102 uint64_t uValue;
103 if (cTicks >= uCpuFreq)
104 {
105 pszUnit = "s";
106 uValue = (cTicks * RT_MS_1SEC) / uCpuFreq;
107 }
108 else if (cTicks * RT_MS_1SEC >= uCpuFreq)
109 {
110 pszUnit = "ms";
111 uValue = (cTicks * RT_US_1SEC) / uCpuFreq;
112 }
113 else if (cTicks * RT_US_1SEC >= uCpuFreq)
114 {
115 pszUnit = "us";
116 uValue = (cTicks * RT_NS_1SEC) / uCpuFreq;
117 }
118 else if (cTicks * RT_NS_1SEC >= uCpuFreq)
119 {
120 pszUnit = "ns";
121 uValue = (cTicks * UINT64_C(1000000000000)) / uCpuFreq;
122 }
123 else
124 {
125 Bs3TestPrintf("%'RU64ps", (cTicks * UINT64_C(1000000000000)) / uCpuFreq);
126 return;
127 }
128 Bs3TestPrintf("%u.%03u%s (%'RU64 ticks)", (uint32_t)uValue / 1000, (uint32_t)uValue % 1000, pszUnit, cTicks);
129 }
130 }
131 else
132 Bs3TestPrintf("%'RU64 ticks", cTicks);
133}
134
135
136/**
137 * Prints a result.
138 *
139 * @param pResult The result to print.
140 * @param iRun The run (loop in qpc parlance).
141 * @param uVerbosity The verbosity level.
142 */
143static void bs3Timing1_PrintResult(BS3TIMING1RESULT const *pResult, unsigned iRun, unsigned uVerbosity)
144{
145 uint64_t uCpuFreq;
146
147 /*
148 * Calc CPU frequency.
149 */
150 if (pResult->cNsElapsed > 0 && pResult->cTicksElapsed > 0)
151 {
152#if 1
153 RTUINT128U Tmp1, Divisor, Result;
154 RTUInt128Div(&Result,
155 RTUInt128MulU64ByU64(&Tmp1, pResult->cTicksElapsed, RT_NS_1SEC),
156 RTUInt128AssignU64(&Divisor, pResult->cNsElapsed));
157 uCpuFreq = Result.s.Lo;
158#else
159 unsigned const cShift = pResult->cTicksElapsed < UINT64_C(0x000225C17D04) ? 0
160 : pResult->cTicksElapsed < UINT64_C(0x00225C17D04D) ? 4
161 : pResult->cTicksElapsed < UINT64_C(0x0225C17D04DA) ? 8
162 : pResult->cTicksElapsed < UINT64_C(0x225C1D940BF6) ? 12
163 : 16;
164 uCpuFreq = pResult->cTicksElapsed * ((uint64_t)RT_NS_1SEC >> cShift) / (pResult->cNsElapsed >> cShift);
165#endif
166 }
167 else
168 uCpuFreq = 1;
169
170 /*
171 * Report results.
172 *
173 * Note! in 32-bit and 16-bit mode, values 4G or higher gets formatted as
174 * hexadecimal to avoid 64-bit division.
175 */
176 Bs3TestPrintf("Loop #%u: %'RU64 tests: ", iRun, pResult->cTotalLoops);
177
178 Bs3TestPrintf("average ");
179 bs3Timing1_PrintTicks(pResult->cTicksSum / pResult->cTotalLoops, uCpuFreq);
180 Bs3TestPrintf(", min ");
181 bs3Timing1_PrintTicks(pResult->cTicksMin, uCpuFreq);
182 Bs3TestPrintf(", max ");
183 bs3Timing1_PrintTicks(pResult->cTicksMax, uCpuFreq);
184 Bs3TestPrintf("\n");
185
186 /* Distribution (tick delta log2-ish). */
187 if (uVerbosity > 0)
188 {
189 unsigned iItem = 0;
190 unsigned i;
191 for (i = uVerbosity > 1 ? 0 : 5; i < RT_ELEMENTS(pResult->aDistribution); i++)
192 if (pResult->aDistribution[i] != 0)
193 {
194 if (iItem >= 6)
195 {
196 iItem = 0;
197 Bs3TestPrintf("\n");
198 }
199 iItem++;
200 Bs3TestPrintf(" %'11RU64|2^%-2u", pResult->aDistribution[i], i);
201 }
202 if (uVerbosity > 1)
203 Bs3TestPrintf(iItem < 6 ? " (%'RU64 Hz)\n" : "\n (%'RU64 Hz)\n", uCpuFreq);
204 else
205 Bs3TestPrintf("\n");
206 }
207 if (pResult->cBackwards != 0)
208 Bs3TestFailedF("TSC went backwards %'RU64 time(s)", pResult->cBackwards);
209}
210
211
212/**
213 * Do one TSC timing iteration.
214 *
215 * @param iRun The iteration number (loop).
216 * @param cSecs The number of seconds to sample TSCs.
217 * @param uVerbosity The noise level.
218 * @param iMinHistory The threshold level to put stuff in g_auTscHistory.
219 */
220static void bs3Timing1_Tsc_One(unsigned iRun, uint32_t cSecs, unsigned uVerbosity, unsigned iMinHistory)
221{
222 uint64_t const nsStart = Bs3TestNow();
223 uint64_t const uTscStart = ASMReadTSC();
224 uint64_t const nsDeadline = nsStart + cSecs * RT_NS_1SEC_64;
225 uint64_t cNsElapsed;
226 BS3TIMING1RESULT Result;
227 unsigned i;
228
229 Bs3MemZero(&Result, sizeof(Result));
230 Result.cTicksMin = UINT64_MAX;
231
232 /*
233 * Test loop.
234 */
235 do
236 {
237 unsigned cLoops = 100000 + 1;
238 Result.cTotalLoops += cLoops - 1;
239 while (--cLoops != 0)
240 {
241 uint64_t uTscPrev = ASMReadTSC();
242 uint64_t uTscNow = ASMReadTSC();
243 uint64_t cTicks = uTscNow - uTscPrev;
244 unsigned iBit;
245
246 /* check that it doesn't go backwards*/
247 if ((int64_t)cTicks < 0)
248 Result.cBackwards++;
249
250 /* min/max/avg */
251 Result.cTicksSum += cTicks;
252 if (cTicks < Result.cTicksMin)
253 Result.cTicksMin = cTicks;
254 if (cTicks > Result.cTicksMax)
255 Result.cTicksMax = cTicks;
256
257 /* result distribution by most significant bit. */
258 iBit = ASMBitLastSetU64(cTicks);
259 Result.aDistribution[iBit] += 1;
260 if (iBit < iMinHistory)
261 { /* likely */ }
262 else
263 {
264 g_aBigHistory[g_iBigHistory].uTsc = uTscPrev;
265 g_aBigHistory[g_iBigHistory].cTicksDelta = cTicks;
266 if (++g_iBigHistory >= RT_ELEMENTS(g_aBigHistory))
267 {
268 g_iBigHistory = 0;
269 g_fBigHistoryWrapped = true;
270 }
271 }
272 }
273 } while ((cNsElapsed = Bs3TestNow()) < nsDeadline);
274
275 Result.cTicksElapsed = ASMReadTSC() - uTscStart;
276 Result.cNsElapsed = cNsElapsed - nsStart;
277
278 bs3Timing1_PrintResult(&Result, iRun, uVerbosity);
279
280 /* Add to total. */
281 g_TotalResult.cNsElapsed += Result.cNsElapsed;
282 g_TotalResult.cTicksElapsed += Result.cTicksElapsed;
283 if (Result.cTicksMin < g_TotalResult.cTicksMin || g_TotalResult.cTicksMin == 0)
284 g_TotalResult.cTicksMin = Result.cTicksMin;
285 if (Result.cTicksMax > g_TotalResult.cTicksMax)
286 g_TotalResult.cTicksMax += Result.cTicksMax;
287 g_TotalResult.cTicksSum += Result.cTicksSum;
288 g_TotalResult.cTotalLoops += Result.cTotalLoops;
289 g_TotalResult.cBackwards += Result.cBackwards;
290 for (i = 0; i < RT_ELEMENTS(Result.aDistribution); i++)
291 g_TotalResult.aDistribution[i] += Result.aDistribution[i];
292}
293
294
295/**
296 * The TSC test driver.
297 *
298 * @param cLoops Number of test iterations.
299 * @param cSecs The number of seconds per iteration.
300 * @param uVerbosity How noisy we should be.
301 * @param iMinHistory The threshold for big gap history.
302 */
303static void bs3Timing1_Tsc_Driver(unsigned cLoops, unsigned cSecs, unsigned uVerbosity, unsigned iMinHistory)
304{
305 unsigned iLoop;
306
307#if 1
308 /*
309 * Verify that the first/last bit in U64 works (didn't).
310 */
311 iLoop = ASMBitLastSetU64( UINT64_C(0x1000100010001000)); if (iLoop != 61) Bs3TestFailedF("%d: iLoop=%d\n", __LINE__, iLoop);
312 iLoop = ASMBitFirstSetU64(UINT64_C(0x1000100010001000)); if (iLoop != 13) Bs3TestFailedF("%d: iLoop=%d\n", __LINE__, iLoop);
313 iLoop = ASMBitLastSetU64( UINT64_C(0x000ffff000000000)); if (iLoop != 52) Bs3TestFailedF("%d: iLoop=%d\n", __LINE__, iLoop);
314 iLoop = ASMBitFirstSetU64(UINT64_C(0x000ffff000000000)); if (iLoop != 37) Bs3TestFailedF("%d: iLoop=%d\n", __LINE__, iLoop);
315#endif
316
317 /*
318 * Do the work.
319 */
320 Bs3TestPrintf("Running %u loops, %u second%s each...\n", cLoops, cSecs, cSecs != 1 ? "s" : "");
321 for (iLoop = 1; iLoop <= cLoops; iLoop++)
322 bs3Timing1_Tsc_One(iLoop, cSecs, uVerbosity, iMinHistory);
323
324 /*
325 * Report the total.
326 */
327 Bs3TestPrintf("Total:\n");
328 bs3Timing1_PrintResult(&g_TotalResult, iLoop, uVerbosity + 1);
329
330 /*
331 * Dump the large gap history, if any.
332 */
333 if (g_fBigHistoryWrapped || g_iBigHistory > 0)
334 {
335 uint32_t const iFirst = g_fBigHistoryWrapped ? g_iBigHistory : 0;
336 uint32_t const iEnd = g_iBigHistory;
337 uint64_t uTscPrev = g_aBigHistory[iFirst].uTsc;
338 uint32_t i = iFirst;
339 Bs3TestPrintf("Big gap history (TSC, prev delta, test delta|level):\n");
340 do
341 {
342 Bs3TestPrintf(" %'RU64: %'14RU64 - %'14RU64|%u\n", g_aBigHistory[i].uTsc, g_aBigHistory[i].uTsc - uTscPrev,
343 g_aBigHistory[i].cTicksDelta, ASMBitLastSetU64(g_aBigHistory[i].cTicksDelta));
344 uTscPrev = g_aBigHistory[i].uTsc;
345 if (++i >= RT_ELEMENTS(g_aBigHistory))
346 i = 0;
347 } while (i != iEnd);
348 }
349 else
350 Bs3TestPrintf("No big gap history.\n");
351}
352
353
354#ifndef STANDALONE_EXECUTABLE
355BS3_DECL(void) bs3Timing1_Tsc_pe32(void)
356{
357 Bs3TestPrintf("bs3Timing1_Tsc_pe32\n");
358 bs3Timing1_Tsc_Driver(60, 10 /*sec*/, 1 /*uVerbosity*/, 17);
359}
360#endif
361
362/* P.S. don't forget: VBoxManage setextradata bs3-timing-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 */
363
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