VBoxServiceStats.cpp revision edef0eb9023260495fd67751464fae912a3114cd
6a67d144095c31bbafed93cec1619590157335eajvergara/* $Id$ */
6a67d144095c31bbafed93cec1619590157335eajvergara/** @file
6a67d144095c31bbafed93cec1619590157335eajvergara * VBoxStats - Guest statistics notification
6a67d144095c31bbafed93cec1619590157335eajvergara */
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/*
6a67d144095c31bbafed93cec1619590157335eajvergara * Copyright (C) 2006-2007 Sun Microsystems, Inc.
6a67d144095c31bbafed93cec1619590157335eajvergara *
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * This file is part of VirtualBox Open Source Edition (OSE), as
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * available from http://www.virtualbox.org. This file is free software;
6a67d144095c31bbafed93cec1619590157335eajvergara * you can redistribute it and/or modify it under the terms of the GNU
6a67d144095c31bbafed93cec1619590157335eajvergara * General Public License (GPL) as published by the Free Software
6a67d144095c31bbafed93cec1619590157335eajvergara * Foundation, in version 2 as it comes in the "COPYING" file of the
6a67d144095c31bbafed93cec1619590157335eajvergara * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac *
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * Clara, CA 95054 USA or visit http://www.sun.com if you need
6a67d144095c31bbafed93cec1619590157335eajvergara * additional information or have any questions.
6a67d144095c31bbafed93cec1619590157335eajvergara */
6a67d144095c31bbafed93cec1619590157335eajvergara#ifdef TARGET_NT4
6a67d144095c31bbafed93cec1619590157335eajvergara#undef _WIN32_WINNT
6a67d144095c31bbafed93cec1619590157335eajvergara#define _WIN32_WINNT 0x501
20b2af997c687f4604060f7e43e43b3f28766017jvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#if defined(RT_OS_WINDOWS)
6a67d144095c31bbafed93cec1619590157335eajvergara# include <windows.h>
6a67d144095c31bbafed93cec1619590157335eajvergara# include <psapi.h>
6a67d144095c31bbafed93cec1619590157335eajvergara# include <winternl.h>
6a67d144095c31bbafed93cec1619590157335eajvergara#elif defined(RT_OS_LINUX)
6a67d144095c31bbafed93cec1619590157335eajvergara# include <iprt/ctype.h>
6a67d144095c31bbafed93cec1619590157335eajvergara# include <iprt/stream.h>
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara#endif
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#include <iprt/assert.h>
6a67d144095c31bbafed93cec1619590157335eajvergara#include <iprt/mem.h>
6a67d144095c31bbafed93cec1619590157335eajvergara#include <iprt/thread.h>
6a67d144095c31bbafed93cec1619590157335eajvergara#include <iprt/string.h>
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara#include <iprt/semaphore.h>
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter#include <iprt/system.h>
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter#include <iprt/time.h>
6a67d144095c31bbafed93cec1619590157335eajvergara#include <VBox/VBoxGuestLib.h>
6a67d144095c31bbafed93cec1619590157335eajvergara#include "VBoxServiceInternal.h"
6a67d144095c31bbafed93cec1619590157335eajvergara#include "VBoxServiceUtils.h"
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergaratypedef struct _VBOXSTATSCONTEXT
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara RTMSINTERVAL cMsStatInterval;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara uint64_t ullLastCpuLoad_Idle;
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter uint64_t ullLastCpuLoad_Kernel;
6a67d144095c31bbafed93cec1619590157335eajvergara uint64_t ullLastCpuLoad_User;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara#ifdef RT_OS_WINDOWS
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
6a67d144095c31bbafed93cec1619590157335eajvergara void (WINAPI *pfnGlobalMemoryStatusEx)(LPMEMORYSTATUSEX lpBuffer);
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter BOOL (WINAPI *pfnGetPerformanceInfo)(PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb);
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter#endif
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara} VBOXSTATSCONTEXT;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/*******************************************************************************
6a67d144095c31bbafed93cec1619590157335eajvergara* Global Variables *
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter*******************************************************************************/
6a67d144095c31bbafed93cec1619590157335eajvergarastatic VBOXSTATSCONTEXT gCtx = {0};
857225469c51bedb8c0566aa7757800cfaac4075kenneth_suter
6a67d144095c31bbafed93cec1619590157335eajvergara/** The semaphore we're blocking on. */
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_suterstatic RTSEMEVENTMULTI g_VMStatEvent = NIL_RTSEMEVENTMULTI;
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/** @copydoc VBOXSERVICE::pfnPreInit */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic DECLCALLBACK(int) VBoxServiceVMStatsPreInit(void)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara return VINF_SUCCESS;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/** @copydoc VBOXSERVICE::pfnOption */
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergarastatic DECLCALLBACK(int) VBoxServiceVMStatsOption(const char **ppszShort, int argc, char **argv, int *pi)
6a67d144095c31bbafed93cec1619590157335eajvergara{
7b6b125d52edabd5b1c9134feef7aeae0e69499ekenneth_suter NOREF(ppszShort);
6a67d144095c31bbafed93cec1619590157335eajvergara NOREF(argc);
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter NOREF(argv);
6a67d144095c31bbafed93cec1619590157335eajvergara NOREF(pi);
6a67d144095c31bbafed93cec1619590157335eajvergara return VINF_SUCCESS;
6a67d144095c31bbafed93cec1619590157335eajvergara}
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
6a67d144095c31bbafed93cec1619590157335eajvergara/** @copydoc VBOXSERVICE::pfnInit */
6a67d144095c31bbafed93cec1619590157335eajvergarastatic DECLCALLBACK(int) VBoxServiceVMStatsInit(void)
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara VBoxServiceVerbose(3, "VBoxServiceVMStatsInit\n");
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara int rc = RTSemEventMultiCreate(&g_VMStatEvent);
6a67d144095c31bbafed93cec1619590157335eajvergara AssertRCReturn(rc, rc);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.cMsStatInterval = 0; /* default; update disabled */
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.ullLastCpuLoad_Idle = 0;
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.ullLastCpuLoad_Kernel = 0;
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara gCtx.ullLastCpuLoad_User = 0;
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara rc = VbglR3StatQueryInterval(&gCtx.cMsStatInterval);
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara if (RT_SUCCESS(rc))
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara VBoxServiceVerbose(3, "VBoxStatsInit: new statistics interval %u seconds\n", gCtx.cMsStatInterval);
20b2af997c687f4604060f7e43e43b3f28766017jvergara else
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara VBoxServiceVerbose(3, "VBoxStatsInit: DeviceIoControl failed with %d\n", rc);
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara#ifdef RT_OS_WINDOWS
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara /* NtQuerySystemInformation might be dropped in future releases, so load it dynamically as per Microsoft's recommendation */
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara HMODULE hMod = LoadLibrary("NTDLL.DLL");
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara if (hMod)
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara {
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara *(uintptr_t *)&gCtx.pfnNtQuerySystemInformation = (uintptr_t)GetProcAddress(hMod, "NtQuerySystemInformation");
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara if (gCtx.pfnNtQuerySystemInformation)
68c6568488f064ce97a76169ef43a8f5f7b1c2f6jvergara VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnNtQuerySystemInformation = %x\n", gCtx.pfnNtQuerySystemInformation);
6a67d144095c31bbafed93cec1619590157335eajvergara else
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara VBoxServiceError("VBoxStatsInit: NTDLL.NtQuerySystemInformation not found!!\n");
6a67d144095c31bbafed93cec1619590157335eajvergara return VERR_NOT_IMPLEMENTED;
6a67d144095c31bbafed93cec1619590157335eajvergara }
5b3741e0620fd2baaa974cecc2c2d953bb7d4fbbkenneth_suter }
6a67d144095c31bbafed93cec1619590157335eajvergara
857225469c51bedb8c0566aa7757800cfaac4075kenneth_suter /* GlobalMemoryStatus is win2k and up, so load it dynamically */
6a67d144095c31bbafed93cec1619590157335eajvergara hMod = LoadLibrary("KERNEL32.DLL");
6a67d144095c31bbafed93cec1619590157335eajvergara if (hMod)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara *(uintptr_t *)&gCtx.pfnGlobalMemoryStatusEx = (uintptr_t)GetProcAddress(hMod, "GlobalMemoryStatusEx");
6a67d144095c31bbafed93cec1619590157335eajvergara if (gCtx.pfnGlobalMemoryStatusEx)
6a67d144095c31bbafed93cec1619590157335eajvergara VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.GlobalMemoryStatusEx = %x\n", gCtx.pfnGlobalMemoryStatusEx);
6a67d144095c31bbafed93cec1619590157335eajvergara else
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara /** @todo now fails in NT4; do we care? */
6a67d144095c31bbafed93cec1619590157335eajvergara VBoxServiceError("VBoxStatsInit: KERNEL32.GlobalMemoryStatusEx not found!!\n");
6a67d144095c31bbafed93cec1619590157335eajvergara return VERR_NOT_IMPLEMENTED;
6a67d144095c31bbafed93cec1619590157335eajvergara }
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter }
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara /* GetPerformanceInfo is xp and up, so load it dynamically */
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara hMod = LoadLibrary("PSAPI.DLL");
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter if (hMod)
6a67d144095c31bbafed93cec1619590157335eajvergara {
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter *(uintptr_t *)&gCtx.pfnGetPerformanceInfo = (uintptr_t)GetProcAddress(hMod, "GetPerformanceInfo");
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara if (gCtx.pfnGetPerformanceInfo)
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnGetPerformanceInfo= %x\n", gCtx.pfnGetPerformanceInfo);
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara /* failure is not fatal */
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara#endif /* RT_OS_WINDOWS */
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara return VINF_SUCCESS;
6a67d144095c31bbafed93cec1619590157335eajvergara}
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergarastatic void VBoxServiceVMStatsReport()
6a67d144095c31bbafed93cec1619590157335eajvergara{
6a67d144095c31bbafed93cec1619590157335eajvergara#if defined(RT_OS_WINDOWS)
6a67d144095c31bbafed93cec1619590157335eajvergara SYSTEM_INFO systemInfo;
6a67d144095c31bbafed93cec1619590157335eajvergara PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pProcInfo;
6a67d144095c31bbafed93cec1619590157335eajvergara MEMORYSTATUSEX memStatus;
c78c4e1812dcdaed5437c85f6a18a754a479e0bdjvergara VMMDevReportGuestStats req;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara uint32_t cbStruct;
6a67d144095c31bbafed93cec1619590157335eajvergara DWORD cbReturned;
6a67d144095c31bbafed93cec1619590157335eajvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara Assert(gCtx.pfnGlobalMemoryStatusEx && gCtx.pfnNtQuerySystemInformation);
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara if ( !gCtx.pfnGlobalMemoryStatusEx
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara || !gCtx.pfnNtQuerySystemInformation)
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara return;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
6a67d144095c31bbafed93cec1619590157335eajvergara /* Query and report guest statistics */
6a67d144095c31bbafed93cec1619590157335eajvergara GetSystemInfo(&systemInfo);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara memStatus.dwLength = sizeof(memStatus);
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara gCtx.pfnGlobalMemoryStatusEx(&memStatus);
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara req.guestStats.u32PageSize = systemInfo.dwPageSize;
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32PhysMemTotal = (uint32_t)(memStatus.ullTotalPhys / systemInfo.dwPageSize);
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32PhysMemAvail = (uint32_t)(memStatus.ullAvailPhys / systemInfo.dwPageSize);
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter /* 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. */
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter req.guestStats.u32PageFileSize = (uint32_t)(memStatus.ullTotalPageFile / systemInfo.dwPageSize) - req.guestStats.u32PhysMemTotal;
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter req.guestStats.u32MemoryLoad = memStatus.dwMemoryLoad;
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32PhysMemBalloon = VBoxServiceBalloonQueryChunks() * (_1M/systemInfo.dwPageSize); /* was in megabytes */
6a67d144095c31bbafed93cec1619590157335eajvergara 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;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara if (gCtx.pfnGetPerformanceInfo)
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara PERFORMANCE_INFORMATION perfInfo;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara if (gCtx.pfnGetPerformanceInfo(&perfInfo, sizeof(perfInfo)))
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara {
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara req.guestStats.u32Processes = perfInfo.ProcessCount;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara req.guestStats.u32Threads = perfInfo.ThreadCount;
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32Handles = perfInfo.HandleCount;
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32MemCommitTotal = perfInfo.CommitTotal; /* already in pages */
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32MemKernelTotal = perfInfo.KernelTotal; /* already in pages */
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara req.guestStats.u32MemKernelPaged = perfInfo.KernelPaged; /* already in pages */
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara req.guestStats.u32MemKernelNonPaged = perfInfo.KernelNonpaged; /* already in pages */
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32MemSystemCache = perfInfo.SystemCache; /* already in pages */
6a67d144095c31bbafed93cec1619590157335eajvergara 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;
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara else
6a67d144095c31bbafed93cec1619590157335eajvergara VBoxServiceVerbose(3, "GetPerformanceInfo failed with %d\n", GetLastError());
6a67d144095c31bbafed93cec1619590157335eajvergara }
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara /* Query CPU load information */
6a67d144095c31bbafed93cec1619590157335eajvergara cbStruct = systemInfo.dwNumberOfProcessors*sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
6a67d144095c31bbafed93cec1619590157335eajvergara pProcInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(cbStruct);
6a67d144095c31bbafed93cec1619590157335eajvergara Assert(pProcInfo);
6a67d144095c31bbafed93cec1619590157335eajvergara if (!pProcInfo)
6a67d144095c31bbafed93cec1619590157335eajvergara return;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara /* Unfortunately GetSystemTimes is XP SP1 and up only, so we need to use the semi-undocumented NtQuerySystemInformation */
6a67d144095c31bbafed93cec1619590157335eajvergara NTSTATUS rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
6a67d144095c31bbafed93cec1619590157335eajvergara if ( !rc
6a67d144095c31bbafed93cec1619590157335eajvergara && cbReturned == cbStruct)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara if (gCtx.ullLastCpuLoad_Kernel == 0)
6a67d144095c31bbafed93cec1619590157335eajvergara {
6a67d144095c31bbafed93cec1619590157335eajvergara /* first time */
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.ullLastCpuLoad_Idle = pProcInfo->IdleTime.QuadPart;
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.ullLastCpuLoad_Kernel = pProcInfo->KernelTime.QuadPart;
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.ullLastCpuLoad_User = pProcInfo->UserTime.QuadPart;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara Sleep(250);
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
6a67d144095c31bbafed93cec1619590157335eajvergara Assert(!rc);
6a67d144095c31bbafed93cec1619590157335eajvergara }
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter
6a67d144095c31bbafed93cec1619590157335eajvergara uint64_t deltaIdle = (pProcInfo->IdleTime.QuadPart - gCtx.ullLastCpuLoad_Idle);
6a67d144095c31bbafed93cec1619590157335eajvergara uint64_t deltaKernel = (pProcInfo->KernelTime.QuadPart - gCtx.ullLastCpuLoad_Kernel);
6a67d144095c31bbafed93cec1619590157335eajvergara uint64_t deltaUser = (pProcInfo->UserTime.QuadPart - gCtx.ullLastCpuLoad_User);
6a67d144095c31bbafed93cec1619590157335eajvergara deltaKernel -= deltaIdle; /* idle time is added to kernel time */
6a67d144095c31bbafed93cec1619590157335eajvergara uint64_t ullTotalTime = deltaIdle + deltaKernel + deltaUser;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32CpuLoad_Idle = (uint32_t)(deltaIdle * 100 / ullTotalTime);
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32CpuLoad_Kernel = (uint32_t)(deltaKernel* 100 / ullTotalTime);
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32CpuLoad_User = (uint32_t)(deltaUser * 100 / ullTotalTime);
3e6ff045d382a718a951d6305c8910ffc268f893kenneth_suter
6a67d144095c31bbafed93cec1619590157335eajvergara req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE | VBOX_GUEST_STAT_CPU_LOAD_KERNEL | VBOX_GUEST_STAT_CPU_LOAD_USER;
6a67d144095c31bbafed93cec1619590157335eajvergara
6a67d144095c31bbafed93cec1619590157335eajvergara gCtx.ullLastCpuLoad_Idle = pProcInfo->IdleTime.QuadPart;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara gCtx.ullLastCpuLoad_Kernel = pProcInfo->KernelTime.QuadPart;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara gCtx.ullLastCpuLoad_User = pProcInfo->UserTime.QuadPart;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara }
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara for (uint32_t i=0; i<systemInfo.dwNumberOfProcessors; i++)
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara {
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara req.guestStats.u32CpuId = i;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara rc = VbglR3StatReport(&req);
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara if (RT_SUCCESS(rc))
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics reported successfully!\n");
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara else
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara VBoxServiceVerbose(3, "VBoxStatsReportStatistics: DeviceIoControl (stats report) failed with %d\n", GetLastError());
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara }
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara free(pProcInfo);
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara#elif defined(RT_OS_LINUX)
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara VMMDevReportGuestStats req;
11178d20048abeee671d0cdb2aab6dfbaa36293bjvergara RT_ZERO(req);
6a67d144095c31bbafed93cec1619590157335eajvergara PRTSTREAM pStrm;
char szLine[256];
char *psz;
int rc = RTStrmOpen("/proc/meminfo", "r", &pStrm);
if (RT_SUCCESS(rc))
{
uint64_t u64Kb;
uint64_t u64Total = 0, u64Free = 0, u64Buffers = 0, u64Cached = 0, u64PagedTotal = 0;
for (;;)
{
rc = RTStrmGetLine(pStrm, szLine, sizeof(szLine));
if (RT_FAILURE(rc))
break;
if (strstr("MemTotal:", szLine) == szLine)
{
rc = RTStrToUInt64Ex(RTStrStripL(&szLine[9]), &psz, 0, &u64Kb);
if (RT_SUCCESS(rc))
u64Total = u64Kb * _1K;
}
else if (strstr("MemFree:", szLine) == szLine)
{
rc = RTStrToUInt64Ex(RTStrStripL(&szLine[8]), &psz, 0, &u64Kb);
if (RT_SUCCESS(rc))
u64Free = u64Kb * _1K;
}
else if (strstr("Buffers:", szLine) == szLine)
{
rc = RTStrToUInt64Ex(RTStrStripL(&szLine[8]), &psz, 0, &u64Kb);
if (RT_SUCCESS(rc))
u64Buffers = u64Kb * _1K;
}
else if (strstr("Cached:", szLine) == szLine)
{
rc = RTStrToUInt64Ex(RTStrStripL(&szLine[7]), &psz, 0, &u64Kb);
if (RT_SUCCESS(rc))
u64Cached = u64Kb * _1K;
}
else if (strstr("SwapTotal:", szLine) == szLine)
{
rc = RTStrToUInt64Ex(RTStrStripL(&szLine[10]), &psz, 0, &u64Kb);
if (RT_SUCCESS(rc))
u64PagedTotal = u64Kb * _1K;
}
}
req.guestStats.u32PhysMemTotal = u64Total / _4K;
req.guestStats.u32PhysMemAvail = (u64Free + u64Buffers + u64Cached) / _4K;
req.guestStats.u32MemSystemCache = (u64Buffers + u64Cached) / _4K;
req.guestStats.u32PageFileSize = u64PagedTotal / _4K;
RTStrmClose(pStrm);
}
req.guestStats.u32PhysMemBalloon = VBoxServiceBalloonQueryChunks() * (_1M/_4K);
req.guestStats.u32StatCaps = VBOX_GUEST_STAT_PHYS_MEM_TOTAL \
| VBOX_GUEST_STAT_PHYS_MEM_AVAIL \
| VBOX_GUEST_STAT_PHYS_MEM_BALLOON \
| VBOX_GUEST_STAT_PAGE_FILE_SIZE;
rc = RTStrmOpen("/proc/stat", "r", &pStrm);
if (RT_SUCCESS(rc))
{
for (;;)
{
uint64_t u64CpuId, u64User = 0, u64Nice = 0, u64System = 0, u64Idle = 0;
rc = RTStrmGetLine(pStrm, szLine, sizeof(szLine));
if (RT_FAILURE(rc))
break;
if ( strstr("cpu", szLine) == szLine
&& strlen(szLine) > 3
&& RT_C_IS_DIGIT(szLine[3]))
{
rc = RTStrToUInt64Ex(&szLine[3], &psz, 0, &u64CpuId);
if (RT_SUCCESS(rc))
rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64User);
if (RT_SUCCESS(rc))
rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64Nice);
if (RT_SUCCESS(rc))
rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64System);
if (RT_SUCCESS(rc))
rc = RTStrToUInt64Ex(RTStrStripL(psz), &psz, 0, &u64Idle);
uint64_t u64All = u64Idle + u64System + u64User + u64Nice;
req.guestStats.u32CpuId = u64CpuId;
req.guestStats.u32CpuLoad_Idle = (uint32_t)(u64Idle * 100 / u64All);
req.guestStats.u32CpuLoad_Kernel = (uint32_t)(u64System * 100 / u64All);
req.guestStats.u32CpuLoad_User = (uint32_t)((u64User + u64Nice) * 100 / u64All);
req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE \
| VBOX_GUEST_STAT_CPU_LOAD_KERNEL \
| VBOX_GUEST_STAT_CPU_LOAD_USER;
rc = VbglR3StatReport(&req);
if (RT_SUCCESS(rc))
VBoxServiceVerbose(3, "VBoxStatsReportStatistics: new statistics reported successfully!\n");
else
VBoxServiceVerbose(3, "VBoxStatsReportStatistics: stats report failed with rc=%Rrc\n", rc);
}
}
RTStrmClose(pStrm);
}
#else
/* todo: implement for other platforms. */
#endif
}
/** @copydoc VBOXSERVICE::pfnWorker */
DECLCALLBACK(int) VBoxServiceVMStatsWorker(bool volatile *pfShutdown)
{
int rc = VINF_SUCCESS;
/* Start monitoring of the stat event change event. */
rc = VbglR3CtlFilterMask(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0);
if (RT_FAILURE(rc))
{
VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc);
return rc;
}
/*
* Tell the control thread that it can continue
* spawning services.
*/
RTThreadUserSignal(RTThreadSelf());
/*
* Now enter the loop retrieving runtime data continuously.
*/
for (;;)
{
uint32_t fEvents = 0;
RTMSINTERVAL cWaitMillies;
/* Check if an update interval change is pending. */
rc = VbglR3WaitEvent(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0 /* no wait */, &fEvents);
if ( RT_SUCCESS(rc)
&& (fEvents & VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST))
{
VbglR3StatQueryInterval(&gCtx.cMsStatInterval);
}
if (gCtx.cMsStatInterval)
{
VBoxServiceVMStatsReport();
cWaitMillies = gCtx.cMsStatInterval;
}
else
cWaitMillies = 3000;
/*
* Block for a while.
*
* The event semaphore takes care of ignoring interruptions and it
* allows us to implement service wakeup later.
*/
if (*pfShutdown)
break;
int rc2 = RTSemEventMultiWait(g_VMStatEvent, cWaitMillies);
if (*pfShutdown)
break;
if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
{
VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
rc = rc2;
break;
}
}
/* Cancel monitoring of the stat event change event. */
rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
if (RT_FAILURE(rc))
VBoxServiceVerbose(3, "VBoxServiceVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc);
RTSemEventMultiDestroy(g_VMStatEvent);
g_VMStatEvent = NIL_RTSEMEVENTMULTI;
VBoxServiceVerbose(3, "VBoxStatsThread: finished statistics change request thread\n");
return 0;
}
/** @copydoc VBOXSERVICE::pfnTerm */
static DECLCALLBACK(void) VBoxServiceVMStatsTerm(void)
{
VBoxServiceVerbose(3, "VBoxServiceVMStatsTerm\n");
return;
}
/** @copydoc VBOXSERVICE::pfnStop */
static DECLCALLBACK(void) VBoxServiceVMStatsStop(void)
{
RTSemEventMultiSignal(g_VMStatEvent);
}
/**
* The 'vminfo' service description.
*/
VBOXSERVICE g_VMStatistics =
{
/* pszName. */
"vmstats",
/* pszDescription. */
"Virtual Machine Statistics",
/* pszUsage. */
NULL,
/* pszOptions. */
NULL,
/* methods */
VBoxServiceVMStatsPreInit,
VBoxServiceVMStatsOption,
VBoxServiceVMStatsInit,
VBoxServiceVMStatsWorker,
VBoxServiceVMStatsStop,
VBoxServiceVMStatsTerm
};