88
99import  psutil 
1010
11+ from  framework .properties  import  global_props 
12+ 
1113
1214class  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 } { guest_mem_bytes }  )
88+ 
7489                if  self .is_guest_mem (mmap .size , guest_mem_bytes ):
90+                     print (f"Region { mmap }  )
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