Commit ec992cc7 authored by Nadav Amit's avatar Nadav Amit Committed by Greg Kroah-Hartman

vmw_balloon: remove inflation rate limiting

Since commit 33d268ed ("VMware balloon: Do not limit the amount of
frees and allocations in non-sleep mode."), the allocations are not
increased, and therefore balloon inflation rate limiting is in practice
broken.

While we can restore rate limiting, in practice we see that it can
result in adverse effect, as the hypervisor throttles down the VM if it
does not respond well enough, or alternatively causes it to perform very
poorly as the host swaps out the VM memory. Throttling the VM down can
even have a cascading effect, in which the VM reclaims memory even
slower and consequentially throttled down even further.

We therefore remove all the rate limiting mechanisms, including the slow
allocation cycles, as they are likely to do more harm than good.

Fixes: 33d268ed ("VMware balloon: Do not limit the amount of frees and allocations in non-sleep mode.")
Reviewed-by: default avatarXavier Deguillard <xdeguillard@vmware.com>
Signed-off-by: default avatarNadav Amit <namit@vmware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c3cc1b0f
...@@ -54,25 +54,6 @@ MODULE_ALIAS("dmi:*:svnVMware*:*"); ...@@ -54,25 +54,6 @@ MODULE_ALIAS("dmi:*:svnVMware*:*");
MODULE_ALIAS("vmware_vmmemctl"); MODULE_ALIAS("vmware_vmmemctl");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* Various constants controlling rate of inflaint/deflating balloon,
* measured in pages.
*/
/*
* Rates of memory allocaton when guest experiences memory pressure
* (driver performs sleeping allocations).
*/
#define VMW_BALLOON_RATE_ALLOC_MIN 512U
#define VMW_BALLOON_RATE_ALLOC_MAX 2048U
#define VMW_BALLOON_RATE_ALLOC_INC 16U
/*
* When guest is under memory pressure, use a reduced page allocation
* rate for next several cycles.
*/
#define VMW_BALLOON_SLOW_CYCLES 4
/* /*
* Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't
* allow wait (__GFP_RECLAIM) for NOSLEEP page allocations. Use * allow wait (__GFP_RECLAIM) for NOSLEEP page allocations. Use
...@@ -284,12 +265,6 @@ struct vmballoon { ...@@ -284,12 +265,6 @@ struct vmballoon {
/* reset flag */ /* reset flag */
bool reset_required; bool reset_required;
/* adjustment rates (pages per second) */
unsigned int rate_alloc;
/* slowdown page allocations for next few cycles */
unsigned int slow_allocation_cycles;
unsigned long capabilities; unsigned long capabilities;
struct vmballoon_batch_page *batch_page; struct vmballoon_batch_page *batch_page;
...@@ -797,8 +772,6 @@ static void vmballoon_add_batched_page(struct vmballoon *b, int idx, ...@@ -797,8 +772,6 @@ 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 rate;
unsigned int allocations = 0;
unsigned int num_pages = 0; unsigned int num_pages = 0;
int error = 0; int error = 0;
gfp_t flags = VMW_PAGE_ALLOC_NOSLEEP; gfp_t flags = VMW_PAGE_ALLOC_NOSLEEP;
...@@ -825,17 +798,9 @@ static void vmballoon_inflate(struct vmballoon *b) ...@@ -825,17 +798,9 @@ 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.
*/ */
if (b->slow_allocation_cycles) { is_2m_pages = b->supported_page_sizes == VMW_BALLOON_NUM_PAGE_SIZES;
rate = b->rate_alloc;
is_2m_pages = false;
} else {
rate = UINT_MAX;
is_2m_pages =
b->supported_page_sizes == VMW_BALLOON_NUM_PAGE_SIZES;
}
pr_debug("%s - goal: %d, no-sleep rate: %u, sleep rate: %d\n", pr_debug("%s - goal: %d", __func__, b->target - b->size);
__func__, b->target - b->size, rate, b->rate_alloc);
while (!b->reset_required && while (!b->reset_required &&
b->size + num_pages * vmballoon_page_size(is_2m_pages) b->size + num_pages * vmballoon_page_size(is_2m_pages)
...@@ -868,31 +833,24 @@ static void vmballoon_inflate(struct vmballoon *b) ...@@ -868,31 +833,24 @@ static void vmballoon_inflate(struct vmballoon *b)
if (flags == VMW_PAGE_ALLOC_CANSLEEP) { if (flags == VMW_PAGE_ALLOC_CANSLEEP) {
/* /*
* CANSLEEP page allocation failed, so guest * CANSLEEP page allocation failed, so guest
* is under severe memory pressure. Quickly * is under severe memory pressure. We just log
* decrease allocation rate. * the event, but do not stop the inflation
* due to its negative impact on performance.
*/ */
b->rate_alloc = max(b->rate_alloc / 2,
VMW_BALLOON_RATE_ALLOC_MIN);
STATS_INC(b->stats.sleep_alloc_fail); STATS_INC(b->stats.sleep_alloc_fail);
break; break;
} }
/* /*
* NOSLEEP page allocation failed, so the guest is * NOSLEEP page allocation failed, so the guest is
* under memory pressure. Let us slow down page * under memory pressure. Slowing down page alloctions
* allocations for next few cycles so that the guest * seems to be reasonable, but doing so might actually
* gets out of memory pressure. Also, if we already * cause the hypervisor to throttle us down, resulting
* allocated b->rate_alloc pages, let's pause, * in degraded performance. We will count on the
* otherwise switch to sleeping allocations. * scheduler and standard memory management mechanisms
* for now.
*/ */
b->slow_allocation_cycles = VMW_BALLOON_SLOW_CYCLES;
if (allocations >= b->rate_alloc)
break;
flags = VMW_PAGE_ALLOC_CANSLEEP; flags = VMW_PAGE_ALLOC_CANSLEEP;
/* Lower rate for sleeping allocations. */
rate = b->rate_alloc;
continue; continue;
} }
...@@ -906,28 +864,11 @@ static void vmballoon_inflate(struct vmballoon *b) ...@@ -906,28 +864,11 @@ static void vmballoon_inflate(struct vmballoon *b)
} }
cond_resched(); cond_resched();
if (allocations >= rate) {
/* We allocated enough pages, let's take a break. */
break;
}
} }
if (num_pages > 0) if (num_pages > 0)
b->ops->lock(b, num_pages, is_2m_pages, &b->target); b->ops->lock(b, num_pages, is_2m_pages, &b->target);
/*
* We reached our goal without failures so try increasing
* allocation rate.
*/
if (error == 0 && allocations >= b->rate_alloc) {
unsigned int mult = allocations / b->rate_alloc;
b->rate_alloc =
min(b->rate_alloc + mult * VMW_BALLOON_RATE_ALLOC_INC,
VMW_BALLOON_RATE_ALLOC_MAX);
}
vmballoon_release_refused_pages(b, true); vmballoon_release_refused_pages(b, true);
vmballoon_release_refused_pages(b, false); vmballoon_release_refused_pages(b, false);
} }
...@@ -1122,9 +1063,6 @@ static void vmballoon_work(struct work_struct *work) ...@@ -1122,9 +1063,6 @@ static void vmballoon_work(struct work_struct *work)
if (b->reset_required) if (b->reset_required)
vmballoon_reset(b); vmballoon_reset(b);
if (b->slow_allocation_cycles > 0)
b->slow_allocation_cycles--;
if (!b->reset_required && vmballoon_send_get_target(b, &target)) { if (!b->reset_required && vmballoon_send_get_target(b, &target)) {
/* update target, adjust size */ /* update target, adjust size */
b->target = target; b->target = target;
...@@ -1168,11 +1106,6 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset) ...@@ -1168,11 +1106,6 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset)
"current: %8d pages\n", "current: %8d pages\n",
b->target, b->size); b->target, b->size);
/* format rate info */
seq_printf(f,
"rateSleepAlloc: %8d pages/sec\n",
b->rate_alloc);
seq_printf(f, seq_printf(f,
"\n" "\n"
"timer: %8u\n" "timer: %8u\n"
...@@ -1279,9 +1212,6 @@ static int __init vmballoon_init(void) ...@@ -1279,9 +1212,6 @@ static int __init vmballoon_init(void)
INIT_LIST_HEAD(&balloon.page_sizes[is_2m_pages].refused_pages); INIT_LIST_HEAD(&balloon.page_sizes[is_2m_pages].refused_pages);
} }
/* initialize rates */
balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX;
INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work);
error = vmballoon_debugfs_init(&balloon); error = vmballoon_debugfs_init(&balloon);
......
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