]> git.proxmox.com Git - pve-manager.git/blobdiff - bin/pvestatd
implement new auto balloon algorithm
[pve-manager.git] / bin / pvestatd
index b119696abf38c7880254c535f1390ad2696b6b74..d98660609f8de22de0846c52613e0e31fc27290d 100755 (executable)
@@ -6,7 +6,7 @@ use POSIX ":sys_wait_h";
 use Fcntl ':flock';
 use Getopt::Long;
 use Time::HiRes qw (gettimeofday);
-use PVE::Tools;
+use PVE::Tools qw(dir_glob_foreach file_read_firstline);
 use PVE::ProcFSTools;
 use Filesys::Df;
 use PVE::INotify;
@@ -15,6 +15,8 @@ use PVE::Storage;
 use PVE::QemuServer;
 use PVE::OpenVZ;
 use PVE::RPCEnvironment;
+use PVE::API2::Subscription;
+use PVE::AutoBalloon;
 
 $SIG{'__WARN__'} = sub {
     my $err = $@;
@@ -144,6 +146,9 @@ sub update_node_status {
 
     my $maxcpu = $cpuinfo->{cpus}; 
 
+    my $subinfo = PVE::INotify::read_file('subscription');
+    my $sublevel = $subinfo->{level} || '';
+
     # traffic from/to physical interface cards
     my $netin = 0;
     my $netout = 0;
@@ -162,7 +167,7 @@ sub update_node_status {
     # everything not free is considered to be used
     my $dused = $dinfo->{blocks} - $dinfo->{bfree};
 
-    my $data = "$uptime:$ctime:$avg1:$maxcpu:$stat->{cpu}:$stat->{wait}:" .
+    my $data = "$uptime:$sublevel:$ctime:$avg1:$maxcpu:$stat->{cpu}:$stat->{wait}:" .
        "$meminfo->{memtotal}:$meminfo->{memused}:" .
        "$meminfo->{swaptotal}:$meminfo->{swapused}:" .
        "$dinfo->{blocks}:$dused:$netin:$netout";
@@ -170,11 +175,54 @@ sub update_node_status {
     PVE::Cluster::broadcast_rrd("pve2-node/$nodename", $data);
 }
 
+sub auto_balloning {
+    my ($vmstatus) =  @_;
+
+    my $log = sub {
+       return if !$opt_debug;
+       print @_;
+    };
+
+    my $hostmeminfo = PVE::ProcFSTools::read_meminfo();
+
+    # to debug, run 'pvestatd -d' and set  memtotal here
+    #$hostmeminfo->{memtotal} = int(2*1024*1024*1024/0.8); # you can set this to test
+
+    my $hostfreemem = $hostmeminfo->{memtotal} - $hostmeminfo->{memused};
+
+    # we try to use about 80% host memory
+    # goal: we want to change memory usage by this amount (positive or negative)
+    my $goal = int($hostmeminfo->{memtotal}*0.8 - $hostmeminfo->{memused});
+
+    my $maxchange = 100*1024*1024;
+    my $res = PVE::AutoBalloon::compute_alg1($vmstatus, $goal, $maxchange);
+    &$log("host goal: $goal free: $hostfreemem total: $hostmeminfo->{memtotal}\n");
+
+    foreach my $vmid (keys %$vmstatus) {
+       next if !$res->{$vmid};
+       my $d = $vmstatus->{$vmid};
+       my $diff = int($res->{$vmid} - $d->{balloon});
+       my $absdiff = $diff < 0 ? -$diff : $diff;
+       if ($absdiff > 0) {
+           &$log("BALLOON $vmid to $res->{$vmid} ($diff)\n");
+           eval {
+               PVE::QemuServer::vm_mon_cmd($vmid, "balloon", 
+                                           value => int($res->{$vmid}));
+           };
+           warn $@ if $@;
+       }
+    }
+}
+
 sub update_qemu_status {
 
     my $ctime = time();
 
-    my $vmstatus = PVE::QemuServer::vmstatus();
+    my $vmstatus = PVE::QemuServer::vmstatus(undef, 1);
+
+    eval { auto_balloning($vmstatus); };
+    syslog('err', "auto ballooning error: $@") if $@;
 
     foreach my $vmid (keys %$vmstatus) {
        my $d = $vmstatus->{$vmid};
@@ -195,6 +243,45 @@ sub update_qemu_status {
     }
 }
 
+sub find_vzctl_console_pids {
+
+    my $res = {};
+
+    dir_glob_foreach('/proc', '\d+', sub {
+       my ($pid) = @_;
+
+       my $cmdline = file_read_firstline("/proc/$pid/cmdline");
+       return if !$cmdline;
+
+       my @args = split(/\0/, $cmdline);
+
+       # serach for vzctl console <vmid>
+       return if scalar(@args) != 3; 
+       return if $args[1] ne 'console';
+       return if $args[2] !~ m/^\d+$/;
+       return if $args[0] !~ m|^(/usr/sbin/)?vzctl$|;
+       
+       my $vmid = $args[2];
+       
+       push @{$res->{$vmid}}, $pid;
+    });
+
+    return $res;
+}
+sub remove_stale_openvz_consoles {
+
+    my $vmstatus = PVE::OpenVZ::vmstatus();
+    my $pidhash = find_vzctl_console_pids();
+
+    foreach my $vmid (keys %$pidhash) {
+       next if defined($vmstatus->{$vmid});
+       syslog('info', "remove stale vzctl console for CT $vmid");
+       foreach my $pid (@{$pidhash->{$vmid}}) {
+           kill(9, $pid);
+       }
+    }
+}
+
 sub update_openvz_status {
 
     my $ctime = time();
@@ -277,6 +364,12 @@ sub update_status {
     };
     $err = $@;
     syslog('err', "storage status update error: $err") if $err;
+
+    eval {
+       remove_stale_openvz_consoles();
+    };
+    $err = $@;
+    syslog('err', "openvz console cleanup error: $err") if $err;
 }
 
 my $next_update = 0;
@@ -303,6 +396,8 @@ sub restart_server {
     exit (-1); # never reached?
 }
 
+my $initial_memory_usage;
+
 for (;;) { # forever
 
     eval {
@@ -312,7 +407,7 @@ for (;;) { # forever
            my ($ccsec, $cusec) = gettimeofday ();
            eval {
                $reload_config = 0;
-               syslog('info', "start status update");
+               syslog('info', "start status update");
                PVE::Cluster::cfs_update();
                update_status();
            };
@@ -325,17 +420,23 @@ for (;;) { # forever
            my ($ccsec_end, $cusec_end) = gettimeofday ();
            my $cptime = ($ccsec_end-$ccsec) + ($cusec_end - $cusec)/1000000;
 
-           syslog('info', sprintf("status update finished (%.3f seconds)", $cptime));
+           syslog('info', sprintf("status update time (%.3f seconds)", $cptime))
+               if ($cptime > 5);
        }
 
        $cycle++;
 
        my $mem = PVE::ProcFSTools::read_memory_usage();
 
-       if ($mem->{resident} > (35*1024*1024)) {
-           syslog ('info', "restarting server after $cycle cycles to " .
-                   "reduce memory usage (free $mem->{resident} bytes)");
-           restart_server ();
+       if (!defined($initial_memory_usage) || ($cycle < 10)) {
+           $initial_memory_usage = $mem->{resident};
+       } else {
+           my $diff = $mem->{resident} - $initial_memory_usage;
+           if ($diff > 5*1024*1024) {
+               syslog ('info', "restarting server after $cycle cycles to " .
+                       "reduce memory usage (free $mem->{resident} ($diff) bytes)");
+               restart_server ();
+           }
        }
 
        my $wcount = 0;