Skip to content

Commit 4e781f5

Browse files
committed
tests: fix MMIO gaps in memory monitor tool
The memory monitor was only assuming a single MMIO gap on x86_64 when calculating the memory regions that corresponded to guest memory. Now we need to account for two MMIO gaps in x86 and one in ARM. Signed-off-by: Babis Chalios <[email protected]>
1 parent c7419fa commit 4e781f5

File tree

1 file changed

+63
-15
lines changed

1 file changed

+63
-15
lines changed

tests/host_tools/memory.py

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import psutil
1010

11+
from framework.properties import global_props
12+
1113

1214
class MemoryUsageExceededError(Exception):
1315
"""A custom exception containing details on excessive memory usage."""
@@ -28,10 +30,20 @@ class MemoryMonitor(Thread):
2830
VMM memory usage.
2931
"""
3032

31-
# If guest memory is >3328MB, it is split in a 2nd region
32-
X86_MEMORY_GAP_START = 3328 * 2**20
33-
34-
def __init__(self, vm, threshold=5 * 2**20, period_s=0.05):
33+
# If guest memory is >3GiB, it is split in a 2nd region
34+
# Gap starts at 3GiBs and is 1GiB long
35+
X86_32BIT_MEMORY_GAP_START = 3 * 2**30
36+
X86_32BIT_MEMORY_GAP_SIZE = 1 * 2**30
37+
# If guest memory is >255GiB, it is split in a 3rd region
38+
# Gap starts at 256 GiB and is 256GiB long
39+
X86_64BIT_MEMORY_GAP_START = 256 * 2**30
40+
# On ARM64 we just have a single gap, but memory starts at an offset
41+
# Gap starts at 256 GiB and is GiB long
42+
# Memory starts at 2GiB
43+
ARM64_64BIT_MEMORY_GAP_START = 256 * 2**30
44+
ARM64_MEMORY_START = 2 * 2**30
45+
46+
def __init__(self, vm, threshold=5 * 2**20, period_s=0.01):
3547
"""Initialize monitor attributes."""
3648
Thread.__init__(self)
3749
self._vm = vm
@@ -71,8 +83,13 @@ def run(self):
7183
return
7284
mem_total = 0
7385
for mmap in mmaps:
86+
if mmap.size >= 512 * 2**20:
87+
print(f"Checking mmap region: {mmap}. VM memory: {guest_mem_bytes}")
88+
7489
if self.is_guest_mem(mmap.size, guest_mem_bytes):
90+
print(f"Region {mmap} is guest memory")
7591
continue
92+
7693
mem_total += mmap.rss
7794
self._current_rss = mem_total
7895
if mem_total > self.threshold:
@@ -81,24 +98,55 @@ def run(self):
8198

8299
time.sleep(self._period_s)
83100

84-
def is_guest_mem(self, size, guest_mem_bytes):
101+
def is_guest_mem_x86(self, size, guest_mem_bytes):
85102
"""
86-
If the address is recognised as a guest memory region,
87-
return True, otherwise return False.
103+
Checks if a region is a guest memory region based on
104+
x86_64 physical memory layout
88105
"""
106+
return size in (
107+
# memory fits before the first gap
108+
guest_mem_bytes,
109+
# guest memory spans at least two regions & memory fits before the second gap
110+
self.X86_32BIT_MEMORY_GAP_START,
111+
# guest memory spans exactly two regions
112+
guest_mem_bytes - self.X86_32BIT_MEMORY_GAP_START,
113+
# guest memory fills the space between the two gaps
114+
self.X86_64BIT_MEMORY_GAP_START
115+
- self.X86_32BIT_MEMORY_GAP_START
116+
- self.X86_32BIT_MEMORY_GAP_SIZE,
117+
# guest memory spans 3 regions, this is what remains past the second gap
118+
guest_mem_bytes
119+
- self.X86_64BIT_MEMORY_GAP_START
120+
+ self.X86_32BIT_MEMORY_GAP_SIZE,
121+
)
89122

90-
# If x86_64 guest memory exceeds 3328M, it will be split
91-
# in 2 regions: 3328M and the rest. We have 3 cases here
92-
# to recognise a guest memory region:
93-
# - its size matches the guest memory exactly
94-
# - its size is 3328M
95-
# - its size is guest memory minus 3328M.
123+
def is_guest_mem_arch64(self, size, guest_mem_bytes):
124+
"""
125+
Checks if a region is a guest memory region based on
126+
ARM64 physical memory layout
127+
"""
96128
return size in (
129+
# guest memory fits before the gap
97130
guest_mem_bytes,
98-
self.X86_MEMORY_GAP_START,
99-
guest_mem_bytes - self.X86_MEMORY_GAP_START,
131+
# guest memory fills the space before the gap
132+
self.ARM64_64BIT_MEMORY_GAP_START - self.ARM64_MEMORY_START,
133+
# guest memory spans 2 regions, this is what remains past the gap
134+
guest_mem_bytes
135+
- self.ARM64_64BIT_MEMORY_GAP_START
136+
+ self.ARM64_MEMORY_START,
100137
)
101138

139+
def is_guest_mem(self, size, guest_mem_bytes):
140+
"""
141+
If the address is recognised as a guest memory region,
142+
return True, otherwise return False.
143+
"""
144+
145+
if global_props.cpu_architecture == "x86_64":
146+
return self.is_guest_mem_x86(size, guest_mem_bytes)
147+
148+
return self.is_guest_mem_arch64(size, guest_mem_bytes)
149+
102150
def check_samples(self):
103151
"""Check that there are no samples over the threshold."""
104152
if self._exceeded is not None:

0 commit comments

Comments
 (0)