[pve-devel] [PATCH] auto balloning with mom algorithm implementation
Alexandre Derumier
aderumier at odiso.com
Mon Dec 10 14:06:01 CET 2012
for test!
require ballooning stats patchs on top qemu-kvm
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
PVE/QemuServer.pm | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 140 insertions(+), 1 deletion(-)
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 81cc682..3df3f57 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -31,6 +31,25 @@ use Time::HiRes qw(gettimeofday);
my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
+# then we will consider the host to be under memory pressure
+my $pressure_threshold = 0.20;
+
+# If pressure threshold drops below this level, then the pressure
+# is critical and more aggressive ballooning will be employed.
+my $pressure_critical = 0.05;
+
+# This is the minimum percentage of free memory that an unconstrained
+# guest would like to maintain
+my $min_guest_free_percent = 0.20;
+
+# Don't change a guest's memory by more than this percent of total memory
+my $max_balloon_change_percent = 0.5;
+
+# Only ballooning operations that change the balloon by this percentage
+# of current guest memory should be undertaken to avoid overhead
+my $min_balloon_change_percent = 0.0025;
+
+
# Note about locking: we use flock on the config file protect
# against concurent actions.
# Aditionaly, we have a 'lock' setting in the config file. This
@@ -1966,6 +1985,9 @@ sub vmstatus {
$d->{diskread} = 0;
$d->{diskwrite} = 0;
+ $d->{freemem} = undef;
+ $d->{balloon} = $conf->{balloon} ?($conf->{balloon} * 1024 *1024) : undef;
+
$res->{$vmid} = $d;
}
@@ -2042,10 +2064,28 @@ sub vmstatus {
$res->{$vmid}->{diskwrite} = $totalwrbytes;
};
+ my $freememcb = sub {
+ my ($vmid, $resp) = @_;
+ my $value = $resp->{'return'} || 0;
+ $res->{$vmid}->{freemem} = $value;
+ };
+
+ my $totalmemcb = sub {
+ my ($vmid, $resp) = @_;
+ my $value = $resp->{'return'} || 0;
+ $res->{$vmid}->{mem} = $value;
+ };
+
my $statuscb = sub {
my ($vmid, $resp) = @_;
$qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
+ if( $res->{$vmid}->{balloon}){
+ $qmpclient->queue_cmd($vmid, undef, 'qom-set',path=> "machine/peripheral/balloon0", property => "stats-polling-interval", value => 10);
+ $qmpclient->queue_cmd($vmid, $freememcb, 'qom-get',path=> "machine/peripheral/balloon0", property => "stat-free-memory");
+ $qmpclient->queue_cmd($vmid, $totalmemcb, 'qom-get',path=> "machine/peripheral/balloon0", property => "stat-total-memory");
+ }
+
my $status = 'unknown';
if (!defined($status = $resp->{'return'}->{status})) {
warn "unable to get VM status\n";
@@ -2068,9 +2108,109 @@ sub vmstatus {
$res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
}
+ #auto-balloning
+ my $hostmeminfo = PVE::ProcFSTools::read_meminfo();
+ my $hostfreemem = $hostmeminfo->{memtotal} - $hostmeminfo->{memused};
+ my $host_free_percent = ($hostfreemem / $hostmeminfo->{memtotal});
+
+ warn "host free:".$hostfreemem." total:".$hostmeminfo->{memtotal}."\n";
+
+ foreach my $vmid (keys %$list) {
+ if($res->{$vmid}->{pid} && $res->{$vmid}->{balloon} && $res->{$vmid}->{freemem}){
+ warn "vm $vmid: mem:".$res->{$vmid}->{mem}. " maxmem:".$res->{$vmid}->{maxmem} ." freemem:".$res->{$vmid}->{freemem}. " min_mem: ".$res->{$vmid}->{balloon}."\n";
+ if ($host_free_percent < $pressure_threshold){
+ balloon_shrink_guest($vmid, $host_free_percent, $res->{$vmid}->{mem}, $res->{$vmid}->{maxmem}, $res->{$vmid}->{freemem}, $res->{$vmid}->{balloon});
+ }else{
+ balloon_grow_guest($vmid, $host_free_percent, $res->{$vmid}->{mem}, $res->{$vmid}->{maxmem}, $res->{$vmid}->{freemem}, $res->{$vmid}->{balloon});
+ }
+ }
+
+ }
+
return $res;
}
+sub balloon_shrink_guest {
+ my ($vmid, $host_free_percent, $balloon_cur, $balloon_max, $freemem, $min_mem) = @_;
+
+ my $guest_free_percent = undef;
+ # Determine the degree of host memory pressure
+ if ($host_free_percent <= $pressure_critical){
+ # Pressure is critical:
+ # Force guest to swap by making free memory negative
+ $guest_free_percent = (-0.05 + $host_free_percent);
+ }else{
+ # Normal pressure situation
+ # Scale the guest free memory back according to host pressure
+ $guest_free_percent = ($min_guest_free_percent * ($host_free_percent / $pressure_threshold));
+ }
+
+ # Given current conditions, determine the ideal guest memory size
+# $guest_used_mem = $guest.StatAvg "balloon_cur") - (guest.StatAvg "mem_unused");
+
+ my $guest_used_mem = $balloon_cur - $freemem; # do we need average ?
+
+ my $balloon_min = $guest_used_mem + ($guest_free_percent * $balloon_cur);
+
+ $balloon_min = $min_mem if $balloon_min < $min_mem;
+
+ # But do not change it too fast
+ my $balloon_size = $balloon_cur * (1 - $max_balloon_change_percent);
+
+ if($balloon_size < $balloon_min){
+ $balloon_size = $balloon_min;
+ }
+ # Set the new target for the BalloonController. Only set it if the
+ # value makes sense and is a large enough change to be worth it.
+ if (($balloon_size <= $balloon_cur) && (balloon_change_big_enough ($balloon_cur, $balloon_size))){
+ vm_balloonset($vmid, floor($balloon_size/1024/1024));
+ warn "$vmid shrink from $balloon_cur to $balloon_size\n";
+
+ }
+}
+
+sub balloon_grow_guest {
+ my ($vmid, $host_free_percent, $balloon_cur, $balloon_max, $freemem, $min_mem) = @_;
+
+ # There is only work to do if the guest is ballooned
+ if ($balloon_cur < $balloon_max) {
+ # Minimally, increase so the guest has its desired free memory
+# my $guest_used_mem = $guest.StatAvg "balloon_cur") - $guest.StatAvg "mem_unused";
+
+ my $guest_used_mem = $balloon_cur - $freemem; #do we need average ?
+
+ my $balloon_min = $guest_used_mem + ($min_guest_free_percent * $balloon_max);
+
+ $balloon_min = $min_mem if $balloon_min < $min_mem;
+
+ # Otherwise, increase according to the max balloon change
+ my $balloon_size = $balloon_cur * (1 + $max_balloon_change_percent);
+
+ # Determine the new target for the BalloonController. Only set
+ # if the value is a large enough for the change to be worth it.
+ if ($balloon_size > $balloon_max){
+ $balloon_size = $balloon_max;
+ }elsif ($balloon_size < $balloon_min){
+ $balloon_size = $balloon_min;
+ }
+
+ if (balloon_change_big_enough($balloon_cur, $balloon_size)){
+ vm_balloonset($vmid, floor($balloon_size/1024/1024));
+ warn "$vmid grow from $balloon_cur to $balloon_size\n";
+
+ }
+ }
+}
+
+sub balloon_change_big_enough {
+ my ($balloon_cur, $new_val) = @_;
+
+ if (abs($new_val - $balloon_cur) > ($min_balloon_change_percent * $balloon_cur)){
+ return 1;
+ }
+ return undef;
+}
+
sub foreach_drive {
my ($conf, $func) = @_;
@@ -2960,7 +3100,6 @@ sub vm_start {
}
vm_balloonset($vmid, $conf->{balloon}) if $conf->{balloon};
-
});
}
--
1.7.10.4
More information about the pve-devel
mailing list