VirtualBox

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

Last change on this file since 79067 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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