VirtualBox

source: vbox/trunk/src/VBox/Additions/common/testcase/tstPageFusion.cpp@ 30457

Last change on this file since 30457 was 30067, checked in by vboxsync, 14 years ago

Count user and kernel pages separately

File size: 11.7 KB
Line 
1/* $Id: VBoxServicePageSharing.cpp 62335 2010-06-03 14:40:59Z bird $ */
2/** @file
3 * VBoxService - Guest page sharing testcase
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/asm.h>
24#include <iprt/mem.h>
25#include <iprt/stream.h>
26#include <iprt/string.h>
27#include <iprt/initterm.h>
28#include <VBox/VBoxGuestLib.h>
29#include <VBox/x86.h>
30#include <stdio.h>
31
32/*******************************************************************************
33* Global Variables *
34*******************************************************************************/
35
36#ifdef RT_OS_WINDOWS
37#include <Windows.h>
38#include <process.h> /* Needed for file version information. */
39#include <tlhelp32.h>
40#include <psapi.h>
41#include <winternl.h>
42
43#define SystemModuleInformation 11
44
45typedef struct _RTL_PROCESS_MODULE_INFORMATION
46{
47 ULONG Section;
48 PVOID MappedBase;
49 PVOID ImageBase;
50 ULONG ImageSize;
51 ULONG Flags;
52 USHORT LoadOrderIndex;
53 USHORT InitOrderIndex;
54 USHORT LoadCount;
55 USHORT OffsetToFileName;
56 CHAR FullPathName[256];
57} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
58
59typedef struct _RTL_PROCESS_MODULES
60{
61 ULONG NumberOfModules;
62 RTL_PROCESS_MODULE_INFORMATION Modules[1];
63} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
64
65typedef NTSTATUS (WINAPI *PFNZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
66static PFNZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL;
67static HMODULE hNtdll = 0;
68
69#define PAGE_STATE_INVALID 0
70#define PAGE_STATE_SHARED 1
71#define PAGE_STATE_READ_WRITE 2
72#define PAGE_STATE_READ_ONLY 3
73#define PAGE_STATE_NOT_PRESENT 4
74
75/* Page counters. */
76static unsigned cNotPresentPages = 0;
77static unsigned cWritablePages = 0;
78static unsigned cSharedPages = 0;
79static unsigned cPrivatePages = 0;
80
81/**
82 * Registers a new module with the VMM
83 * @param pModule Module ptr
84 */
85void VBoxServicePageSharingCheckModule(MODULEENTRY32 *pModule)
86{
87 DWORD dwModuleSize = pModule->modBaseSize;
88 BYTE *pBaseAddress = pModule->modBaseAddr;
89 bool fFirstLine = true;
90 unsigned uPageState, uLastPageState;
91 bool fLastWritable = false;
92 BYTE *pLastBaseAddress = pBaseAddress;
93
94 uPageState = uLastPageState = PAGE_STATE_INVALID;
95
96 printf("Check module %s base %p size %x\n", pModule->szModule, pBaseAddress, dwModuleSize);
97 do
98 {
99 bool fShared;
100 uint64_t uPageFlags;
101
102#ifdef RT_ARCH_X86
103 int rc = VbglR3PageIsShared((uint32_t)pLastBaseAddress, &fShared, &uPageFlags);
104#else
105 int rc = VbglR3PageIsShared((RTGCPTR)pLastBaseAddress, &fShared, &uPageFlags);
106#endif
107 if (RT_FAILURE(rc))
108 printf("VbglR3PageIsShared %p failed with %d\n", pLastBaseAddress, rc);
109
110 if (RT_SUCCESS(rc))
111 {
112 if (uPageFlags & X86_PTE_P)
113 {
114 if (uPageFlags & X86_PTE_RW)
115 {
116 cWritablePages++;
117 uPageState = PAGE_STATE_READ_WRITE;
118 }
119 else
120 if (fShared)
121 {
122 cSharedPages++;
123 uPageState = PAGE_STATE_SHARED;
124 }
125 else
126 {
127 cPrivatePages++;
128 uPageState = PAGE_STATE_READ_ONLY;
129 }
130 }
131 else
132 {
133 cNotPresentPages++;
134 uPageState = PAGE_STATE_NOT_PRESENT;
135 }
136
137 if ( !fFirstLine
138 && uPageState != uLastPageState)
139 {
140 printf("0x%p\n", pLastBaseAddress + 0xfff);
141 }
142
143 if (uPageState != uLastPageState)
144 {
145 switch (uPageState)
146 {
147 case PAGE_STATE_READ_WRITE:
148 printf("%s RW 0x%p - ", pModule->szModule, pBaseAddress);
149 break;
150 case PAGE_STATE_SHARED:
151 printf("%s SHARED 0x%p - ", pModule->szModule, pBaseAddress);
152 break;
153 case PAGE_STATE_READ_ONLY:
154 printf("%s PRIV 0x%p - ", pModule->szModule, pBaseAddress);
155 break;
156 case PAGE_STATE_NOT_PRESENT:
157 printf("%s NP 0x%p - ", pModule->szModule, pBaseAddress);
158 break;
159 }
160
161 fFirstLine = false;
162 }
163 uLastPageState = uPageState;
164 }
165 else
166 if (!fFirstLine)
167 {
168 printf("0x%p\n", pLastBaseAddress + 0xfff);
169 fFirstLine = true;
170 }
171
172 if (dwModuleSize > PAGE_SIZE)
173 dwModuleSize -= PAGE_SIZE;
174 else
175 dwModuleSize = 0;
176
177 pLastBaseAddress = pBaseAddress;
178 pBaseAddress += PAGE_SIZE;
179 }
180 while (dwModuleSize);
181
182 printf("0x%p\n", pLastBaseAddress + 0xfff);
183 return;
184}
185
186/**
187 * Inspect all loaded modules for the specified process
188 * @param dwProcessId Process id
189 */
190void VBoxServicePageSharingInspectModules(DWORD dwProcessId)
191{
192 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
193 if (hSnapshot == INVALID_HANDLE_VALUE)
194 {
195 printf("VBoxServicePageSharingInspectModules: CreateToolhelp32Snapshot failed with %d\n", GetLastError());
196 return;
197 }
198
199 printf("VBoxServicePageSharingInspectModules\n");
200
201 MODULEENTRY32 ModuleInfo;
202 BOOL bRet;
203
204 ModuleInfo.dwSize = sizeof(ModuleInfo);
205 bRet = Module32First(hSnapshot, &ModuleInfo);
206 do
207 {
208 /** todo when changing this make sure VBoxService.exe is excluded! */
209 char *pszDot = strrchr(ModuleInfo.szModule, '.');
210 if ( pszDot
211 && (pszDot[1] == 'e' || pszDot[1] == 'E'))
212 continue; /* ignore executables for now. */
213
214 VBoxServicePageSharingCheckModule(&ModuleInfo);
215 }
216 while (Module32Next(hSnapshot, &ModuleInfo));
217
218 CloseHandle(hSnapshot);
219}
220
221/**
222 * Inspect all running processes for executables and dlls that might be worth sharing
223 * with other VMs.
224 *
225 */
226void VBoxServicePageSharingInspectGuest()
227{
228 VBoxServicePageSharingInspectModules(GetCurrentProcessId());
229
230 printf("\n\nUSER RESULTS\n");
231 printf("cNotPresentPages = %d\n", cNotPresentPages);
232 printf("cWritablePages = %d\n", cWritablePages);
233 printf("cPrivatePages = %d\n", cPrivatePages);
234 printf("cSharedPages = %d\n", cSharedPages);
235
236 cNotPresentPages = 0;
237 cWritablePages = 0;
238 cPrivatePages = 0;
239 cSharedPages = 0;
240
241 /* Check all loaded kernel modules. */
242 if (ZwQuerySystemInformation)
243 {
244 ULONG cbBuffer = 0;
245 PVOID pBuffer = NULL;
246 PRTL_PROCESS_MODULES pSystemModules;
247
248 NTSTATUS ret = ZwQuerySystemInformation(SystemModuleInformation, (PVOID)&cbBuffer, 0, &cbBuffer);
249 if (!cbBuffer)
250 {
251 printf("ZwQuerySystemInformation returned length 0\n");
252 goto skipkernelmodules;
253 }
254
255 pBuffer = RTMemAllocZ(cbBuffer);
256 if (!pBuffer)
257 goto skipkernelmodules;
258
259 ret = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, cbBuffer, &cbBuffer);
260 if (ret != 0)
261 {
262 printf("ZwQuerySystemInformation returned %x (1)\n", ret);
263 goto skipkernelmodules;
264 }
265
266 pSystemModules = (PRTL_PROCESS_MODULES)pBuffer;
267 for (unsigned i = 0; i < pSystemModules->NumberOfModules; i++)
268 {
269 /* User-mode modules seem to have no flags set; skip them as we detected them above. */
270 if (pSystemModules->Modules[i].Flags == 0)
271 continue;
272
273 /* New module; register it. */
274 char szFullFilePath[512];
275 MODULEENTRY32 ModuleInfo;
276
277 strcpy(ModuleInfo.szModule, &pSystemModules->Modules[i].FullPathName[pSystemModules->Modules[i].OffsetToFileName]);
278 GetSystemDirectoryA(szFullFilePath, sizeof(szFullFilePath));
279
280 /* skip \Systemroot\system32 */
281 char *lpPath = strchr(&pSystemModules->Modules[i].FullPathName[1], '\\');
282 if (!lpPath)
283 {
284 printf("Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
285 break;
286 }
287
288 lpPath = strchr(lpPath+1, '\\');
289 if (!lpPath)
290 {
291 printf("Unexpected kernel module name %s\n", pSystemModules->Modules[i].FullPathName);
292 break;
293 }
294
295 strcat(szFullFilePath, lpPath);
296 strcpy(ModuleInfo.szExePath, szFullFilePath);
297 ModuleInfo.modBaseAddr = (BYTE *)pSystemModules->Modules[i].ImageBase;
298 ModuleInfo.modBaseSize = pSystemModules->Modules[i].ImageSize;
299
300 VBoxServicePageSharingCheckModule(&ModuleInfo);
301 }
302skipkernelmodules:
303 if (pBuffer)
304 RTMemFree(pBuffer);
305 }
306 printf("\n\nKERNEL RESULTS\n");
307 printf("cNotPresentPages = %d\n", cNotPresentPages);
308 printf("cWritablePages = %d\n", cWritablePages);
309 printf("cPrivatePages = %d\n", cPrivatePages);
310 printf("cSharedPages = %d\n", cSharedPages);
311}
312#else
313void VBoxServicePageSharingInspectGuest()
314{
315 /* @todo other platforms */
316}
317#endif
318
319
320/** @copydoc VBOXSERVICE::pfnInit */
321static DECLCALLBACK(int) VBoxServicePageSharingInit(void)
322{
323 printf("VBoxServicePageSharingInit\n");
324
325#ifdef RT_OS_WINDOWS
326 hNtdll = LoadLibrary("ntdll.dll");
327
328 if (hNtdll)
329 ZwQuerySystemInformation = (PFNZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
330#endif
331
332 /* @todo report system name and version */
333 /* Never fail here. */
334 return VINF_SUCCESS;
335}
336
337static DECLCALLBACK(void) VBoxServicePageSharingTerm(void)
338{
339 printf("VBoxServicePageSharingTerm\n");
340
341#ifdef RT_OS_WINDOWS
342 if (hNtdll)
343 FreeLibrary(hNtdll);
344#endif
345 return;
346}
347
348int main(int argc, char **argv)
349{
350 int rc = VINF_SUCCESS;
351 /*
352 * Init globals and such.
353 */
354 RTR3Init();
355
356 /*
357 * Connect to the kernel part before daemonizing so we can fail
358 * and complain if there is some kind of problem. We need to initialize
359 * the guest lib *before* we do the pre-init just in case one of services
360 * needs do to some initial stuff with it.
361 */
362 printf("Calling VbgR3Init()\n");
363 rc = VbglR3Init();
364 if (RT_FAILURE(rc))
365 {
366 printf("VbglR3Init failed with rc=%Rrc.\n", rc);
367 return -1;
368 }
369 VBoxServicePageSharingInit();
370
371 VBoxServicePageSharingInspectGuest();
372
373 VBoxServicePageSharingTerm();
374 return 0;
375}
376
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