VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBalloonCtrl/VBoxModBallooning.cpp@ 59908

Last change on this file since 59908 was 59908, checked in by vboxsync, 9 years ago

VBoxModBallooning.cpp: Forgot to remove debug breakpoint.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.3 KB
Line 
1/* $Id: VBoxModBallooning.cpp 59908 2016-03-03 15:16:05Z vboxsync $ */
2/** @file
3 * VBoxModBallooning - Module for handling the automatic ballooning of VMs.
4 */
5
6/*
7 * Copyright (C) 2011-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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#ifndef VBOX_ONLY_DOCS
23# include <VBox/com/errorprint.h>
24#endif /* !VBOX_ONLY_DOCS */
25
26#include "VBoxWatchdogInternal.h"
27#include <iprt/system.h>
28
29using namespace com;
30
31#define VBOX_MOD_BALLOONING_NAME "balloon"
32
33/*********************************************************************************************************************************
34* Local Structures *
35*********************************************************************************************************************************/
36
37/**
38 * The module's RTGetOpt-IDs for the command line.
39 */
40enum GETOPTDEF_BALLOONCTRL
41{
42 GETOPTDEF_BALLOONCTRL_BALLOONINC = 2000,
43 GETOPTDEF_BALLOONCTRL_BALLOONDEC,
44 GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT,
45 GETOPTDEF_BALLOONCTRL_BALLOONMAX,
46 GETOPTDEF_BALLOONCTRL_BALLOONSAFETY,
47 GETOPTDEF_BALLOONCTRL_TIMEOUTMS,
48 GETOPTDEF_BALLOONCTRL_GROUPS
49};
50
51/**
52 * The module's command line arguments.
53 */
54static const RTGETOPTDEF g_aBalloonOpts[] = {
55 { "--balloon-dec", GETOPTDEF_BALLOONCTRL_BALLOONDEC, RTGETOPT_REQ_UINT32 },
56 { "--balloon-groups", GETOPTDEF_BALLOONCTRL_GROUPS, RTGETOPT_REQ_STRING },
57 { "--balloon-inc", GETOPTDEF_BALLOONCTRL_BALLOONINC, RTGETOPT_REQ_UINT32 },
58 { "--balloon-interval", GETOPTDEF_BALLOONCTRL_TIMEOUTMS, RTGETOPT_REQ_UINT32 },
59 { "--balloon-lower-limit", GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT, RTGETOPT_REQ_UINT32 },
60 { "--balloon-max", GETOPTDEF_BALLOONCTRL_BALLOONMAX, RTGETOPT_REQ_UINT32 },
61 { "--balloon-safety-margin", GETOPTDEF_BALLOONCTRL_BALLOONSAFETY, RTGETOPT_REQ_UINT32 }
62};
63
64/** The ballooning module's payload. */
65typedef struct VBOXWATCHDOG_BALLOONCTRL_PAYLOAD
66{
67 /** The maximum ballooning size for the VM set last.
68 * Specify 0 for ballooning disabled. */
69 unsigned long ulBalloonMaxLast;
70} VBOXWATCHDOG_BALLOONCTRL_PAYLOAD, *PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD;
71
72/*********************************************************************************************************************************
73* Globals *
74*********************************************************************************************************************************/
75
76static unsigned long g_ulMemoryBalloonTimeoutMS = 30 * 1000;
77static unsigned long g_ulMemoryBalloonIncrementMB = 256;
78static unsigned long g_ulMemoryBalloonDecrementMB = 128;
79/** Command line: Global balloon limit (in MB) for all VMs. Default is 0, which means
80 * no global limit is set. See balloonGetMaxSize() for more information. */
81static unsigned long g_ulMemoryBalloonMaxMB = 0;
82static unsigned long g_ulMemoryBalloonLowerLimitMB = 128;
83static unsigned long g_ulMemoryBalloonSafetyMB = 1024;
84
85/*********************************************************************************************************************************
86* Local Function Prototypes *
87*********************************************************************************************************************************/
88static int balloonSetSize(PVBOXWATCHDOG_MACHINE pMachine, unsigned long ulBalloonCur);
89
90/**
91 * Retrieves the current delta value
92 *
93 * @return long Delta (MB) of the balloon to be deflated (<0) or inflated (>0).
94 * @param pMachine Pointer to the machine's internal structure.
95 * @param ulGuestMemFree The guest's current free memory (MB).
96 * @param ulBalloonOld The balloon's current (old) size (MB).
97 * @param ulBalloonNew The balloon's new size (MB).
98 * @param ulBalloonMax The maximum ballooning size (MB) it can inflate to.
99 */
100static long balloonGetDelta(PVBOXWATCHDOG_MACHINE pMachine,
101 unsigned long ulGuestMemFree,
102 unsigned long ulBalloonOld, unsigned long ulBalloonNew, unsigned long ulBalloonMax)
103{
104 serviceLogVerbose(("[%ls] ulGuestMemFree=%RU32, ulBalloonOld=%RU32, ulBalloonNew=%RU32, ulBalloonMax=%RU32\n",
105 pMachine->strName.raw(), ulGuestMemFree, ulBalloonOld, ulBalloonNew, ulBalloonMax));
106
107 /* Make sure that the requested new ballooning size does not
108 * exceed the maximum ballooning size (if set). */
109 if ( ulBalloonMax
110 && (ulBalloonNew > ulBalloonMax))
111 {
112 ulBalloonNew = ulBalloonMax;
113 }
114
115 long lBalloonDelta = 0;
116 if (ulGuestMemFree < g_ulMemoryBalloonLowerLimitMB)
117 {
118 /* Guest is running low on memory, we need to
119 * deflate the balloon. */
120 lBalloonDelta = (g_ulMemoryBalloonDecrementMB * -1);
121
122 /* Ensure that the delta will not return a negative
123 * balloon size. */
124 if ((long)ulBalloonOld + lBalloonDelta < 0)
125 lBalloonDelta = 0;
126 }
127 else if (ulBalloonNew > ulBalloonOld) /* Inflate. */
128 {
129 /* We want to inflate the balloon if we have room. */
130 unsigned long ulIncrement = g_ulMemoryBalloonIncrementMB;
131 while (ulIncrement >= 16 && (ulGuestMemFree - ulIncrement) < g_ulMemoryBalloonLowerLimitMB)
132 ulIncrement = (ulIncrement / 2);
133
134 if ((ulGuestMemFree - ulIncrement) > g_ulMemoryBalloonLowerLimitMB)
135 lBalloonDelta = (long)ulIncrement;
136
137 /* Make sure we're still within bounds. */
138 Assert(lBalloonDelta >= 0);
139 if (ulBalloonOld + lBalloonDelta > ulBalloonNew)
140 lBalloonDelta = RT_MIN(g_ulMemoryBalloonIncrementMB, ulBalloonNew - ulBalloonOld);
141 }
142 else if (ulBalloonNew < ulBalloonOld) /* Deflate. */
143 {
144 lBalloonDelta = RT_CLAMP(g_ulMemoryBalloonDecrementMB, 0, ulBalloonOld - ulBalloonNew) * -1;
145 }
146
147 /* Limit the ballooning to the available host memory, leaving some free.
148 * If anything fails clamp the delta to 0. */
149 if (lBalloonDelta < 0)
150 {
151 uint64_t cbSafety = (uint64_t)g_ulMemoryBalloonSafetyMB * _1M;
152 uint64_t cbHostRamAvail = 0;
153 int vrc = RTSystemQueryAvailableRam(&cbHostRamAvail);
154 if (RT_SUCCESS(vrc))
155 {
156 if (cbHostRamAvail < cbSafety)
157 lBalloonDelta = 0;
158 else if ((uint64_t)(-lBalloonDelta) > (cbHostRamAvail - cbSafety) / _1M)
159 lBalloonDelta = -(long)((cbHostRamAvail - cbSafety) / _1M);
160 }
161 else
162 lBalloonDelta = 0;
163 }
164
165 return lBalloonDelta;
166}
167
168/**
169 * Determines the maximum balloon size to set for the specified machine.
170 *
171 * @return unsigned long Maximum ballooning size (in MB), 0 if no maximum set.
172 * @param pMachine Machine to determine maximum ballooning size for.
173 */
174static unsigned long balloonGetMaxSize(PVBOXWATCHDOG_MACHINE pMachine)
175{
176 const ComPtr<IMachine> &rptrMachine = pMachine->machine;
177
178 /*
179 * Is a maximum ballooning size set? Make sure we're within bounds.
180 *
181 * The maximum balloning size can be set
182 * - via global extra-data ("VBoxInternal/Guest/BalloonSizeMax")
183 * - via command line ("--balloon-max")
184 *
185 * Precedence from top to bottom.
186 */
187 unsigned long ulBalloonMax = 0;
188 char szSource[64];
189
190 Bstr strValue;
191 HRESULT hr = g_pVirtualBox->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
192 strValue.asOutParam());
193 if ( SUCCEEDED(hr)
194 && strValue.isNotEmpty())
195 {
196 ulBalloonMax = Utf8Str(strValue).toUInt32();
197 if (g_fVerbose)
198 RTStrPrintf(szSource, sizeof(szSource), "global extra-data");
199 }
200
201 if (strValue.isEmpty())
202 {
203 Assert(ulBalloonMax == 0);
204
205 ulBalloonMax = g_ulMemoryBalloonMaxMB;
206 if (g_fVerbose)
207 RTStrPrintf(szSource, sizeof(szSource), "command line");
208 }
209
210 serviceLogVerbose(("[%ls] Maximum balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, ulBalloonMax));
211 return ulBalloonMax;
212}
213
214/**
215 * Determines the current (set) balloon size of the specified machine.
216 *
217 * @return IPRT status code.
218 * @param pMachine Machine to determine maximum ballooning size for.
219 * @param pulBalloonCur Where to store the current (set) balloon size (in MB) on success.
220 */
221static int balloonGetCurrentSize(PVBOXWATCHDOG_MACHINE pMachine, unsigned long *pulBalloonCur)
222{
223 LONG lBalloonCur;
224 int vrc = getMetric(pMachine, L"Guest/RAM/Usage/Balloon", &lBalloonCur);
225 if (RT_SUCCESS(vrc))
226 {
227 lBalloonCur /= 1024; /* Convert to MB. */
228 if (pulBalloonCur)
229 *pulBalloonCur = (unsigned long)lBalloonCur;
230 }
231
232 return vrc;
233}
234
235/**
236 * Determines the requested balloon size to set for the specified machine.
237 *
238 * @return unsigned long Requested ballooning size (in MB), 0 if ballooning should be disabled.
239 * @param pMachine Machine to determine maximum ballooning size for.
240 */
241static unsigned long balloonGetRequestedSize(PVBOXWATCHDOG_MACHINE pMachine)
242{
243 const ComPtr<IMachine> &rptrMachine = pMachine->machine;
244
245 /*
246 * The maximum balloning size can be set
247 * - via per-VM extra-data ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
248 * - via per-VM extra-data (legacy) ("VBoxInternal/Guest/BalloonSizeMax")
249 *
250 * Precedence from top to bottom.
251 */
252 unsigned long ulBalloonReq;
253 char szSource[64];
254
255 Bstr strValue;
256 HRESULT hr = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
257 strValue.asOutParam());
258 if ( SUCCEEDED(hr)
259 && strValue.isNotEmpty())
260 {
261 ulBalloonReq = Utf8Str(strValue).toUInt32();
262 if (g_fVerbose)
263 RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data");
264 }
265 else
266 {
267 hr = rptrMachine->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
268 strValue.asOutParam());
269 if ( SUCCEEDED(hr)
270 && strValue.isNotEmpty())
271 {
272 ulBalloonReq = Utf8Str(strValue).toUInt32();
273 if (g_fVerbose)
274 RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data (legacy)");
275 }
276 }
277
278 if ( FAILED(hr)
279 || strValue.isEmpty())
280 {
281 ulBalloonReq = 0;
282 if (g_fVerbose)
283 RTStrPrintf(szSource, sizeof(szSource), "none (disabled)");
284 }
285
286 serviceLogVerbose(("[%ls] Requested balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, ulBalloonReq));
287 return ulBalloonReq;
288}
289
290/**
291 * Indicates whether ballooning on the specified machine state is
292 * possible -- this only is true if the machine is up and running.
293 *
294 * @return bool Flag indicating whether the VM is running or not.
295 * @param enmState The VM's machine state to judge whether it's running or not.
296 */
297static bool balloonIsPossible(MachineState_T enmState)
298{
299 switch (enmState)
300 {
301 case MachineState_Running:
302#if 0
303 /* Not required for ballooning. */
304 case MachineState_Teleporting:
305 case MachineState_LiveSnapshotting:
306 case MachineState_Paused:
307 case MachineState_TeleportingPausedVM:
308#endif
309 return true;
310 default:
311 break;
312 }
313 return false;
314}
315
316int balloonMachineSetup(const Bstr& strUuid)
317{
318 int vrc = VINF_SUCCESS;
319
320 do
321 {
322 PVBOXWATCHDOG_MACHINE pMachine = getMachine(strUuid);
323 AssertPtrBreakStmt(pMachine, vrc=VERR_INVALID_PARAMETER);
324
325 ComPtr<IMachine> m = pMachine->machine;
326
327 /*
328 * Setup metrics required for ballooning.
329 */
330 com::SafeArray<BSTR> metricNames(1);
331 com::SafeIfaceArray<IUnknown> metricObjects(1);
332 com::SafeIfaceArray<IPerformanceMetric> metricAffected;
333
334 Bstr strMetricNames(L"Guest/RAM/Usage");
335 strMetricNames.cloneTo(&metricNames[0]);
336
337 HRESULT rc = m.queryInterfaceTo(&metricObjects[0]);
338
339#ifdef VBOX_WATCHDOG_GLOBAL_PERFCOL
340 CHECK_ERROR_BREAK(g_pPerfCollector, SetupMetrics(ComSafeArrayAsInParam(metricNames),
341 ComSafeArrayAsInParam(metricObjects),
342 5 /* 5 seconds */,
343 1 /* One sample is enough */,
344 ComSafeArrayAsOutParam(metricAffected)));
345#else
346 ComPtr<IPerformanceCollector> coll = pMachine->collector;
347
348 CHECK_ERROR_BREAK(g_pVirtualBox, COMGETTER(PerformanceCollector)(coll.asOutParam()));
349 CHECK_ERROR_BREAK(coll, SetupMetrics(ComSafeArrayAsInParam(metricNames),
350 ComSafeArrayAsInParam(metricObjects),
351 5 /* 5 seconds */,
352 1 /* One sample is enough */,
353 ComSafeArrayAsOutParam(metricAffected)));
354#endif
355 if (FAILED(rc))
356 vrc = VERR_COM_IPRT_ERROR; /* @todo Find better rc! */
357
358 } while (0);
359
360 return vrc;
361}
362
363/**
364 * Does the actual ballooning and assumes the machine is
365 * capable and ready for ballooning.
366 *
367 * @return IPRT status code.
368 * @param pMachine Pointer to the machine's internal structure.
369 */
370static int balloonMachineUpdate(PVBOXWATCHDOG_MACHINE pMachine)
371{
372 AssertPtrReturn(pMachine, VERR_INVALID_POINTER);
373
374 /*
375 * Get metrics collected at this point.
376 */
377 LONG lGuestMemFree;
378 unsigned long ulBalloonCur;
379
380 int vrc = getMetric(pMachine, L"Guest/RAM/Usage/Free", &lGuestMemFree);
381 if (RT_SUCCESS(vrc))
382 vrc = balloonGetCurrentSize(pMachine, &ulBalloonCur);
383
384 if (RT_SUCCESS(vrc))
385 {
386 /* If guest statistics are not up and running yet, skip this iteration and try next time. */
387 if (lGuestMemFree <= 0)
388 {
389#ifdef DEBUG
390 serviceLogVerbose(("[%ls] No metrics available yet!\n", pMachine->strName.raw()));
391#endif
392 return VINF_SUCCESS;
393 }
394
395 lGuestMemFree /= 1024;
396
397 PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD pData = (PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD)
398 payloadFrom(pMachine, VBOX_MOD_BALLOONING_NAME);
399 AssertPtr(pData);
400
401 /* Determine the current set maximum balloon size. */
402 unsigned long ulBalloonMax = balloonGetMaxSize(pMachine);
403
404 /* Determine the requested balloon size. */
405 unsigned long ulBalloonReq = balloonGetRequestedSize(pMachine);
406
407 serviceLogVerbose(("[%ls] Free RAM (MB): %RI32, Ballooning: Current=%RU32MB, Requested=%RU32MB, Maximum=%RU32MB\n",
408 pMachine->strName.raw(), lGuestMemFree, ulBalloonCur, ulBalloonReq, ulBalloonMax));
409
410 if ( ulBalloonMax
411 && (ulBalloonReq > ulBalloonMax))
412 {
413 serviceLog("[%ls] Warning: Requested ballooning size (%RU32MB) exceeds set maximum ballooning size (%RU32MB), limiting ...\n",
414 pMachine->strName.raw(), ulBalloonReq, ulBalloonMax);
415 }
416
417 /* Calculate current balloon delta. */
418 long lBalloonDelta = balloonGetDelta(pMachine,
419 (unsigned long)lGuestMemFree, ulBalloonCur, ulBalloonReq, ulBalloonMax);
420#ifdef DEBUG
421 serviceLogVerbose(("[%ls] lBalloonDelta=%RI32\n", pMachine->strName.raw(), lBalloonDelta));
422#endif
423 if (lBalloonDelta) /* Only do ballooning if there's really smth. to change ... */
424 {
425 ulBalloonCur = ulBalloonCur + lBalloonDelta;
426
427 serviceLog("[%ls] %s balloon by %RU32MB to %RU32MB ...\n",
428 pMachine->strName.raw(), lBalloonDelta > 0 ? "Inflating" : "Deflating", RT_ABS(lBalloonDelta), ulBalloonCur);
429
430 vrc = balloonSetSize(pMachine, ulBalloonCur);
431 if (RT_SUCCESS(vrc))
432 pData->ulBalloonMaxLast = ulBalloonMax;
433 }
434 }
435 else
436 serviceLog("Error: Unable to retrieve metrics for machine '%ls', rc=%Rrc\n",
437 pMachine->strName.raw(), vrc);
438 return vrc;
439}
440
441static int balloonSetSize(PVBOXWATCHDOG_MACHINE pMachine, unsigned long ulBalloonCur)
442{
443 int vrc = VINF_SUCCESS;
444
445 serviceLogVerbose(("[%ls] Setting balloon size to %RU32MB ...\n", pMachine->strName.raw(), ulBalloonCur));
446
447 if (g_fDryrun)
448 return VINF_SUCCESS;
449
450 /* Open a session for the VM. */
451 HRESULT rc;
452 CHECK_ERROR_RET(pMachine->machine, LockMachine(g_pSession, LockType_Shared), VERR_ACCESS_DENIED);
453
454 do
455 {
456 /* Get the associated console. */
457 ComPtr<IConsole> console;
458 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
459
460 ComPtr <IGuest> guest;
461 rc = console->COMGETTER(Guest)(guest.asOutParam());
462 if (SUCCEEDED(rc))
463 CHECK_ERROR_BREAK(guest, COMSETTER(MemoryBalloonSize)((LONG)ulBalloonCur));
464 else
465 serviceLog("Error: Unable to set new balloon size %RU32 for machine '%ls', rc=%Rhrc\n",
466 ulBalloonCur, pMachine->strName.raw(), rc);
467 if (FAILED(rc))
468 vrc = VERR_COM_IPRT_ERROR;
469
470 } while (0);
471
472
473 /* Unlock the machine again. */
474 CHECK_ERROR_RET(g_pSession, UnlockMachine(), VERR_ACCESS_DENIED);
475
476 return vrc;
477}
478
479/* Callbacks. */
480static DECLCALLBACK(int) VBoxModBallooningPreInit(void)
481{
482 return VINF_SUCCESS;
483}
484
485static DECLCALLBACK(int) VBoxModBallooningOption(int argc, char *argv[], int *piConsumed)
486{
487 if (!argc) /* Take a shortcut. */
488 return -1;
489
490 AssertPtrReturn(argv, VERR_INVALID_POINTER);
491 AssertPtrReturn(piConsumed, VERR_INVALID_POINTER);
492
493 RTGETOPTSTATE GetState;
494 int rc = RTGetOptInit(&GetState, argc, argv,
495 g_aBalloonOpts, RT_ELEMENTS(g_aBalloonOpts),
496 0 /* First */, 0 /*fFlags*/);
497 if (RT_FAILURE(rc))
498 return rc;
499
500 rc = 0; /* Set default parsing result to valid. */
501
502 int c;
503 RTGETOPTUNION ValueUnion;
504 while ((c = RTGetOpt(&GetState, &ValueUnion)))
505 {
506 switch (c)
507 {
508 case GETOPTDEF_BALLOONCTRL_BALLOONDEC:
509 g_ulMemoryBalloonDecrementMB = ValueUnion.u32;
510 break;
511
512 case GETOPTDEF_BALLOONCTRL_BALLOONINC:
513 g_ulMemoryBalloonIncrementMB = ValueUnion.u32;
514 break;
515
516 case GETOPTDEF_BALLOONCTRL_GROUPS:
517 /** @todo Add ballooning groups cmd line arg. */
518 break;
519
520 case GETOPTDEF_BALLOONCTRL_BALLOONLOWERLIMIT:
521 g_ulMemoryBalloonLowerLimitMB = ValueUnion.u32;
522 break;
523
524 case GETOPTDEF_BALLOONCTRL_BALLOONMAX:
525 g_ulMemoryBalloonMaxMB = ValueUnion.u32;
526 break;
527
528 case GETOPTDEF_BALLOONCTRL_BALLOONSAFETY:
529 g_ulMemoryBalloonSafetyMB = ValueUnion.u32;
530 break;
531
532 /** @todo This option is a common module option! Put
533 * this into a utility function! */
534 case GETOPTDEF_BALLOONCTRL_TIMEOUTMS:
535 g_ulMemoryBalloonTimeoutMS = ValueUnion.u32;
536 if (g_ulMemoryBalloonTimeoutMS < 500)
537 g_ulMemoryBalloonTimeoutMS = 500;
538 break;
539
540 default:
541 rc = -1; /* We don't handle this option, skip. */
542 break;
543 }
544
545 /* At the moment we only process one option at a time. */
546 break;
547 }
548
549 *piConsumed += GetState.iNext - 1;
550
551 return rc;
552}
553
554static DECLCALLBACK(int) VBoxModBallooningInit(void)
555{
556 if (!g_ulMemoryBalloonTimeoutMS)
557 cfgGetValueULong(g_pVirtualBox, NULL /* Machine */,
558 "VBoxInternal2/Watchdog/BalloonCtrl/TimeoutMS", NULL /* Per-machine */,
559 &g_ulMemoryBalloonTimeoutMS, 30 * 1000 /* Default is 30 seconds timeout. */);
560
561 if (!g_ulMemoryBalloonIncrementMB)
562 cfgGetValueULong(g_pVirtualBox, NULL /* Machine */,
563 "VBoxInternal2/Watchdog/BalloonCtrl/BalloonIncrementMB", NULL /* Per-machine */,
564 &g_ulMemoryBalloonIncrementMB, 256);
565
566 if (!g_ulMemoryBalloonDecrementMB)
567 cfgGetValueULong(g_pVirtualBox, NULL /* Machine */,
568 "VBoxInternal2/Watchdog/BalloonCtrl/BalloonDecrementMB", NULL /* Per-machine */,
569 &g_ulMemoryBalloonDecrementMB, 128);
570
571 if (!g_ulMemoryBalloonLowerLimitMB)
572 cfgGetValueULong(g_pVirtualBox, NULL /* Machine */,
573 "VBoxInternal2/Watchdog/BalloonCtrl/BalloonLowerLimitMB", NULL /* Per-machine */,
574 &g_ulMemoryBalloonLowerLimitMB, 128);
575
576 return VINF_SUCCESS;
577}
578
579static DECLCALLBACK(int) VBoxModBallooningMain(void)
580{
581 static uint64_t s_msLast = RTTimeMilliTS();
582 uint64_t msDelta = RTTimeMilliTS() - s_msLast;
583 if (msDelta <= g_ulMemoryBalloonTimeoutMS)
584 return VINF_SUCCESS;
585
586 int rc = VINF_SUCCESS;
587
588 /** @todo Provide API for enumerating/working w/ machines inside a module! */
589 mapVMIter it = g_mapVM.begin();
590 while (it != g_mapVM.end())
591 {
592 MachineState_T state = getMachineState(&it->second);
593
594 /* Our actual ballooning criteria. */
595 if (balloonIsPossible(state))
596 {
597 rc = balloonMachineUpdate(&it->second);
598 AssertRC(rc);
599 }
600 if (RT_FAILURE(rc))
601 break;
602
603 ++it;
604 }
605
606 s_msLast = RTTimeMilliTS();
607 return rc;
608}
609
610static DECLCALLBACK(int) VBoxModBallooningStop(void)
611{
612 return VINF_SUCCESS;
613}
614
615static DECLCALLBACK(void) VBoxModBallooningTerm(void)
616{
617}
618
619static DECLCALLBACK(int) VBoxModBallooningOnMachineRegistered(const Bstr &strUuid)
620{
621 PVBOXWATCHDOG_MACHINE pMachine = getMachine(strUuid);
622 AssertPtrReturn(pMachine, VERR_INVALID_PARAMETER);
623
624 PVBOXWATCHDOG_BALLOONCTRL_PAYLOAD pData;
625 int rc = payloadAlloc(pMachine, VBOX_MOD_BALLOONING_NAME,
626 sizeof(VBOXWATCHDOG_BALLOONCTRL_PAYLOAD), (void**)&pData);
627 if (RT_SUCCESS(rc))
628 rc = balloonMachineUpdate(pMachine);
629
630 return rc;
631}
632
633static DECLCALLBACK(int) VBoxModBallooningOnMachineUnregistered(const Bstr &strUuid)
634{
635 PVBOXWATCHDOG_MACHINE pMachine = getMachine(strUuid);
636 AssertPtrReturn(pMachine, VERR_INVALID_PARAMETER);
637
638 payloadFree(pMachine, VBOX_MOD_BALLOONING_NAME);
639
640 return VINF_SUCCESS;
641}
642
643static DECLCALLBACK(int) VBoxModBallooningOnMachineStateChanged(const Bstr &strUuid,
644 MachineState_T enmState)
645{
646 PVBOXWATCHDOG_MACHINE pMachine = getMachine(strUuid);
647 /* Note: The machine state will change to "setting up" when machine gets deleted,
648 * so pMachine might be NULL here. */
649 if (!pMachine)
650 return VINF_SUCCESS;
651
652 return balloonMachineUpdate(pMachine);
653}
654
655static DECLCALLBACK(int) VBoxModBallooningOnServiceStateChanged(bool fAvailable)
656{
657 return VINF_SUCCESS;
658}
659
660/**
661 * The 'balloonctrl' module description.
662 */
663VBOXMODULE g_ModBallooning =
664{
665 /* pszName. */
666 VBOX_MOD_BALLOONING_NAME,
667 /* pszDescription. */
668 "Memory Ballooning Control",
669 /* pszDepends. */
670 NULL,
671 /* uPriority. */
672 0 /* Not used */,
673 /* pszUsage. */
674 " [--balloon-dec=<MB>] [--balloon-groups=<string>] [--balloon-inc=<MB>]\n"
675 " [--balloon-interval=<ms>] [--balloon-lower-limit=<MB>]\n"
676 " [--balloon-max=<MB>]\n",
677 /* pszOptions. */
678 "--balloon-dec Sets the ballooning decrement in MB (128 MB).\n"
679 "--balloon-groups Sets the VM groups for ballooning (all).\n"
680 "--balloon-inc Sets the ballooning increment in MB (256 MB).\n"
681 "--balloon-interval Sets the check interval in ms (30 seconds).\n"
682 "--balloon-lower-limit Sets the ballooning lower limit in MB (64 MB).\n"
683 "--balloon-max Sets the balloon maximum limit in MB (0 MB).\n"
684 " Specifying \"0\" means disabled ballooning.\n"
685#if 1
686 /* (Legacy) note. */
687 "Set \"VBoxInternal/Guest/BalloonSizeMax\" for a per-VM maximum ballooning size.\n"
688#endif
689 "--balloon-safety-margin Free memory when deflating a balloon in MB (1024 MB).\n"
690 ,
691 /* methods. */
692 VBoxModBallooningPreInit,
693 VBoxModBallooningOption,
694 VBoxModBallooningInit,
695 VBoxModBallooningMain,
696 VBoxModBallooningStop,
697 VBoxModBallooningTerm,
698 /* callbacks. */
699 VBoxModBallooningOnMachineRegistered,
700 VBoxModBallooningOnMachineUnregistered,
701 VBoxModBallooningOnMachineStateChanged,
702 VBoxModBallooningOnServiceStateChanged
703};
704
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette