2020
2121import logging
2222
23- # This are only defaults - can be overridden by QMemmanServer with values from
24- # config file
23+ # These defaults can be overridden by QMemmanServer with values from config
24+ # file.
2525CACHE_FACTOR = 1.3
2626MIN_PREFMEM = 200 * 1024 * 1024
2727DOM0_MEM_BOOST = 350 * 1024 * 1024
28+ # REQ_SAFETY_NET_FACTOR is a bit greater that 1. So that if the domain
29+ # yields a bit less than requested, due to e.g. rounding errors, we will not
30+ # get stuck. The surplus will return to the VM during "balance" call.
2831REQ_SAFETY_NET_FACTOR = 1.05
2932
3033log = logging .getLogger ("qmemman.daemon.algo" )
@@ -40,188 +43,179 @@ def sanitize_and_parse_meminfo(untrusted_meminfo):
4043 return int (untrusted_meminfo ) * 1024
4144
4245
43- # Called when a domain updates its 'meminfo' xenstore key.
4446def refresh_meminfo_for_domain (domain , untrusted_xenstore_key ):
47+ """
48+ Called when a domain updates its 'meminfo' xenstore key.
49+ """
4550 domain .mem_used = sanitize_and_parse_meminfo (untrusted_xenstore_key )
4651
4752
48- def prefmem (domain ):
53+ def pref_mem (domain ):
4954 # As dom0 must have large cache for vbds, give it a special boost.
5055 mem_used = domain .mem_used * CACHE_FACTOR
5156 if domain .domid == "0" :
5257 mem_used += DOM0_MEM_BOOST
53- return int (min (mem_used , domain .memory_maximum ))
54- return int (max (min (mem_used , domain .memory_maximum ), MIN_PREFMEM ))
58+ return int (min (mem_used , domain .mem_max ))
59+ return int (max (min (mem_used , domain .mem_max ), MIN_PREFMEM ))
5560
5661
57- def memory_needed (domain ):
58- # Do not change. In balance(), "distribute total_available_memory
59- # proportionally to mempref " relies on this exact formula.
60- ret = prefmem (domain ) - domain .memory_actual
62+ def needed_mem (domain ):
63+ # Do not change. In balance(), "distribute total_available_mem
64+ # proportionally to pref_mem " relies on this exact formula.
65+ ret = pref_mem (domain ) - domain .mem_actual
6166 return ret
6267
6368
64- # Prepare list of (domain, memory_target ) pairs that need to be passed to "xm
65- # memset" equivalent in order to obtain "memsize ".
69+ # Prepare list of (domain, mem_target ) pairs that need to be passed to "xm
70+ # memset" equivalent in order to obtain "mem_size ".
6671# Returns empty list when the request cannot be satisfied.
67- def balloon (memsize , domain_dictionary ):
72+ def balloon (mem_size , dom_dict ):
6873 log .debug (
69- "balloon(memsize={!r}, domain_dictionary={!r})" .format (
70- memsize , domain_dictionary
71- )
74+ "balloon(mem_size={!r}, dom_dict={!r})" .format (mem_size , dom_dict )
7275 )
7376 donors = []
7477 request = []
7578 available = 0
76- for domid , dom in domain_dictionary .items ():
79+ for domid , dom in dom_dict .items ():
7780 if dom .mem_used is None or dom .no_progress :
7881 continue
79- need = memory_needed (dom )
82+ need = needed_mem (dom )
8083 if need < 0 :
8184 log .info (
8285 "balloon: dom {} has actual memory {}" .format (
83- domid , dom .memory_actual
86+ domid , dom .mem_actual
8487 )
8588 )
8689 donors .append ((domid , - need ))
8790 available -= need
8891
89- log .info ("req={} avail={} donors={!r}" .format (memsize , available , donors ))
92+ log .info ("req={} avail={} donors={!r}" .format (mem_size , available , donors ))
9093
91- if available < memsize :
94+ if available < mem_size :
9295 return []
93- scale = 1.0 * memsize / available
96+ scale = 1.0 * mem_size / available
9497 for donors_iter in donors :
95- dom_id , mem = donors_iter
96- memborrowed = mem * scale * REQ_SAFETY_NET_FACTOR
97- log .info ("borrow {} from {}" .format (memborrowed , dom_id ))
98- memtarget = int (domain_dictionary [ dom_id ]. memory_actual - memborrowed )
99- request .append ((dom_id , memtarget ))
98+ domid , mem = donors_iter
99+ mem_borrowed = mem * scale * REQ_SAFETY_NET_FACTOR
100+ log .info ("borrow {} from {}" .format (mem_borrowed , domid ))
101+ mem_target = int (dom_dict [ domid ]. mem_actual - mem_borrowed )
102+ request .append ((domid , mem_target ))
100103 return request
101104
102105
103- # REQ_SAFETY_NET_FACTOR is a bit greater that 1. So that if the domain
104- # yields a bit less than requested, due to e.g. rounding errors, we will not
105- # get stuck. The surplus will return to the VM during "balance" call.
106-
107-
108- # Redistribute positive "total_available_memory" of memory between domains,
109- # proportionally to prefmem.
110- def balance_when_enough_memory (
111- domain_dictionary , xen_free_memory , total_mem_pref , total_available_memory
106+ # Redistribute positive "total_available_mem" of memory between domains,
107+ # proportionally to pref_mem.
108+ def balance_when_enough_mem (
109+ dom_dict , xen_free_mem , total_mem_pref , total_available_mem
112110):
113111 log .info (
114- "balance_when_enough_memory(xen_free_memory ={!r}, "
115- "total_mem_pref={!r}, total_available_memory ={!r})" .format (
116- xen_free_memory , total_mem_pref , total_available_memory
112+ "balance_when_enough_mem(xen_free_mem ={!r}, "
113+ "total_mem_pref={!r}, total_available_mem ={!r})" .format (
114+ xen_free_mem , total_mem_pref , total_available_mem
117115 )
118116 )
119117
120- target_memory = {}
118+ target_mem = {}
121119 # Memory not assigned because of static max.
122- left_memory = 0
120+ mem_left = 0
123121 acceptors_count = 0
124- for domid , dom in domain_dictionary .items ():
122+ for domid , dom in dom_dict .items ():
125123 if dom .mem_used is None or dom .no_progress :
126124 continue
127- # Distribute total_available_memory proportionally to mempref .
128- scale = 1.0 * prefmem (dom ) / total_mem_pref
129- target_nonint = prefmem (dom ) + scale * total_available_memory
125+ # Distribute total_available_mem proportionally to pref_mem .
126+ scale = 1.0 * pref_mem (dom ) / total_mem_pref
127+ target_nonint = pref_mem (dom ) + scale * total_available_mem
130128 # Prevent rounding errors.
131129 target = int (0.999 * target_nonint )
132130 # Do not try to give more memory than static max.
133- if target > dom .memory_maximum :
134- left_memory += target - dom .memory_maximum
135- target = dom .memory_maximum
131+ if target > dom .mem_max :
132+ mem_left += target - dom .mem_max
133+ target = dom .mem_max
136134 else :
137135 # Count domains which can accept more memory.
138136 acceptors_count += 1
139- target_memory [domid ] = target
137+ target_mem [domid ] = target
140138 # Distribute left memory across all acceptors.
141- while left_memory > 0 and acceptors_count > 0 :
139+ while mem_left > 0 and acceptors_count > 0 :
142140 log .info (
143- "left_memory={} acceptors_count={}" .format (
144- left_memory , acceptors_count
145- )
141+ "mem_left={} acceptors_count={}" .format (mem_left , acceptors_count )
146142 )
147143
148- new_left_memory = 0
144+ new_mem_left = 0
149145 new_acceptors_count = acceptors_count
150- for domid , target in target_memory .items ():
151- dom = domain_dictionary [domid ]
152- if target < dom .memory_maximum :
153- memory_bonus = int (0.999 * (left_memory / acceptors_count ))
154- if target + memory_bonus >= dom .memory_maximum :
155- new_left_memory += (
156- target + memory_bonus - dom .memory_maximum
157- )
158- target = dom .memory_maximum
146+ for domid , target in target_mem .items ():
147+ dom = dom_dict [domid ]
148+ if target < dom .mem_max :
149+ mem_bonus = int (0.999 * (mem_left / acceptors_count ))
150+ if target + mem_bonus >= dom .mem_max :
151+ new_mem_left += target + mem_bonus - dom .mem_max
152+ target = dom .mem_max
159153 new_acceptors_count -= 1
160154 else :
161- target += memory_bonus
162- target_memory [domid ] = target
163- left_memory = new_left_memory
155+ target += mem_bonus
156+ target_mem [domid ] = target
157+ mem_left = new_mem_left
164158 acceptors_count = new_acceptors_count
165- # Split target_memory dictionary to donors and acceptors. This is needed to
159+ # Split target_mem dictionary to donors and acceptors. This is needed to
166160 # first get memory from donors and only then give it to acceptors.
167161 donors_rq = []
168162 acceptors_rq = []
169- for domid , target in target_memory .items ():
170- dom = domain_dictionary [domid ]
171- if target < dom .memory_actual :
163+ for domid , target in target_mem .items ():
164+ dom = dom_dict [domid ]
165+ if target < dom .mem_actual :
172166 donors_rq .append ((domid , target ))
173167 else :
174168 acceptors_rq .append ((domid , target ))
175169 return donors_rq + acceptors_rq
176170
177171
178- # When not enough mem to make everyone be above prefmem , make donors be at
179- # prefmem , and redistribute anything left between acceptors.
180- def balance_when_low_on_memory (
181- domain_dictionary ,
182- xen_free_memory ,
172+ # When not enough mem to make everyone be above pref_mem , make donors be at
173+ # pref_mem , and redistribute anything left between acceptors.
174+ def balance_when_low_on_mem (
175+ dom_dict ,
176+ xen_free_mem ,
183177 total_mem_pref_acceptors ,
184178 donors ,
185179 acceptors ,
186180):
187181 log .info (
188- "balance_when_low_on_memory(xen_free_memory ={!r}, "
182+ "balance_when_low_on_mem(xen_free_mem ={!r}, "
189183 "total_mem_pref_acceptors={!r}, donors={!r}, acceptors={!r})" .format (
190- xen_free_memory , total_mem_pref_acceptors , donors , acceptors
184+ xen_free_mem , total_mem_pref_acceptors , donors , acceptors
191185 )
192186 )
193187 donors_rq = []
194188 acceptors_rq = []
195- squeezed_mem = xen_free_memory
189+ squeezed_mem = xen_free_mem
196190 for domid in donors :
197- dom = domain_dictionary [domid ]
198- avail = - memory_needed (dom )
191+ dom = dom_dict [domid ]
192+ avail = - needed_mem (dom )
199193 if avail < 10 * 1024 * 1024 :
200- # Probably we have already tried making it exactly at prefmem , give
194+ # Probably we have already tried making it exactly at pref_mem , give
201195 # up.
202196 continue
203197 squeezed_mem -= avail
204- donors_rq .append ((domid , prefmem (dom )))
198+ donors_rq .append ((domid , pref_mem (dom )))
205199 # The below condition can happen if initially xen free memory is below 50M.
206200 if squeezed_mem < 0 :
207201 return donors_rq
208202 for domid in acceptors :
209- dom = domain_dictionary [domid ]
210- scale = 1.0 * prefmem (dom ) / total_mem_pref_acceptors
211- target_nonint = dom .memory_actual + scale * squeezed_mem
203+ dom = dom_dict [domid ]
204+ scale = 1.0 * pref_mem (dom ) / total_mem_pref_acceptors
205+ target_nonint = dom .mem_actual + scale * squeezed_mem
212206 # Do not try to give more memory than static max.
213- target = min (int (0.999 * target_nonint ), dom .memory_maximum )
207+ target = min (int (0.999 * target_nonint ), dom .mem_max )
214208 acceptors_rq .append ((domid , target ))
215209 return donors_rq + acceptors_rq
216210
217211
218212# Get memory information.
219213# Called before and after domain balances.
220214# Return a dictionary of various memory data points.
221- def memory_info ( xen_free_memory , domain_dictionary ):
215+ def mem_info ( xen_free_mem , dom_dict ):
222216 log .debug (
223- "memory_info(xen_free_memory ={!r}, domain_dictionary ={!r})" .format (
224- xen_free_memory , domain_dictionary
217+ "mem_info(xen_free_mem ={!r}, dom_dict ={!r})" .format (
218+ xen_free_mem , dom_dict
225219 )
226220 )
227221
@@ -230,7 +224,7 @@ def memory_info(xen_free_memory, domain_dictionary):
230224 # their preferred memory, and memory that can be taken from domains
231225 # (donors) that can provide memory. So, it can be negative when plenty of
232226 # memory.
233- total_memory_needed = 0
227+ total_needed_mem = 0
234228
235229 # Sum of memory preferences of all domains.
236230 total_mem_pref = 0
@@ -241,54 +235,54 @@ def memory_info(xen_free_memory, domain_dictionary):
241235 donors = []
242236 acceptors = []
243237 # Pass 1: compute the above "total" values.
244- for domid , dom in domain_dictionary .items ():
238+ for domid , dom in dom_dict .items ():
245239 if dom .mem_used is None or dom .no_progress :
246240 continue
247- need = memory_needed (dom )
248- if need < 0 or dom .memory_actual >= dom .memory_maximum :
241+ need = needed_mem (dom )
242+ if need < 0 or dom .mem_actual >= dom .mem_max :
249243 donors .append (domid )
250244 else :
251245 acceptors .append (domid )
252- total_mem_pref_acceptors += prefmem (dom )
253- total_memory_needed += need
254- total_mem_pref += prefmem (dom )
246+ total_mem_pref_acceptors += pref_mem (dom )
247+ total_needed_mem += need
248+ total_mem_pref += pref_mem (dom )
255249
256- total_available_memory = xen_free_memory - total_memory_needed
250+ total_available_mem = xen_free_mem - total_needed_mem
257251
258- mem_dictionary = {}
259- mem_dictionary [ "domain_dictionary " ] = domain_dictionary
260- mem_dictionary [ "total_available_memory " ] = total_available_memory
261- mem_dictionary [ "xen_free_memory " ] = xen_free_memory
262- mem_dictionary ["total_mem_pref" ] = total_mem_pref
263- mem_dictionary ["total_mem_pref_acceptors" ] = total_mem_pref_acceptors
264- mem_dictionary ["donors" ] = donors
265- mem_dictionary ["acceptors" ] = acceptors
266- return mem_dictionary
252+ mem_dict = {}
253+ mem_dict [ "dom_dict " ] = dom_dict
254+ mem_dict [ "total_available_mem " ] = total_available_mem
255+ mem_dict [ "xen_free_mem " ] = xen_free_mem
256+ mem_dict ["total_mem_pref" ] = total_mem_pref
257+ mem_dict ["total_mem_pref_acceptors" ] = total_mem_pref_acceptors
258+ mem_dict ["donors" ] = donors
259+ mem_dict ["acceptors" ] = acceptors
260+ return mem_dict
267261
268262
269263# Redistribute memory across domains.
270264# Called when one of domains update its 'meminfo' xenstore key.
271- # Return the list of (domain, memory_target ) pairs to be passed to "xm memset"
265+ # Return the list of (domain, mem_target ) pairs to be passed to "xm memset"
272266# equivalent
273- def balance (xen_free_memory , domain_dictionary ):
267+ def balance (xen_free_mem , dom_dict ):
274268 log .debug (
275- "balance(xen_free_memory ={!r}, domain_dictionary ={!r})" .format (
276- xen_free_memory , domain_dictionary
269+ "balance(xen_free_mem ={!r}, dom_dict ={!r})" .format (
270+ xen_free_mem , dom_dict
277271 )
278272 )
279- memory_dictionary = memory_info ( xen_free_memory , domain_dictionary )
280-
281- if memory_dictionary [ "total_available_memory " ] > 0 :
282- return balance_when_enough_memory (
283- memory_dictionary [ "domain_dictionary " ],
284- memory_dictionary [ "xen_free_memory " ],
285- memory_dictionary ["total_mem_pref" ],
286- memory_dictionary [ "total_available_memory " ],
273+ mem_dict = mem_info ( xen_free_mem , dom_dict )
274+
275+ if mem_dict [ "total_available_mem " ] > 0 :
276+ return balance_when_enough_mem (
277+ mem_dict [ "dom_dict " ],
278+ mem_dict [ "xen_free_mem " ],
279+ mem_dict ["total_mem_pref" ],
280+ mem_dict [ "total_available_mem " ],
287281 )
288- return balance_when_low_on_memory (
289- memory_dictionary [ "domain_dictionary " ],
290- memory_dictionary [ "xen_free_memory " ],
291- memory_dictionary ["total_mem_pref_acceptors" ],
292- memory_dictionary ["donors" ],
293- memory_dictionary ["acceptors" ],
282+ return balance_when_low_on_mem (
283+ mem_dict [ "dom_dict " ],
284+ mem_dict [ "xen_free_mem " ],
285+ mem_dict ["total_mem_pref_acceptors" ],
286+ mem_dict ["donors" ],
287+ mem_dict ["acceptors" ],
294288 )
0 commit comments