Commit 33d268ed authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by Greg Kroah-Hartman

VMware balloon: Do not limit the amount of frees and allocations in non-sleep mode.

When VMware's hypervisor requests a VM to reclaim memory this is preferrably done
via ballooning. If the balloon driver does not return memory fast enough, more
drastic methods, such as hypervisor-level swapping are needed. These other methods
cause performance issues, e.g. hypervisor-level swapping requires the hypervisor to
swap in a page syncronously while the virtual CPU is blocked.

Hence it is in the interest of the VM to balloon memory as fast as possible. The
problem with doing this is that the VM might end up doing nothing else than
ballooning and the user might notice that the VM is stalled, esp. when the VM has
only a single virtual CPU.

This is less of a problem if the VM and the hypervisor perform balloon operations
faster. Also the balloon driver yields regularly, hence on a single virtual CPU
the Linux scheduler should be able to properly time-slice between ballooning and
other tasks.

Testing Done: quickly ballooned a lot of pages while wathing if there are any
perceived hickups (periods of non-responsiveness) in the execution of the
linux VM. No such hickups were seen.
Signed-off-by: default avatarXavier Deguillard <xdeguillard@vmware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b36e89da
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
MODULE_AUTHOR("VMware, Inc."); MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver");
MODULE_VERSION("1.3.3.0-k"); MODULE_VERSION("1.3.4.0-k");
MODULE_ALIAS("dmi:*:svnVMware*:*"); MODULE_ALIAS("dmi:*:svnVMware*:*");
MODULE_ALIAS("vmware_vmmemctl"); MODULE_ALIAS("vmware_vmmemctl");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -57,12 +57,6 @@ MODULE_LICENSE("GPL"); ...@@ -57,12 +57,6 @@ MODULE_LICENSE("GPL");
* measured in pages. * measured in pages.
*/ */
/*
* Rate of allocating memory when there is no memory pressure
* (driver performs non-sleeping allocations).
*/
#define VMW_BALLOON_NOSLEEP_ALLOC_MAX 16384U
/* /*
* Rates of memory allocaton when guest experiences memory pressure * Rates of memory allocaton when guest experiences memory pressure
* (driver performs sleeping allocations). * (driver performs sleeping allocations).
...@@ -71,13 +65,6 @@ MODULE_LICENSE("GPL"); ...@@ -71,13 +65,6 @@ MODULE_LICENSE("GPL");
#define VMW_BALLOON_RATE_ALLOC_MAX 2048U #define VMW_BALLOON_RATE_ALLOC_MAX 2048U
#define VMW_BALLOON_RATE_ALLOC_INC 16U #define VMW_BALLOON_RATE_ALLOC_INC 16U
/*
* Rates for releasing pages while deflating balloon.
*/
#define VMW_BALLOON_RATE_FREE_MIN 512U
#define VMW_BALLOON_RATE_FREE_MAX 16384U
#define VMW_BALLOON_RATE_FREE_INC 16U
/* /*
* When guest is under memory pressure, use a reduced page allocation * When guest is under memory pressure, use a reduced page allocation
* rate for next several cycles. * rate for next several cycles.
...@@ -100,9 +87,6 @@ MODULE_LICENSE("GPL"); ...@@ -100,9 +87,6 @@ MODULE_LICENSE("GPL");
*/ */
#define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER) #define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER)
/* Maximum number of page allocations without yielding processor */
#define VMW_BALLOON_YIELD_THRESHOLD 1024
/* Maximum number of refused pages we accumulate during inflation cycle */ /* Maximum number of refused pages we accumulate during inflation cycle */
#define VMW_BALLOON_MAX_REFUSED 16 #define VMW_BALLOON_MAX_REFUSED 16
...@@ -279,7 +263,6 @@ struct vmballoon { ...@@ -279,7 +263,6 @@ struct vmballoon {
/* adjustment rates (pages per second) */ /* adjustment rates (pages per second) */
unsigned int rate_alloc; unsigned int rate_alloc;
unsigned int rate_free;
/* slowdown page allocations for next few cycles */ /* slowdown page allocations for next few cycles */
unsigned int slow_allocation_cycles; unsigned int slow_allocation_cycles;
...@@ -503,19 +486,14 @@ static bool vmballoon_send_batched_unlock(struct vmballoon *b, ...@@ -503,19 +486,14 @@ static bool vmballoon_send_batched_unlock(struct vmballoon *b,
static void vmballoon_pop(struct vmballoon *b) static void vmballoon_pop(struct vmballoon *b)
{ {
struct page *page, *next; struct page *page, *next;
unsigned int count = 0;
list_for_each_entry_safe(page, next, &b->pages, lru) { list_for_each_entry_safe(page, next, &b->pages, lru) {
list_del(&page->lru); list_del(&page->lru);
__free_page(page); __free_page(page);
STATS_INC(b->stats.free); STATS_INC(b->stats.free);
b->size--; b->size--;
if (++count >= b->rate_free) {
count = 0;
cond_resched(); cond_resched();
} }
}
if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) { if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) {
if (b->batch_page) if (b->batch_page)
...@@ -716,7 +694,7 @@ static void vmballoon_add_batched_page(struct vmballoon *b, int idx, ...@@ -716,7 +694,7 @@ static void vmballoon_add_batched_page(struct vmballoon *b, int idx,
*/ */
static void vmballoon_inflate(struct vmballoon *b) static void vmballoon_inflate(struct vmballoon *b)
{ {
unsigned int rate; unsigned rate;
unsigned int allocations = 0; unsigned int allocations = 0;
unsigned int num_pages = 0; unsigned int num_pages = 0;
int error = 0; int error = 0;
...@@ -743,13 +721,13 @@ static void vmballoon_inflate(struct vmballoon *b) ...@@ -743,13 +721,13 @@ static void vmballoon_inflate(struct vmballoon *b)
* Start with no sleep allocation rate which may be higher * Start with no sleep allocation rate which may be higher
* than sleeping allocation rate. * than sleeping allocation rate.
*/ */
rate = b->slow_allocation_cycles ? rate = b->slow_allocation_cycles ? b->rate_alloc : UINT_MAX;
b->rate_alloc : VMW_BALLOON_NOSLEEP_ALLOC_MAX;
pr_debug("%s - goal: %d, no-sleep rate: %d, sleep rate: %d\n", pr_debug("%s - goal: %d, no-sleep rate: %u, sleep rate: %d\n",
__func__, b->target - b->size, rate, b->rate_alloc); __func__, b->target - b->size, rate, b->rate_alloc);
while (b->size < b->target && num_pages < b->target - b->size) { while (!b->reset_required &&
b->size < b->target && num_pages < b->target - b->size) {
struct page *page; struct page *page;
if (flags == VMW_PAGE_ALLOC_NOSLEEP) if (flags == VMW_PAGE_ALLOC_NOSLEEP)
...@@ -799,10 +777,7 @@ static void vmballoon_inflate(struct vmballoon *b) ...@@ -799,10 +777,7 @@ static void vmballoon_inflate(struct vmballoon *b)
break; break;
} }
if (++allocations > VMW_BALLOON_YIELD_THRESHOLD) {
cond_resched(); cond_resched();
allocations = 0;
}
if (allocations >= rate) { if (allocations >= rate) {
/* We allocated enough pages, let's take a break. */ /* We allocated enough pages, let's take a break. */
...@@ -838,36 +813,29 @@ static void vmballoon_deflate(struct vmballoon *b) ...@@ -838,36 +813,29 @@ static void vmballoon_deflate(struct vmballoon *b)
unsigned int num_pages = 0; unsigned int num_pages = 0;
int error; int error;
pr_debug("%s - size: %d, target %d, rate: %d\n", __func__, b->size, pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target);
b->target, b->rate_free);
/* free pages to reach target */ /* free pages to reach target */
list_for_each_entry_safe(page, next, &b->pages, lru) { list_for_each_entry_safe(page, next, &b->pages, lru) {
list_del(&page->lru); list_del(&page->lru);
b->ops->add_page(b, num_pages++, page); b->ops->add_page(b, num_pages++, page);
if (num_pages == b->batch_max_pages) { if (num_pages == b->batch_max_pages) {
error = b->ops->unlock(b, num_pages, &b->target); error = b->ops->unlock(b, num_pages, &b->target);
num_pages = 0; num_pages = 0;
if (error) { if (error)
/* quickly decrease rate in case of error */
b->rate_free = max(b->rate_free / 2,
VMW_BALLOON_RATE_FREE_MIN);
return; return;
} }
}
if (++i >= b->size - b->target) if (b->reset_required || ++i >= b->size - b->target)
break; break;
cond_resched();
} }
if (num_pages > 0) if (num_pages > 0)
b->ops->unlock(b, num_pages, &b->target); b->ops->unlock(b, num_pages, &b->target);
/* slowly increase rate if there were no errors */
if (error == 0)
b->rate_free = min(b->rate_free + VMW_BALLOON_RATE_FREE_INC,
VMW_BALLOON_RATE_FREE_MAX);
} }
static const struct vmballoon_ops vmballoon_basic_ops = { static const struct vmballoon_ops vmballoon_basic_ops = {
...@@ -993,11 +961,8 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) ...@@ -993,11 +961,8 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset)
/* format rate info */ /* format rate info */
seq_printf(f, seq_printf(f,
"rateNoSleepAlloc: %8d pages/sec\n" "rateSleepAlloc: %8d pages/sec\n",
"rateSleepAlloc: %8d pages/sec\n" b->rate_alloc);
"rateFree: %8d pages/sec\n",
VMW_BALLOON_NOSLEEP_ALLOC_MAX,
b->rate_alloc, b->rate_free);
seq_printf(f, seq_printf(f,
"\n" "\n"
...@@ -1088,7 +1053,6 @@ static int __init vmballoon_init(void) ...@@ -1088,7 +1053,6 @@ static int __init vmballoon_init(void)
/* initialize rates */ /* initialize rates */
balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX; balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX;
balloon.rate_free = VMW_BALLOON_RATE_FREE_MAX;
INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment