VBoxStatistics.cpp revision b357df727b216b85d4517efecf466a7b14c2e80c
/** @file
*
* VBoxStats - Guest statistics notification
*
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <psapi.h>
#include "VBoxTray.h"
#include "VBoxStatistics.h"
#include "VBoxMemBalloon.h"
#include <VBoxDisplay.h>
#include <VBox/VBoxGuest.h>
#include <VBoxGuestInternal.h>
#include "helpers.h"
#include <winternl.h>
typedef struct _VBOXSTATSCONTEXT
{
const VBOXSERVICEENV *pEnv;
NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
static VBOXSTATSCONTEXT gCtx = {0};
{
dprintf(("VBoxStatsInit\n"));
gCtx.ullLastCpuLoad_Idle = 0;
gCtx.ullLastCpuLoad_User = 0;
if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST, &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
{
}
else
/* NtQuerySystemInformation might be dropped in future releases, so load it dynamically as per Microsoft's recommendation */
if (hMod)
{
*(uintptr_t *)&gCtx.pfnNtQuerySystemInformation = (uintptr_t)GetProcAddress(hMod, "NtQuerySystemInformation");
else
{
dprintf(("NTDLL.NtQuerySystemInformation not found!!\n"));
return VERR_NOT_IMPLEMENTED;
}
}
/* GlobalMemoryStatus is win2k and up, so load it dynamically */
if (hMod)
{
*(uintptr_t *)&gCtx.pfnGlobalMemoryStatusEx = (uintptr_t)GetProcAddress(hMod, "GlobalMemoryStatusEx");
else
{
/** @todo now fails in NT4; do we care? */
dprintf(("KERNEL32.GlobalMemoryStatusEx not found!!\n"));
return VERR_NOT_IMPLEMENTED;
}
}
/* GetPerformanceInfo is xp and up, so load it dynamically */
if (hMod)
{
/* failure is not fatal */
}
*pfStartThread = true;
*ppInstance = &gCtx;
return VINF_SUCCESS;
}
{
dprintf(("VBoxStatsDestroy\n"));
return;
}
{
if ( !gCtx.pfnGlobalMemoryStatusEx
return;
/* Query and report guest statistics */
/* The current size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead. */
req.guestStats.u32PageFileSize = (uint32_t)(memStatus.ullTotalPageFile / systemInfo.dwPageSize) - req.guestStats.u32PhysMemTotal;
req.guestStats.u32PhysMemBalloon = VBoxMemBalloonQuerySize() * (_1M/systemInfo.dwPageSize); /* was in megabytes */
req.guestStats.u32StatCaps = VBOX_GUEST_STAT_PHYS_MEM_TOTAL | VBOX_GUEST_STAT_PHYS_MEM_AVAIL | VBOX_GUEST_STAT_PAGE_FILE_SIZE | VBOX_GUEST_STAT_MEMORY_LOAD | VBOX_GUEST_STAT_PHYS_MEM_BALLOON;
{
{
req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_PROCESSES | VBOX_GUEST_STAT_THREADS | VBOX_GUEST_STAT_HANDLES | VBOX_GUEST_STAT_MEM_COMMIT_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_PAGED | VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE;
}
else
}
/* Query CPU load information */
if (!pProcInfo)
return;
/* Unfortunately GetSystemTimes is XP SP1 and up only, so we need to use the semi-undocumented NtQuerySystemInformation */
NTSTATUS rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
if ( !rc
&& cbReturned == cbStruct)
{
if (gCtx.ullLastCpuLoad_Kernel == 0)
{
/* first time */
Sleep(250);
rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
}
req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE | VBOX_GUEST_STAT_CPU_LOAD_KERNEL | VBOX_GUEST_STAT_CPU_LOAD_USER;
}
{
if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST, &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
{
dprintf(("VBoxStatsReportStatistics: new statistics reported successfully!\n"));
}
else
dprintf(("VBoxStatsReportStatistics: DeviceIoControl (stats report) failed with %d\n", GetLastError()));
}
}
/**
* Thread function to wait for and process seamless mode change
* requests
*/
{
bool fTerminate = false;
maskInfo.u32NotMask = 0;
if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
{
dprintf(("VBoxStatsThread: DeviceIOControl(CtlMask - or) succeeded\n"));
}
else
{
dprintf(("VBoxStatsThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
return 0;
}
do
{
/* wait for a seamless change event */
if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
{
dprintf(("VBoxStatsThread: DeviceIOControl succeded\n"));
/* are we supposed to stop? */
break;
dprintf(("VBoxStatsThread: checking event\n"));
/* did we get the right event? */
{
if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST, &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
{
}
else
}
}
else
{
dprintf(("VBoxStatsThread: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
/* sleep a bit to not eat too much CPU in case the above call always fails */
{
fTerminate = true;
break;
}
}
/* Report statistics to the host */
if ( gCtx.uStatInterval
{
}
}
while (!fTerminate);
if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
{
dprintf(("VBoxStatsThread: DeviceIOControl(CtlMask - not) succeeded\n"));
}
else
{
dprintf(("VBoxStatsThread: DeviceIOControl(CtlMask) failed\n"));
}
dprintf(("VBoxStatsThread: finished statistics change request thread\n"));
return 0;
}