VirtualBox

source: vbox/trunk/src/VBox/VMM/testcase/tstMicro.cpp@ 19

Last change on this file since 19 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1/** @file
2 *
3 * Micro Testcase, profiling special CPU operations.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <VBox/vm.h>
26#include <VBox/vmm.h>
27#include <VBox/mm.h>
28#include <VBox/cpum.h>
29#include <VBox/pdm.h>
30#include <VBox/dbgf.h>
31#include <VBox/pgm.h>
32#include <VBox/err.h>
33#include <VBox/param.h>
34
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/runtime.h>
38#include <iprt/stream.h>
39#include <iprt/string.h>
40#include <iprt/semaphore.h>
41
42#include <stdio.h>
43
44#include "tstMicro.h"
45
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50#define TESTCASE "tstVMM"
51
52static const char *GetDescription(TSTMICROTEST enmTest)
53{
54 switch (enmTest)
55 {
56 case TSTMICROTEST_OVERHEAD: return "Overhead";
57 case TSTMICROTEST_INVLPG_0: return "invlpg [0]";
58 case TSTMICROTEST_INVLPG_EIP: return "invlpg [EIP]";
59 case TSTMICROTEST_INVLPG_ESP: return "invlpg [ESP]";
60 case TSTMICROTEST_CR3_RELOAD: return "cr3 reload";
61 case TSTMICROTEST_WP_DISABLE: return "CR0.WP <- 0";
62 case TSTMICROTEST_WP_ENABLE: return "CR0.WP <- 1";
63
64 case TSTMICROTEST_PF_R0: return "R0 #PG (NULL)";
65 case TSTMICROTEST_PF_R1: return "R1 #PG (NULL)";
66 case TSTMICROTEST_PF_R2: return "R2 #PG (NULL)";
67 case TSTMICROTEST_PF_R3: return "R3 #PG (NULL)";
68
69 default:
70 {
71 static char sz[64];
72 RTStrPrintf(sz, sizeof(sz), "%d?", enmTest);
73 return sz;
74 }
75 }
76}
77
78
79static void PrintHeaderInstr(void)
80{
81 RTPrintf(TESTCASE ": %-25s %10s %10s %10s\n",
82 "Test name",
83 "Min",
84 "Avg",
85 "Max");
86}
87
88static void PrintResultInstr(PTSTMICRO pTst, TSTMICROTEST enmTest, int rc, uint64_t cMinTicks, uint64_t cAvgTicks, uint64_t cMaxTicks)
89{
90 if (VBOX_FAILURE(rc))
91 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu - %Vrc cr2=%x err=%x eip=%x!\n",
92 GetDescription(enmTest),
93 cMinTicks,
94 cAvgTicks,
95 cMaxTicks,
96 rc,
97 pTst->u32CR2,
98 pTst->u32ErrCd,
99 pTst->u32EIP);
100 else
101 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu\n",
102 GetDescription(enmTest),
103 cMinTicks,
104 cAvgTicks,
105 cMaxTicks);
106}
107
108static void PrintHeaderTraps(void)
109{
110 RTPrintf(TESTCASE ": %-25s %10s %10s %10s %10s %10s\n",
111 "Test name",
112 "Total",
113 "ToRx",
114 "Trap",
115 "ToRxTrap",
116 "int42-done");
117}
118
119static void PrintResultTrap(PTSTMICRO pTst, TSTMICROTEST enmTest, int rc)
120{
121 if (VBOX_FAILURE(rc))
122 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu %10llu %10llu - %Vrc cr2=%x err=%x eip=%x!\n",
123 GetDescription(enmTest),
124 pTst->aResults[enmTest].cTotalTicks,
125 pTst->aResults[enmTest].cToRxFirstTicks,
126 pTst->aResults[enmTest].cTrapTicks,
127 pTst->aResults[enmTest].cToRxTrapTicks,
128 pTst->aResults[enmTest].cToR0Ticks,
129 rc,
130 pTst->u32CR2,
131 pTst->u32ErrCd,
132 pTst->u32EIP);
133 else
134 RTPrintf(TESTCASE ": %-25s %10llu %10llu %10llu %10llu %10llu\n",
135 GetDescription(enmTest),
136 pTst->aResults[enmTest].cTotalTicks,
137 pTst->aResults[enmTest].cToRxFirstTicks,
138 pTst->aResults[enmTest].cTrapTicks,
139 pTst->aResults[enmTest].cToRxTrapTicks,
140 pTst->aResults[enmTest].cToR0Ticks);
141}
142
143
144/**
145 * 'Allocate' selectors for 32-bit code/data in rings 0-3.
146 *
147 * 0060 - r0 code
148 * 0068 - r0 data
149 *
150 * 1060 - r1 code
151 * 1068 - r1 data
152 *
153 * 2060 - r2 code
154 * 2068 - r2 data
155 *
156 * 3060 - r3 code
157 * 3068 - r3 data
158 *
159 */
160static void SetupSelectors(PVM pVM)
161{
162 /*
163 * Find the GDT - This is a HACK :-)
164 */
165 RTGCPTR GCPtr = CPUMGetHyperGDTR(pVM, NULL);
166 PX86DESC paGDTEs = (PX86DESC)MMHyperGC2HC(pVM, GCPtr);
167
168 for (unsigned i = 0; i <= 3; i++)
169 {
170 RTSEL Sel = (i << 12) + 0x60;
171
172 /* 32-bit code selector. */
173 PX86DESC pGDTE = &paGDTEs[Sel >> X86_SEL_SHIFT];
174 pGDTE->au32[0] = pGDTE->au32[1] = 0;
175 pGDTE->Gen.u16LimitLow = ~0;
176 pGDTE->Gen.u4LimitHigh = ~0;
177 pGDTE->Gen.u1Granularity= 1;
178 pGDTE->Gen.u1Present = 1;
179 pGDTE->Gen.u2Dpl = i;
180 pGDTE->Gen.u1DefBig = 1;
181 pGDTE->Gen.u1DescType = 1; /* !system */
182 pGDTE->Gen.u4Type = X86_SEL_TYPE_ER_ACC;
183
184 /* 32-bit data selector. */
185 pGDTE++;
186 pGDTE->au32[0] = pGDTE->au32[1] = 0;
187 pGDTE->Gen.u16LimitLow = ~0;
188 pGDTE->Gen.u4LimitHigh = ~0;
189 pGDTE->Gen.u1Granularity= 1;
190 pGDTE->Gen.u1Present = 1;
191 pGDTE->Gen.u2Dpl = i;
192 pGDTE->Gen.u1DefBig = 1;
193 pGDTE->Gen.u1DescType = 1; /* !system */
194 pGDTE->Gen.u4Type = X86_SEL_TYPE_RW_ACC;
195 }
196}
197
198
199static DECLCALLBACK(int) doit(PVM pVM)
200{
201 RTPrintf(TESTCASE ": testing...\n");
202 SetupSelectors(pVM);
203
204 /*
205 * Loading the module and resolve the entry point.
206 */
207 int rc = PDMR3LoadGC(pVM, NULL, "tstMicroGC.gc");
208 if (VBOX_FAILURE(rc))
209 {
210 RTPrintf(TESTCASE ": Failed to load tstMicroGC.gc, rc=%Vra\n", rc);
211 return rc;
212 }
213 RTGCPTR GCPtrEntry;
214 rc = PDMR3GetSymbolGC(pVM, "tstMicroGC.gc", "tstMicroGC", &GCPtrEntry);
215 if (VBOX_FAILURE(rc))
216 {
217 RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroGC' entry point in tstMicroGC.gc, rc=%Vra\n", rc);
218 return rc;
219 }
220 RTGCPTR GCPtrStart;
221 rc = PDMR3GetSymbolGC(pVM, "tstMicroGC.gc", "tstMicroGCAsmStart", &GCPtrStart);
222 if (VBOX_FAILURE(rc))
223 {
224 RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroGCAsmStart' entry point in tstMicroGC.gc, rc=%Vra\n", rc);
225 return rc;
226 }
227 RTGCPTR GCPtrEnd;
228 rc = PDMR3GetSymbolGC(pVM, "tstMicroGC.gc", "tstMicroGCAsmEnd", &GCPtrEnd);
229 if (VBOX_FAILURE(rc))
230 {
231 RTPrintf(TESTCASE ": Failed to resolve the 'tstMicroGCAsmEnd' entry point in tstMicroGC.gc, rc=%Vra\n", rc);
232 return rc;
233 }
234
235 /*
236 * Allocate and initialize the instance data.
237 */
238 PTSTMICRO pTst;
239 rc = MMHyperAlloc(pVM, RT_ALIGN_Z(sizeof(*pTst), PAGE_SIZE), PAGE_SIZE, MM_TAG_VM, (void **)&pTst);
240 if (VBOX_FAILURE(rc))
241 {
242 RTPrintf(TESTCASE ": Failed to resolve allocate instance memory (%d bytes), rc=%Vra\n", sizeof(*pTst), rc);
243 return rc;
244 }
245 pTst->GCPtr = MMHyperHC2GC(pVM, pTst);
246 pTst->GCPtrStack = MMHyperHC2GC(pVM, &pTst->au8Stack[sizeof(pTst->au8Stack) - 32]);
247
248 /* the page must be writable from user mode */
249 rc = PGMMapModifyPage(pVM, pTst->GCPtr, sizeof(*pTst), X86_PTE_US | X86_PTE_RW, ~(uint64_t)(X86_PTE_US | X86_PTE_RW));
250 if (VBOX_FAILURE(rc))
251 {
252 RTPrintf(TESTCASE ": PGMMapModifyPage -> rc=%Vra\n", rc);
253 return rc;
254 }
255
256 /* all the code must be executable from R3. */
257 rc = PGMMapModifyPage(pVM, GCPtrStart, GCPtrEnd - GCPtrStart + PAGE_SIZE, X86_PTE_US, ~(uint64_t)X86_PTE_US);
258 if (VBOX_FAILURE(rc))
259 {
260 RTPrintf(TESTCASE ": PGMMapModifyPage -> rc=%Vra\n", rc);
261 return rc;
262 }
263 PGMR3DumpHierarchyHC(pVM, PGMGetHyper32BitCR3(pVM), X86_CR4_PSE, false, 4, NULL);
264
265#if 0
266 /*
267 * Disassemble the assembly...
268 */
269 RTGCPTR GCPtr = GCPtrStart;
270 while (GCPtr < GCPtrEnd)
271 {
272 size_t cb = 0;
273 char sz[256];
274 int rc = DBGFR3DisasInstrEx(pVM, CPUMGetHyperCS(pVM), GCPtr, 0, sz, sizeof(sz), &cb);
275 if (VBOX_SUCCESS(rc))
276 RTLogPrintf("%s\n", sz);
277 else
278 {
279 RTLogPrintf("%VGv rc=%Vrc\n", GCPtr, rc);
280 cb = 1;
281 }
282 GCPtr += cb;
283 }
284#endif
285
286 /*
287 * Do the profiling.
288 */
289 /* execute the instruction profiling tests */
290 PrintHeaderInstr();
291 int i;
292 for (i = TSTMICROTEST_OVERHEAD; i < TSTMICROTEST_TRAP_FIRST; i++)
293 {
294 TSTMICROTEST enmTest = (TSTMICROTEST)i;
295 uint64_t cMin = ~0;
296 uint64_t cMax = 0;
297 uint64_t cTotal = 0;
298 unsigned cSamples = 0;
299 rc = VINF_SUCCESS;
300 for (int c = 0; c < 100; c++)
301 {
302 int rc2 = VMMR3CallGC(pVM, GCPtrEntry, 2, pTst->GCPtr, enmTest);
303 if (VBOX_SUCCESS(rc2))
304 {
305 uint64_t u64 = pTst->aResults[enmTest].cTotalTicks;
306 if (cMin > u64)
307 cMin = u64;
308 if (cMax < u64)
309 cMax = u64;
310 cTotal += u64;
311 cSamples++;
312 }
313 else if (VBOX_SUCCESS(rc))
314 rc = rc2;
315 }
316 uint64_t cAvg = cTotal / (cSamples ? cSamples : 1);
317 pTst->aResults[enmTest].cTotalTicks = cAvg;
318 PrintResultInstr(pTst, enmTest, rc, cMin, cAvg, cMax);
319 /* store the overhead */
320 if (enmTest == TSTMICROTEST_OVERHEAD)
321 pTst->u64Overhead = cMin;
322 }
323
324
325 /* execute the trap/cycle profiling tests. */
326 RTPrintf("\n");
327 PrintHeaderTraps();
328 for (i = TSTMICROTEST_TRAP_FIRST; i < TSTMICROTEST_MAX; i++)
329 {
330 TSTMICROTEST enmTest = (TSTMICROTEST)i;
331 rc = VMMR3CallGC(pVM, GCPtrEntry, 2, pTst->GCPtr, enmTest);
332 PrintResultTrap(pTst, enmTest, rc);
333 }
334
335
336 RTPrintf(TESTCASE ": done!\n");
337 return VINF_SUCCESS;
338}
339
340
341int main(int argc, char **argv)
342{
343 int rcRet = 0; /* error count. */
344
345 RTR3Init();
346
347 /*
348 * Create empty VM.
349 */
350 PVM pVM;
351 int rc = VMR3Create(NULL, NULL, NULL, NULL, &pVM);
352 if (VBOX_SUCCESS(rc))
353 {
354 /*
355 * Do testing.
356 */
357 PVMREQ pReq1 = NULL;
358 rc = VMR3ReqCallVoid(pVM, &pReq1, RT_INDEFINITE_WAIT, (PFNRT)doit, 1, pVM);
359 AssertRC(rc);
360 VMR3ReqFree(pReq1);
361
362 STAMR3Dump(pVM, "*");
363
364 /*
365 * Cleanup.
366 */
367 rc = VMR3Destroy(pVM);
368 if (!VBOX_SUCCESS(rc))
369 {
370 printf(TESTCASE ": error: failed to destroy vm! rc=%d\n", rc);
371 rcRet++;
372 }
373 }
374 else
375 {
376 printf(TESTCASE ": fatal error: failed to create vm! rc=%d\n", rc);
377 rcRet++;
378 }
379
380 return rcRet;
381}
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