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."""
14
16
15
17
def __init__ (self , usage , threshold , * args ):
16
18
"""Compose the error message containing the memory consumption."""
17
19
super ().__init__ (
18
- f"Memory usage ({ usage / 2 ** 20 :.2f} MiB) exceeded maximum threshold "
19
- f"({ threshold / 2 ** 20 } MiB)" ,
20
+ f"Memory usage ({ usage / 1 << 20 :.2f} MiB) exceeded maximum threshold "
21
+ f"({ threshold / 1 << 20 } MiB)" ,
20
22
* args ,
21
23
)
22
24
@@ -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 << 30
36
+ X86_32BIT_MEMORY_GAP_SIZE = 1 << 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 << 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 << 30
44
+ ARM64_MEMORY_START = 2 << 30
45
+
46
+ def __init__ (self , vm , threshold = 5 << 20 , period_s = 0.01 ):
35
47
"""Initialize monitor attributes."""
36
48
Thread .__init__ (self )
37
49
self ._vm = vm
@@ -72,7 +84,9 @@ def run(self):
72
84
mem_total = 0
73
85
for mmap in mmaps :
74
86
if self .is_guest_mem (mmap .size , guest_mem_bytes ):
87
+ print (f"Region { mmap } is guest memory" )
75
88
continue
89
+
76
90
mem_total += mmap .rss
77
91
self ._current_rss = mem_total
78
92
if mem_total > self .threshold :
@@ -81,24 +95,55 @@ def run(self):
81
95
82
96
time .sleep (self ._period_s )
83
97
84
- def is_guest_mem (self , size , guest_mem_bytes ):
98
+ def is_guest_mem_x86 (self , size , guest_mem_bytes ):
85
99
"""
86
- If the address is recognised as a guest memory region,
87
- return True, otherwise return False.
100
+ Checks if a region is a guest memory region based on
101
+ x86_64 physical memory layout
88
102
"""
103
+ return size in (
104
+ # memory fits before the first gap
105
+ guest_mem_bytes ,
106
+ # guest memory spans at least two regions & memory fits before the second gap
107
+ self .X86_32BIT_MEMORY_GAP_START ,
108
+ # guest memory spans exactly two regions
109
+ guest_mem_bytes - self .X86_32BIT_MEMORY_GAP_START ,
110
+ # guest memory fills the space between the two gaps
111
+ self .X86_64BIT_MEMORY_GAP_START
112
+ - self .X86_32BIT_MEMORY_GAP_START
113
+ - self .X86_32BIT_MEMORY_GAP_SIZE ,
114
+ # guest memory spans 3 regions, this is what remains past the second gap
115
+ guest_mem_bytes
116
+ - self .X86_64BIT_MEMORY_GAP_START
117
+ + self .X86_32BIT_MEMORY_GAP_SIZE ,
118
+ )
89
119
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.
120
+ def is_guest_mem_arch64 (self , size , guest_mem_bytes ):
121
+ """
122
+ Checks if a region is a guest memory region based on
123
+ ARM64 physical memory layout
124
+ """
96
125
return size in (
126
+ # guest memory fits before the gap
97
127
guest_mem_bytes ,
98
- self .X86_MEMORY_GAP_START ,
99
- guest_mem_bytes - self .X86_MEMORY_GAP_START ,
128
+ # guest memory fills the space before the gap
129
+ self .ARM64_64BIT_MEMORY_GAP_START - self .ARM64_MEMORY_START ,
130
+ # guest memory spans 2 regions, this is what remains past the gap
131
+ guest_mem_bytes
132
+ - self .ARM64_64BIT_MEMORY_GAP_START
133
+ + self .ARM64_MEMORY_START ,
100
134
)
101
135
136
+ def is_guest_mem (self , size , guest_mem_bytes ):
137
+ """
138
+ If the address is recognised as a guest memory region,
139
+ return True, otherwise return False.
140
+ """
141
+
142
+ if global_props .cpu_architecture == "x86_64" :
143
+ return self .is_guest_mem_x86 (size , guest_mem_bytes )
144
+
145
+ return self .is_guest_mem_arch64 (size , guest_mem_bytes )
146
+
102
147
def check_samples (self ):
103
148
"""Check that there are no samples over the threshold."""
104
149
if self ._exceeded is not None :
0 commit comments