37
37
CHECK_MB_S = 100
38
38
MIN_TOTAL_MEMORY_TRANSFER = 150 * 1024 * 1024
39
39
MIN_MEM_CHANGE_WHEN_UNDER_PREF = 15 * 1024 * 1024
40
+ #: number of loop iterations for CHECK_PERIOD_S seconds
41
+ CHECK_PERIOD = max (1 , int ((CHECK_PERIOD_S + 0.0 ) / BALLOON_DELAY ))
42
+ #: number of free memory bytes expected to get during CHECK_PERIOD_S
43
+ #: seconds
44
+ CHECK_DELTA = CHECK_PERIOD_S * CHECK_MB_S * 1024 * 1024
40
45
41
46
42
47
class SystemState :
@@ -116,11 +121,13 @@ def get_free_xen_mem(self) -> int:
116
121
)
117
122
return xen_free - assigned_but_unused
118
123
119
- # Refresh information on memory assigned to all domains
120
- def refresh_mem_actual (self ) -> None :
124
+ # Refresh information on memory assigned to all or specific domains
125
+ def refresh_mem_actual (self , domid_list : Optional [ list ] = None ) -> None :
121
126
for domain in self .xc .domain_getinfo ():
122
127
domid = str (domain ["domid" ])
123
128
if domid in self .dom_dict :
129
+ if domid_list and domid not in domid_list :
130
+ continue
124
131
dom = self .dom_dict [domid ]
125
132
# Real memory usage
126
133
dom .mem_current = domain ["mem_kb" ] * 1024
@@ -220,17 +227,12 @@ def do_balloon(self, mem_size) -> bool:
220
227
for _ , dom in self .dom_dict .items ():
221
228
dom .no_progress = False
222
229
223
- #: number of loop iterations for CHECK_PERIOD_S seconds
224
- check_period = max (1 , int ((CHECK_PERIOD_S + 0.0 ) / BALLOON_DELAY ))
225
- #: number of free memory bytes expected to get during CHECK_PERIOD_S
226
- #: seconds
227
- check_delta = CHECK_PERIOD_S * CHECK_MB_S * 1024 * 1024
228
230
#: helper array for holding free memory size, CHECK_PERIOD_S seconds
229
231
#: ago, at every loop iteration
230
- xenfree_ring = [0 ] * check_period
232
+ xenfree_ring = [0 ] * CHECK_PERIOD
231
233
232
234
while True :
233
- self .log .debug ("niter={:2d }" .format (niter ))
235
+ self .log .debug ("niter={:d }" .format (niter ))
234
236
self .refresh_mem_actual ()
235
237
xenfree = self .get_free_xen_mem ()
236
238
self .log .info ("xenfree={!r}" .format (xenfree ))
@@ -239,10 +241,10 @@ def do_balloon(self, mem_size) -> bool:
239
241
return True
240
242
# fail the request if over past CHECK_PERIOD_S seconds,
241
243
# we got less than CHECK_MB_S MB/s on average
242
- ring_slot = niter % check_period
244
+ ring_slot = niter % CHECK_PERIOD
243
245
if (
244
- niter >= check_period
245
- and xenfree < xenfree_ring [ring_slot ] + check_delta
246
+ niter >= CHECK_PERIOD
247
+ and xenfree < xenfree_ring [ring_slot ] + CHECK_DELTA
246
248
):
247
249
return False
248
250
xenfree_ring [ring_slot ] = xenfree
@@ -269,6 +271,56 @@ def do_balloon(self, mem_size) -> bool:
269
271
time .sleep (BALLOON_DELAY )
270
272
niter = niter + 1
271
273
274
+ def do_balloon_dom (self , dom_memset : dict ) -> bool :
275
+ self .log .info ("do_balloon_dom(dom_memset={!r})" .format (dom_memset ))
276
+ niter = 0
277
+ if not dom_memset :
278
+ return False
279
+
280
+ domid_list = list (dom_memset .keys ())
281
+ dom_dict = {
282
+ domid : state
283
+ for domid , state in self .dom_dict .items ()
284
+ if domid in domid_list
285
+ }
286
+
287
+ for _ , dom in dom_dict .items ():
288
+ dom .no_progress = False
289
+
290
+ memset_reqs = {}
291
+ for domid , memset in dom_memset .items ():
292
+ if memset == 0 :
293
+ mem_pref = qubes .qmemman .algo .pref_mem (dom_dict [domid ])
294
+ memset_reqs [domid ] = mem_pref
295
+ self .log .debug (
296
+ "mem for dom '%s' is 0, using its pref '%s'" ,
297
+ domid ,
298
+ mem_pref ,
299
+ )
300
+ else :
301
+ memset_reqs [domid ] = memset
302
+
303
+ succeeded = []
304
+ while True :
305
+ self .log .debug ("niter={:d}" .format (niter ))
306
+ self .refresh_mem_actual (domid_list )
307
+ for domid , dom in dom_dict .items ():
308
+ assert isinstance (dom .mem_actual , int )
309
+ if (
310
+ domid not in succeeded
311
+ and dom .mem_actual / memset_reqs [domid ] < 1.1
312
+ ):
313
+ succeeded .append (domid )
314
+ if all (dom in succeeded for dom in domid_list ):
315
+ return True
316
+ if niter >= CHECK_PERIOD :
317
+ return False
318
+ for domid , memset in memset_reqs .items ():
319
+ self .mem_set (domid , memset )
320
+ self .log .debug ("sleeping for {} s" .format (BALLOON_DELAY ))
321
+ time .sleep (BALLOON_DELAY )
322
+ niter += 1
323
+
272
324
def refresh_meminfo (self , domid , untrusted_meminfo_key ) -> None :
273
325
self .log .debug (
274
326
"refresh_meminfo(domid={}, untrusted_meminfo_key={!r})" .format (
0 commit comments