VBoxModBallooning.cpp revision a31bef2bce334fe03729af420c3041d374973184
/* $Id$ */
/** @file
* VBoxModBallooning - Module for handling the automatic ballooning of VMs.
*/
/*
* Copyright (C) 2011-2012 Oracle Corporation
*
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifndef VBOX_ONLY_DOCS
#endif /* !VBOX_ONLY_DOCS */
#include "VBoxWatchdogInternal.h"
using namespace com;
#define VBOX_MOD_BALLOONING_NAME "balloonctrl"
/**
* The module's RTGetOpt-IDs for the command line.
*/
{
GETOPTDEF_BALLOONCTRL_BALLOOINC = 2000,
};
/**
* The module's command line arguments.
*/
static const RTGETOPTDEF g_aBalloonOpts[] = {
};
static unsigned long g_ulMemoryBalloonTimeoutMS = 0;
static unsigned long g_ulMemoryBalloonIncrementMB = 0;
static unsigned long g_ulMemoryBalloonDecrementMB = 0;
/** Global balloon limit is 0, so disabled. Can be overridden by a per-VM
* "VBoxInternal/Guest/BalloonSizeMax" value. */
static unsigned long g_ulMemoryBalloonMaxMB = 0;
static unsigned long g_ulMemoryBalloonLowerLimitMB = 0;
/** The ballooning module's payload. */
typedef struct VBOXWATCHDOG_BALLOONCTRL_PAYLOAD
{
/** The maximum ballooning size for the VM.
* Specify 0 for ballooning disabled. */
unsigned long ulBalloonSizeMax;
/**
* Retrieves the current delta value
*
* @return long Delta (MB) of the balloon to be deflated (<0) or inflated (>0).
* @param ulCurrentDesktopBalloonSize The balloon's current size.
* @param ulDesktopFreeMemory The VM's current free memory.
* @param ulMaxBalloonSize The maximum balloon size (MB) it can inflate to.
*/
static long balloonGetDelta(unsigned long ulCurrentDesktopBalloonSize,
unsigned long ulDesktopFreeMemory, unsigned long ulMaxBalloonSize)
{
return (ulMaxBalloonSize - ulCurrentDesktopBalloonSize);
long lBalloonDelta = 0;
{
/* Guest is running low on memory, we need to
* deflate the balloon. */
/* Ensure that the delta will not return a negative
* balloon size. */
if ((long)ulCurrentDesktopBalloonSize + lBalloonDelta < 0)
lBalloonDelta = 0;
}
else if (ulMaxBalloonSize > ulCurrentDesktopBalloonSize)
{
/* We want to inflate the balloon if we have room. */
{
}
}
return lBalloonDelta;
}
/**
* Determines the maximum balloon size to set for the specified machine.
*
* @return unsigned long Balloon size (in MB) to set, 0 if no ballooning required.
* @param rptrMachine Pointer to interface of specified machine.
*/
{
/*
* Try to retrieve the balloon maximum size via the following order:
* - command line parameter ("--balloon-max")
* Legacy (VBoxBalloonCtrl):
* - per-VM parameter ("VBoxInternal/Guest/BalloonSizeMax")
* Global:
* - global parameter ("VBoxInternal/Guest/BalloonSizeMax")
* New:
* - per-VM parameter ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
*
* By default (e.g. if none of above is set), ballooning is disabled.
*/
unsigned long ulBalloonMax = g_ulMemoryBalloonMaxMB;
if (!ulBalloonMax)
{
"VBoxInternal/Guest/BalloonSizeMax", "VBoxInternal/Guest/BalloonSizeMax", &ulBalloonMax, 0 /* Ballooning disabled */);
if (RT_FAILURE(vrc))
{
/* Try (new) VBoxWatch per-VM approach. */
HRESULT rc = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
strValue.asOutParam());
{
}
}
}
return ulBalloonMax;
}
/**
* Indicates whether ballooning on the specified machine state is
* possible -- this only is true if the machine is up and running.
*
* @return bool Flag indicating whether the VM is running or not.
* @param enmState The VM's machine state to judge whether it's running or not.
*/
{
switch (enmState)
{
case MachineState_Running:
#if 0
/* Not required for ballooning. */
case MachineState_Teleporting:
case MachineState_Paused:
#endif
return true;
default:
break;
}
return false;
}
/**
* Determines whether ballooning is required to the specified machine.
*
* @return bool True if ballooning is required, false if not.
* @param pMachine Machine to determine ballooning for.
*/
{
AssertPtrReturn(pMachine, false);
/* Only do ballooning if we have a maximum balloon size set. */
/** @todo Add grouping as a criteria! */
return pData->ulBalloonSizeMax ? true : false;
}
{
int vrc = VINF_SUCCESS;
do
{
/*
* Setup metrics required for ballooning.
*/
#ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL
5 /* 5 seconds */,
1 /* One sample is enough */,
#else
5 /* 5 seconds */,
1 /* One sample is enough */,
#endif
} while (0);
return vrc;
}
/**
* Does the actual ballooning and assumes the machine is
* capable and ready for ballooning.
*
* @return IPRT status code.
* @param strUuid UUID of the specified machine.
* @param pMachine Pointer to the machine's internal structure.
*/
{
/*
* Get metrics collected at this point.
*/
if (RT_SUCCESS(vrc))
if (RT_SUCCESS(vrc))
{
/* If guest statistics are not up and running yet, skip this iteration
* and try next time. */
if (lMemFree <= 0)
{
#ifdef DEBUG
#endif
return VINF_SUCCESS;
}
lMemFree /= 1024;
lBalloonCur /= 1024;
serviceLogVerbose(("%ls: Balloon: %ld, Free mem: %ld, Max ballon: %ld\n",
/* Calculate current balloon delta. */
if (lDelta) /* Only do ballooning if there's really smth. to change ... */
{
Assert(lBalloonCur > 0);
serviceLog("%ls: %s balloon by %ld to %ld ...\n",
if (!g_fDryrun)
{
/* Open a session for the VM. */
do
{
/* Get the associated console. */
else
serviceLog("Error: Unable to set new balloon size %ld for machine \"%ls\", rc=%Rhrc",
} while (0);
/* Unlock the machine again. */
}
}
}
else
serviceLog("Error: Unable to retrieve metrics for machine \"%ls\", rc=%Rrc",
return vrc;
}
/* Callbacks. */
static DECLCALLBACK(int) VBoxModBallooningPreInit(void)
{
return VINF_SUCCESS;
}
{
if (!argc) /* Take a shortcut. */
return -1;
0 /* First */, 0 /*fFlags*/);
if (RT_FAILURE(rc))
return rc;
rc = 0; /* Set default parsing result to valid. */
int c;
{
switch (c)
{
break;
break;
/** @todo Add ballooning groups cmd line arg. */
break;
break;
break;
/** @todo This option is a common module option! Put
* this into a utility function! */
if (g_ulMemoryBalloonTimeoutMS < 500)
g_ulMemoryBalloonTimeoutMS = 500;
break;
default:
break;
}
}
return rc;
}
static DECLCALLBACK(int) VBoxModBallooningInit(void)
{
&g_ulMemoryBalloonIncrementMB, 256);
&g_ulMemoryBalloonDecrementMB, 128);
&g_ulMemoryBalloonLowerLimitMB, 128);
return VINF_SUCCESS;
}
static DECLCALLBACK(int) VBoxModBallooningMain(void)
{
return VINF_SUCCESS;
int rc = VINF_SUCCESS;
/** @todo Provide API for enumerating/working w/ machines inside a module! */
{
/* Our actual ballooning criteria. */
if ( balloonIsPossible(state)
{
}
if (RT_FAILURE(rc))
break;
it++;
}
return rc;
}
static DECLCALLBACK(int) VBoxModBallooningStop(void)
{
return VINF_SUCCESS;
}
static DECLCALLBACK(void) VBoxModBallooningTerm(void)
{
}
{
sizeof(VBOXWATCHDOG_BALLOONCTRL_PAYLOAD), (void**)&pData);
if (RT_SUCCESS(rc))
return rc;
}
{
return VINF_SUCCESS;
}
{
/* Note: The machine state will change to "setting up" when machine gets deleted,
* so pMachine might be NULL here. */
if (!pMachine)
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
/**
* The 'balloonctrl' module description.
*/
{
/* pszName. */
/* pszDescription. */
"Memory Ballooning Control",
/* pszDepends. */
NULL,
/* uPriority. */
0 /* Not used */,
/* pszUsage. */
" [--balloon-dec=<MB>] [--balloon-groups=<string>] [--balloon-inc=<MB>]\n"
" [--balloon-interval=<ms>] [--balloon-lower-limit=<MB>]\n"
" [--balloon-max=<MB>]\n",
/* pszOptions. */
"--balloon-dec Sets the ballooning decrement in MB (128 MB).\n"
"--balloon-groups Sets the VM groups for ballooning (all).\n"
"--balloon-inc Sets the ballooning increment in MB (256 MB).\n"
"--balloon-interval Sets the check interval in ms (30 seconds).\n"
"--balloon-lower-limit Sets the ballooning lower limit in MB (64 MB).\n"
"--balloon-max Sets the balloon maximum limit in MB (0 MB).\n"
" Specifying \"0\" means disabled ballooning.\n"
#if 1
/* (Legacy) note. */
"Set \"VBoxInternal/Guest/BalloonSizeMax\" for a per-VM maximum ballooning size.\n"
#endif
,
/* methods. */
/* callbacks. */
};