VirtualBox

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

Last change on this file since 19420 was 19300, checked in by vboxsync, 16 years ago

VMReq,*: Replaced VMREQDEST with VMCPUID because it's a pain to have to cast CPU IDs all the time.

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