Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 65 additions & 13 deletions qubes/qmemman/systemstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#: number of free memory bytes expected to get during CHECK_PERIOD_S
#: seconds
CHECK_DELTA = CHECK_PERIOD_S * CHECK_MB_S * 1024 * 1024
LAST_SECOND = max(1, int(1 / BALLOON_DELAY))


class SystemState:
Expand Down Expand Up @@ -283,42 +284,93 @@ def do_balloon_dom(self, dom_memset: dict) -> bool:
for _, dom in dom_dict.items():
dom.no_progress = False

mem_set_threshold = 1.1
succeeded = []
memset_reqs = {}
for domid, memset in dom_memset.items():
dom = dom_dict[domid]
if memset == 0:
# Domain hasn't meminfo back to the server, it is still at the
# initial amount. pref_mem can't be calculated yet.
if dom_dict[domid].mem_used is None:
# Domain hasn't sent meminfo back to the server, it is still at
# the initial amount. pref_mem can't be calculated yet.
if dom.mem_used is None:
self.log.info(
"mem requested for dom '%s' is 0 but meminfo was not "
+ "reported back, skipping ballooning",
domid,
)
succeeded.append(domid)
continue
mem_pref = qubes.qmemman.algo.pref_mem(dom_dict[domid])
mem_pref = qubes.qmemman.algo.pref_mem(dom)
memset_reqs[domid] = mem_pref
self.log.debug(
"mem for dom '%s' is 0, using its pref '%s'",
diff = round(getattr(dom, "mem_actual", 0) / mem_pref, 2)
self.log.info(
"mem requested for dom '%s' is 0, using its pref '%s' while"
+ " actual mem is '%s' (%sx)",
domid,
mem_pref,
dom.mem_actual,
diff,
)
else:
memset_reqs[domid] = memset
diff = round(dom.mem_actual / memset, 2)
self.log.info(
"mem requested for dom '%s' is '%s' while actual mem is "
+ "'%s' (%sx)",
domid,
memset,
dom.mem_actual,
diff,
)

actual_mem_ring: dict[str, list[int]] = {}
while True:
self.log.debug("niter={:d}".format(niter))
self.refresh_mem_actual(domid_list)
for domid, dom in dom_dict.items():
if domid in succeeded:
continue
assert isinstance(dom.mem_actual, int)
if (
domid not in succeeded
and dom.mem_actual / memset_reqs[domid] < 1.1
):
if niter > 0 and niter % 10 == 0 and dom_memset[domid] == 0:
mem_pref = qubes.qmemman.algo.pref_mem(dom)
if mem_pref != memset_reqs[domid]:
memset_reqs[domid] = mem_pref
self.log.info("adjusted pref to '%s'", mem_pref)
diff = round(dom.mem_actual / memset_reqs[domid], 2)
if domid not in succeeded and diff <= mem_set_threshold:
succeeded.append(domid)
self.log.debug(
"round '%d' dom '%s' has actual mem of %s (%sx)",
niter,
dom.domid,
dom.mem_actual,
diff,
)
if all(dom in succeeded for dom in domid_list):
return True
if niter >= CHECK_PERIOD:
slow = []
for domid, dom in dom_dict.items():
if domid in succeeded:
continue
assert isinstance(dom.mem_actual, int)
actual_mem_ring.setdefault(domid, []).append(dom.mem_actual)
if niter >= CHECK_PERIOD:
ring = actual_mem_ring[domid]
transfer_speed_mib = int(
(ring[-LAST_SECOND] - ring[-1]) / 1024**2
)
if transfer_speed_mib < CHECK_MB_S:
self.log.warning(
"slow transfer speed of %sMiB/s on the last second",
transfer_speed_mib,
)
slow.append(domid)
if any(dom in slow for dom in domid_list):
return False
for domid, memset in memset_reqs.items():
if domid in succeeded:
continue
self.mem_set(domid, memset)
self.log.debug("sleeping for {} s".format(BALLOON_DELAY))
self.log.debug("sleeping for {}s".format(BALLOON_DELAY))
time.sleep(BALLOON_DELAY)
niter += 1

Expand Down
1 change: 1 addition & 0 deletions qubes/vm/qubesvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,7 @@ def set_mem(self):
if not qmemman_present or self.maxmem == 0:
return None

self.log.info("Setting qube memory to pref mem")
qmemman_client = qubes.qmemman.client.QMemmanClient()
try:
result = qmemman_client.set_mem({self.xid: 0})
Expand Down