mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
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: Xavier Deguillard <xdeguillard@vmware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b36e89da86
commit
33d268ed00
1 changed files with 16 additions and 52 deletions
|
@ -47,7 +47,7 @@
|
|||
|
||||
MODULE_AUTHOR("VMware, Inc.");
|
||||
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("vmware_vmmemctl");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -57,12 +57,6 @@ MODULE_LICENSE("GPL");
|
|||
* 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
|
||||
* (driver performs sleeping allocations).
|
||||
|
@ -71,13 +65,6 @@ MODULE_LICENSE("GPL");
|
|||
#define VMW_BALLOON_RATE_ALLOC_MAX 2048U
|
||||
#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
|
||||
* rate for next several cycles.
|
||||
|
@ -100,9 +87,6 @@ MODULE_LICENSE("GPL");
|
|||
*/
|
||||
#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 */
|
||||
#define VMW_BALLOON_MAX_REFUSED 16
|
||||
|
||||
|
@ -279,7 +263,6 @@ struct vmballoon {
|
|||
|
||||
/* adjustment rates (pages per second) */
|
||||
unsigned int rate_alloc;
|
||||
unsigned int rate_free;
|
||||
|
||||
/* slowdown page allocations for next few cycles */
|
||||
unsigned int slow_allocation_cycles;
|
||||
|
@ -503,18 +486,13 @@ static bool vmballoon_send_batched_unlock(struct vmballoon *b,
|
|||
static void vmballoon_pop(struct vmballoon *b)
|
||||
{
|
||||
struct page *page, *next;
|
||||
unsigned int count = 0;
|
||||
|
||||
list_for_each_entry_safe(page, next, &b->pages, lru) {
|
||||
list_del(&page->lru);
|
||||
__free_page(page);
|
||||
STATS_INC(b->stats.free);
|
||||
b->size--;
|
||||
|
||||
if (++count >= b->rate_free) {
|
||||
count = 0;
|
||||
cond_resched();
|
||||
}
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if ((b->capabilities & VMW_BALLOON_BATCHED_CMDS) != 0) {
|
||||
|
@ -716,7 +694,7 @@ static void vmballoon_add_batched_page(struct vmballoon *b, int idx,
|
|||
*/
|
||||
static void vmballoon_inflate(struct vmballoon *b)
|
||||
{
|
||||
unsigned int rate;
|
||||
unsigned rate;
|
||||
unsigned int allocations = 0;
|
||||
unsigned int num_pages = 0;
|
||||
int error = 0;
|
||||
|
@ -743,13 +721,13 @@ static void vmballoon_inflate(struct vmballoon *b)
|
|||
* Start with no sleep allocation rate which may be higher
|
||||
* than sleeping allocation rate.
|
||||
*/
|
||||
rate = b->slow_allocation_cycles ?
|
||||
b->rate_alloc : VMW_BALLOON_NOSLEEP_ALLOC_MAX;
|
||||
rate = b->slow_allocation_cycles ? b->rate_alloc : UINT_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);
|
||||
|
||||
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;
|
||||
|
||||
if (flags == VMW_PAGE_ALLOC_NOSLEEP)
|
||||
|
@ -799,10 +777,7 @@ static void vmballoon_inflate(struct vmballoon *b)
|
|||
break;
|
||||
}
|
||||
|
||||
if (++allocations > VMW_BALLOON_YIELD_THRESHOLD) {
|
||||
cond_resched();
|
||||
allocations = 0;
|
||||
}
|
||||
cond_resched();
|
||||
|
||||
if (allocations >= rate) {
|
||||
/* We allocated enough pages, let's take a break. */
|
||||
|
@ -838,36 +813,29 @@ static void vmballoon_deflate(struct vmballoon *b)
|
|||
unsigned int num_pages = 0;
|
||||
int error;
|
||||
|
||||
pr_debug("%s - size: %d, target %d, rate: %d\n", __func__, b->size,
|
||||
b->target, b->rate_free);
|
||||
pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target);
|
||||
|
||||
/* free pages to reach target */
|
||||
list_for_each_entry_safe(page, next, &b->pages, lru) {
|
||||
list_del(&page->lru);
|
||||
b->ops->add_page(b, num_pages++, page);
|
||||
|
||||
|
||||
if (num_pages == b->batch_max_pages) {
|
||||
error = b->ops->unlock(b, num_pages, &b->target);
|
||||
num_pages = 0;
|
||||
if (error) {
|
||||
/* quickly decrease rate in case of error */
|
||||
b->rate_free = max(b->rate_free / 2,
|
||||
VMW_BALLOON_RATE_FREE_MIN);
|
||||
if (error)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (++i >= b->size - b->target)
|
||||
if (b->reset_required || ++i >= b->size - b->target)
|
||||
break;
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (num_pages > 0)
|
||||
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 = {
|
||||
|
@ -993,11 +961,8 @@ static int vmballoon_debug_show(struct seq_file *f, void *offset)
|
|||
|
||||
/* format rate info */
|
||||
seq_printf(f,
|
||||
"rateNoSleepAlloc: %8d pages/sec\n"
|
||||
"rateSleepAlloc: %8d pages/sec\n"
|
||||
"rateFree: %8d pages/sec\n",
|
||||
VMW_BALLOON_NOSLEEP_ALLOC_MAX,
|
||||
b->rate_alloc, b->rate_free);
|
||||
"rateSleepAlloc: %8d pages/sec\n",
|
||||
b->rate_alloc);
|
||||
|
||||
seq_printf(f,
|
||||
"\n"
|
||||
|
@ -1088,7 +1053,6 @@ static int __init vmballoon_init(void)
|
|||
|
||||
/* initialize rates */
|
||||
balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX;
|
||||
balloon.rate_free = VMW_BALLOON_RATE_FREE_MAX;
|
||||
|
||||
INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work);
|
||||
|
||||
|
|
Loading…
Reference in a new issue