3737CHECK_MB_S = 100
3838MIN_TOTAL_MEMORY_TRANSFER = 150 * 1024 * 1024
3939MIN_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
4045
4146
4247class SystemState :
@@ -116,11 +121,11 @@ def get_free_xen_mem(self) -> int:
116121 )
117122 return xen_free - assigned_but_unused
118123
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 : list = None ) -> None :
121126 for domain in self .xc .domain_getinfo ():
122127 domid = str (domain ["domid" ])
123- if domid in self .dom_dict :
128+ if domid in domid_list and domid in self .dom_dict :
124129 dom = self .dom_dict [domid ]
125130 # Real memory usage
126131 dom .mem_current = domain ["mem_kb" ] * 1024
@@ -220,17 +225,12 @@ def do_balloon(self, mem_size) -> bool:
220225 for _ , dom in self .dom_dict .items ():
221226 dom .no_progress = False
222227
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
228228 #: helper array for holding free memory size, CHECK_PERIOD_S seconds
229229 #: ago, at every loop iteration
230- xenfree_ring = [0 ] * check_period
230+ xenfree_ring = [0 ] * CHECK_PERIOD
231231
232232 while True :
233- self .log .debug ("niter={:2d }" .format (niter ))
233+ self .log .debug ("niter={:d }" .format (niter ))
234234 self .refresh_mem_actual ()
235235 xenfree = self .get_free_xen_mem ()
236236 self .log .info ("xenfree={!r}" .format (xenfree ))
@@ -239,10 +239,10 @@ def do_balloon(self, mem_size) -> bool:
239239 return True
240240 # fail the request if over past CHECK_PERIOD_S seconds,
241241 # we got less than CHECK_MB_S MB/s on average
242- ring_slot = niter % check_period
242+ ring_slot = niter % CHECK_PERIOD
243243 if (
244- niter >= check_period
245- and xenfree < xenfree_ring [ring_slot ] + check_delta
244+ niter >= CHECK_PERIOD
245+ and xenfree < xenfree_ring [ring_slot ] + CHECK_DELTA
246246 ):
247247 return False
248248 xenfree_ring [ring_slot ] = xenfree
@@ -269,6 +269,56 @@ def do_balloon(self, mem_size) -> bool:
269269 time .sleep (BALLOON_DELAY )
270270 niter = niter + 1
271271
272+ def do_balloon_dom (self , dom_memset : dict ) -> bool :
273+ self .log .info ("do_balloon_dom(dom_memset={!r})" .format (dom_memset ))
274+ niter = 0
275+ if not dom_memset :
276+ return False
277+
278+ domid_list = list (dom_memset .keys ())
279+ dom_dict = {
280+ domid : state
281+ for domid , state in self .dom_dict .items ()
282+ if domid in domid_list
283+ }
284+
285+ for _ , dom in dom_dict .items ():
286+ dom .no_progress = False
287+
288+ memset_reqs = {}
289+ for domid , memset in dom_memset .items ():
290+ if memset == 0 :
291+ mem_pref = qubes .qmemman .algo .pref_mem (dom_dict [domid ])
292+ memset_reqs [domid ] = mem_pref
293+ self .log .debug (
294+ "original memset for dom '%s' is 0, using its pref_mem '%s'" ,
295+ domid ,
296+ mem_pref ,
297+ )
298+ else :
299+ memset_reqs [domid ] = memset
300+
301+ succeeded = []
302+ while True :
303+ self .log .debug ("niter={:d}" .format (niter ))
304+ self .refresh_mem_actual (domid_list )
305+ for domid , dom in dom_dict .items ():
306+ assert isinstance (dom .mem_actual , int )
307+ if (
308+ domid not in succeeded
309+ and dom .mem_actual / memset_reqs [domid ] < 1.1
310+ ):
311+ succeeded .append (domid )
312+ if all (dom in succeeded for dom in domid_list ):
313+ return True
314+ if niter >= CHECK_PERIOD :
315+ return False
316+ for domid , memset in memset_reqs :
317+ self .mem_set (domid , memset )
318+ self .log .debug ("sleeping for {} s" .format (BALLOON_DELAY ))
319+ time .sleep (BALLOON_DELAY )
320+ niter += 1
321+
272322 def refresh_meminfo (self , domid , untrusted_meminfo_key ) -> None :
273323 self .log .debug (
274324 "refresh_meminfo(domid={}, untrusted_meminfo_key={!r})" .format (
0 commit comments