[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