Skip to content

Commit 1d9400d

Browse files
committed
Wait for memory by transfer speed
Fixes: QubesOS/qubes-issues#10143 For: QubesOS/qubes-issues#1512
1 parent 5140b97 commit 1d9400d

File tree

2 files changed

+65
-13
lines changed

2 files changed

+65
-13
lines changed

qubes/qmemman/systemstate.py

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#: number of free memory bytes expected to get during CHECK_PERIOD_S
4646
#: seconds
4747
CHECK_DELTA = CHECK_PERIOD_S * CHECK_MB_S * 1024 * 1024
48+
LAST_SECOND = max(1, int(1 / BALLOON_DELAY))
4849

4950

5051
class SystemState:
@@ -283,42 +284,92 @@ def do_balloon_dom(self, dom_memset: dict) -> bool:
283284
for _, dom in dom_dict.items():
284285
dom.no_progress = False
285286

287+
mem_set_threshold = 1.1
286288
succeeded = []
287289
memset_reqs = {}
288290
for domid, memset in dom_memset.items():
291+
dom = dom_dict[domid]
289292
if memset == 0:
290-
# Domain hasn't meminfo back to the server, it is still at the
291-
# initial amount. pref_mem can't be calculated yet.
292-
if dom_dict[domid].mem_used is None:
293+
# Domain hasn't sent meminfo back to the server, it is still at
294+
# the initial amount. pref_mem can't be calculated yet.
295+
if dom.mem_used is None:
296+
self.log.info(
297+
"mem requested for dom '%s' is 0 but meminfo was not "
298+
+ "reported back, skipping ballooning",
299+
domid,
300+
)
293301
succeeded.append(domid)
294302
continue
295-
mem_pref = qubes.qmemman.algo.pref_mem(dom_dict[domid])
303+
mem_pref = qubes.qmemman.algo.pref_mem(dom)
296304
memset_reqs[domid] = mem_pref
297-
self.log.debug(
298-
"mem for dom '%s' is 0, using its pref '%s'",
305+
diff = round(getattr(dom, "mem_actual", 0) / mem_pref, 2)
306+
self.log.info(
307+
"mem requested for dom '%s' is 0, using its pref '%s' while"
308+
+ " actual mem is '%s' (%sx)",
299309
domid,
300310
mem_pref,
311+
dom.mem_actual,
312+
diff,
301313
)
302314
else:
303315
memset_reqs[domid] = memset
316+
diff = round(dom.mem_actual / memset, 2)
317+
self.log.info(
318+
"mem for dom '%s' is '%s' while actual mem is '%s' (%sx)",
319+
domid,
320+
memset,
321+
dom.mem_actual,
322+
diff,
323+
)
304324

325+
actual_mem_ring: dict[int, list[int]] = {}
305326
while True:
306-
self.log.debug("niter={:d}".format(niter))
307327
self.refresh_mem_actual(domid_list)
308328
for domid, dom in dom_dict.items():
329+
if domid in succeeded:
330+
continue
309331
assert isinstance(dom.mem_actual, int)
310-
if (
311-
domid not in succeeded
312-
and dom.mem_actual / memset_reqs[domid] < 1.1
313-
):
332+
if niter > 0 and niter % 10 == 0 and dom_memset[domid] == 0:
333+
mem_pref = qubes.qmemman.algo.pref_mem(dom)
334+
if mem_pref != memset_reqs[domid]:
335+
memset_reqs[domid] = mem_pref
336+
self.log.info("adjusted pref to '%s'", mem_pref)
337+
diff = round(dom.mem_actual / memset_reqs[domid], 2)
338+
if domid not in succeeded and diff <= mem_set_threshold:
314339
succeeded.append(domid)
340+
self.log.info(
341+
"round '%d' dom '%s' has actual mem of %s (%sx)",
342+
niter,
343+
dom.domid,
344+
dom.mem_actual,
345+
diff,
346+
)
315347
if all(dom in succeeded for dom in domid_list):
316348
return True
317-
if niter >= CHECK_PERIOD:
349+
slow = []
350+
for domid, dom in dom_dict.items():
351+
if domid in succeeded:
352+
continue
353+
assert isinstance(dom.mem_actual, int)
354+
actual_mem_ring.setdefault(domid, []).append(dom.mem_actual)
355+
if niter >= CHECK_PERIOD:
356+
ring = actual_mem_ring[domid]
357+
transfer_speed_mib = int(
358+
(ring[-LAST_SECOND] - ring[-1]) / 1024**2
359+
)
360+
if transfer_speed_mib < CHECK_MB_S:
361+
self.log.warning(
362+
"slow transfer speed of %sMiB/s on the last second",
363+
transfer_speed_mib,
364+
)
365+
slow.append(domid)
366+
if any(dom in slow for dom in domid_list):
318367
return False
319368
for domid, memset in memset_reqs.items():
369+
if domid in succeeded:
370+
continue
320371
self.mem_set(domid, memset)
321-
self.log.debug("sleeping for {} s".format(BALLOON_DELAY))
372+
self.log.debug("sleeping for {}s".format(BALLOON_DELAY))
322373
time.sleep(BALLOON_DELAY)
323374
niter += 1
324375

qubes/vm/qubesvm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,6 +2085,7 @@ def set_mem(self):
20852085
if not qmemman_present or self.maxmem == 0:
20862086
return None
20872087

2088+
self.log.info("Setting qube memory to pref mem")
20882089
qmemman_client = qubes.qmemman.client.QMemmanClient()
20892090
try:
20902091
result = qmemman_client.set_mem({self.xid: 0})

0 commit comments

Comments
 (0)