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