]>
Commit | Line | Data |
---|---|---|
53f13052 DM |
1 | package PVE::AutoBalloon; |
2 | ||
3 | use warnings; | |
4 | use strict; | |
5 | ||
6 | sub compute_alg1 { | |
7 | my ($vmstatus, $goal, $maxchange, $debug) = @_; | |
8 | ||
9 | my $log = sub { print @_ if $debug; }; | |
10 | ||
11 | my $change_func = sub { | |
12 | my ($res, $idlist, $bytes) = @_; | |
13 | ||
14 | my $rest = $bytes; | |
15 | my $repeat = 1; | |
16 | my $done_hash = {}; | |
17 | my $progress = 1; | |
18 | ||
19 | while ($rest && $repeat && $progress) { | |
20 | $repeat = 0; | |
21 | $progress = 0; | |
22 | ||
23 | my $shares_total = 0; | |
24 | my $alloc_old = 0; | |
25 | ||
26 | foreach my $vmid (@$idlist) { | |
27 | next if defined($done_hash->{$vmid}); | |
28 | my $d = $vmstatus->{$vmid}; | |
29 | my $balloon = defined($res->{$vmid}) ? $res->{$vmid} : $d->{balloon}; | |
30 | $alloc_old += $balloon - $d->{balloon_min}; | |
31 | $shares_total += $d->{shares} || 1000; | |
32 | } | |
33 | ||
34 | my $changes = 0; | |
35 | ||
36 | my $alloc_new = $alloc_old + $rest; | |
37 | ||
38 | &$log("shares_total: $shares_total $alloc_new\n"); | |
39 | ||
40 | foreach my $vmid (@$idlist) { | |
41 | next if defined($done_hash->{$vmid}); | |
42 | my $d = $vmstatus->{$vmid}; | |
43 | my $shares = $d->{shares} || 1000; | |
44 | my $desired = $d->{balloon_min} + int(($alloc_new/$shares_total)*$shares); | |
45 | ||
46 | if ($desired > $d->{maxmem}) { | |
47 | $desired = $d->{maxmem}; | |
48 | $repeat = 1; | |
49 | } elsif ($desired < $d->{balloon_min}) { | |
50 | $desired = $d->{balloon_min}; | |
51 | $repeat = 1; | |
52 | } | |
53 | ||
54 | my ($new, $balloon); | |
55 | if (($bytes > 0) && ($desired - $d->{balloon}) > 0) { # grow | |
56 | $new = $d->{balloon} + $maxchange; | |
57 | $balloon = $new > $desired ? $desired : $new; | |
58 | } elsif (($desired - $d->{balloon}) < 0) { # shrink | |
59 | $new = $d->{balloon} - $maxchange; | |
60 | $balloon = $new > $desired ? $new : $desired; | |
61 | } else { | |
62 | $done_hash->{$vmid} = 1; | |
63 | next; | |
64 | } | |
65 | ||
66 | my $diff = $balloon - $d->{balloon}; | |
67 | if ($diff != 0) { | |
68 | my $oldballoon = defined($res->{$vmid}) ? $res->{$vmid} : $d->{balloon}; | |
69 | $res->{$vmid} = $balloon; | |
70 | my $change = $balloon - $oldballoon; | |
71 | if ($change != 0) { | |
72 | $changes += $change; | |
73 | my $absdiff = $diff > 0 ? $diff : -$diff; | |
74 | $progress += $absdiff; | |
75 | $repeat = 1; | |
76 | } | |
77 | &$log("change request for $vmid ($balloon, $diff, $desired, $new, $changes, $progress)\n"); | |
78 | } | |
79 | } | |
80 | ||
81 | $rest -= $changes; | |
82 | } | |
83 | ||
84 | return $rest; | |
85 | }; | |
86 | ||
87 | ||
88 | my $idlist = []; # list of VMs with working balloon river | |
89 | my $idlist1 = []; # list of VMs with memory pressure | |
90 | my $idlist2 = []; # list of VMs with enough free memory | |
91 | ||
92 | foreach my $vmid (keys %$vmstatus) { | |
93 | my $d = $vmstatus->{$vmid}; | |
94 | next if !$d->{balloon}; # skip if balloon driver not running | |
95 | next if !$d->{balloon_min}; # skip if balloon value not set in config | |
1fa4f911 | 96 | next if $d->{lock} && $d->{lock} eq 'migrate'; |
c1bc34a3 DM |
97 | next if defined($d->{shares}) && |
98 | ($d->{shares} == 0); # skip if shares set to zero | |
53f13052 DM |
99 | |
100 | push @$idlist, $vmid; | |
101 | ||
102 | if ($d->{freemem} && | |
103 | ($d->{freemem} > $d->{balloon_min}*0.25) && | |
104 | ($d->{balloon} >= $d->{balloon_min})) { | |
105 | push @$idlist2, $vmid; | |
106 | &$log("idlist2 $vmid $d->{balloon}, $d->{balloon_min}, $d->{freemem}\n"); | |
107 | } else { | |
108 | push @$idlist1, $vmid; | |
bca6fe1d | 109 | &$log("idlist1 $vmid $d->{balloon}, $d->{balloon_min}\n"); |
53f13052 DM |
110 | } |
111 | } | |
112 | ||
113 | my $res = {}; | |
114 | ||
115 | if ($goal > 10*1024*1024) { | |
116 | &$log("grow request start $goal\n"); | |
117 | # priorize VMs with memory pressure | |
118 | my $rest = &$change_func($res, $idlist1, $goal); | |
119 | if ($rest >= $goal) { # no progress ==> consider all VMs | |
120 | &$log("grow request loop $rest\n"); | |
121 | $rest = &$change_func($res, $idlist, $rest); | |
122 | } | |
123 | &$log("grow request end $rest\n"); | |
124 | ||
125 | } elsif ($goal < -10*1024*1024) { | |
126 | &$log("shrink request $goal\n"); | |
127 | # priorize VMs with enough free memory | |
128 | my $rest = &$change_func($res, $idlist2, $goal); | |
129 | if ($rest <= $goal) { # no progress ==> consider all VMs | |
130 | &$log("shrink request loop $rest\n"); | |
131 | $rest = &$change_func($res, $idlist, $rest); | |
132 | } | |
133 | &$log("shrink request end $rest\n"); | |
134 | } else { | |
135 | &$log("do nothing\n"); | |
136 | # do nothing - requested change to small | |
137 | } | |
138 | ||
139 | foreach my $vmid (@$idlist) { | |
140 | next if !$res->{$vmid}; | |
141 | my $d = $vmstatus->{$vmid}; | |
142 | my $diff = int($res->{$vmid} - $d->{balloon}); | |
143 | my $absdiff = $diff < 0 ? -$diff : $diff; | |
144 | &$log("BALLOON $vmid to $res->{$vmid} ($diff)\n"); | |
145 | } | |
146 | return $res; | |
147 | } | |
148 | ||
149 | 1; |