8
8
9
9
import psutil
10
10
11
+ from framework .properties import global_props
12
+
11
13
12
14
class MemoryUsageExceededError (Exception ):
13
15
"""A custom exception containing details on excessive memory usage."""
@@ -28,10 +30,20 @@ class MemoryMonitor(Thread):
28
30
VMM memory usage.
29
31
"""
30
32
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 ):
35
47
"""Initialize monitor attributes."""
36
48
Thread .__init__ (self )
37
49
self ._vm = vm
@@ -71,8 +83,13 @@ def run(self):
71
83
return
72
84
mem_total = 0
73
85
for mmap in mmaps :
86
+ if mmap .size >= 512 * 2 ** 20 :
87
+ print (f"Checking mmap region: { mmap } . VM memory: { guest_mem_bytes } " )
88
+
74
89
if self .is_guest_mem (mmap .size , guest_mem_bytes ):
90
+ print (f"Region { mmap } is guest memory" )
75
91
continue
92
+
76
93
mem_total += mmap .rss
77
94
self ._current_rss = mem_total
78
95
if mem_total > self .threshold :
@@ -81,24 +98,55 @@ def run(self):
81
98
82
99
time .sleep (self ._period_s )
83
100
84
- def is_guest_mem (self , size , guest_mem_bytes ):
101
+ def is_guest_mem_x86 (self , size , guest_mem_bytes ):
85
102
"""
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
88
105
"""
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
+ )
89
122
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
+ """
96
128
return size in (
129
+ # guest memory fits before the gap
97
130
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 ,
100
137
)
101
138
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
+
102
150
def check_samples (self ):
103
151
"""Check that there are no samples over the threshold."""
104
152
if self ._exceeded is not None :
0 commit comments