|
import re
|
|
import time
|
|
import os
|
|
import random
|
|
import sys
|
|
import gc
|
|
|
|
start_time=time.time()
|
|
|
|
# Monitor use of Resident and Virtual memory.
|
|
class Memory:
|
|
|
|
def __init__(self):
|
|
self.shared_dirty = '.+?Shared_Dirty:\s+(\d+)'
|
|
self.priv_dirty = '.+?Private_Dirty:\s+(\d+)'
|
|
self.MEM_REGEXP = re.compile("{shared_dirty}{priv_dirty}".format(shared_dirty=self.shared_dirty, priv_dirty=self.priv_dirty), re.DOTALL)
|
|
|
|
# get memory usage
|
|
def get_memory_map(self, pids):
|
|
memory_map = {}
|
|
memory_map[ "pids_found" ] = {}
|
|
memory_map[ "shared_dirty" ] = 0
|
|
memory_map[ "priv_dirty" ] = 0
|
|
|
|
for pid in pids:
|
|
try:
|
|
lines = None
|
|
|
|
with open( "/proc/{pid}/smaps".format(pid=pid), "r" ) as infile:
|
|
lines = infile.read()
|
|
except:
|
|
lines = None
|
|
|
|
if lines:
|
|
for shared_dirty, priv_dirty in re.findall( self.MEM_REGEXP, lines ):
|
|
memory_map[ "pids_found" ][pid] = True
|
|
memory_map[ "shared_dirty" ] += int( shared_dirty )
|
|
memory_map[ "priv_dirty" ] += int( priv_dirty )
|
|
|
|
memory_map[ "pids_found" ] = memory_map[ "pids_found" ].keys()
|
|
return memory_map
|
|
|
|
# get the processes and get the value of the memory usage
|
|
def memory_usage( self):
|
|
pids = [ os.getpid() ]
|
|
result = self.get_memory_map( pids)
|
|
|
|
result[ "pids" ] = pids
|
|
|
|
return result
|
|
|
|
# print the values of the private and shared memories
|
|
def log( self, process_name='', log_tag=""):
|
|
if process_name == "header":
|
|
print " %-6s %5s %-12s %10s %10s" % ("proces", "pid", "log", "priv_dirty", "shared_dirty")
|
|
else:
|
|
global start_time
|
|
Time = time.time() - start_time
|
|
mem = self.memory_usage( )
|
|
print " %-6s %5d %-12s %10d %10d" % (process_name, os.getpid(), log_tag, mem["priv_dirty"]/1000, mem["shared_dirty"]/1000)
|
|
|
|
# function to delay the processes a bit
|
|
def time_step( n):
|
|
global start_time
|
|
while (time.time() - start_time) < n:
|
|
time.sleep( 0.01)
|
|
|
|
# create an object of specified size. The option argument can be changed from 0 to 2 to visualize the behavior of the GC in various cases
|
|
#
|
|
# case 0 (default) : we make a huge array of small objects by formatting a string
|
|
# case 1 : we make a huge array of small objects without formatting a string (we use the to_s function)
|
|
# case 2 : we make a smaller array of big objects
|
|
def memory_object( size, option=2):
|
|
count = size/20
|
|
|
|
if option > 3 or option < 1:
|
|
result = [ "%20.18f"% random.random() for i in xrange(count) ]
|
|
|
|
elif option == 1:
|
|
result = [ str( random.random() ) for i in xrange(count) ]
|
|
|
|
elif option == 2:
|
|
count = count/10
|
|
result = [ ("%20.18f"% random.random())*30 for i in xrange(count) ]
|
|
|
|
return result
|
|
|
|
##### main #####
|
|
|
|
print "python version {version}".format(version=sys.version)
|
|
|
|
memory = Memory()
|
|
|
|
gc.disable()
|
|
|
|
# print the column headers and first line
|
|
memory.log( "header") # Print the headers of the columns
|
|
|
|
# Allocation of memory
|
|
big_memory = memory_object( 1000 * 1000 * 10) # Allocate memory
|
|
|
|
memory.log( "Parent", "post alloc")
|
|
|
|
lab_time = time.time() - start_time
|
|
if lab_time < 3.9:
|
|
lab_time = 0
|
|
|
|
# start the forking
|
|
pid = os.fork() # fork the process
|
|
if pid == 0:
|
|
Time = 4
|
|
time_step( Time + lab_time)
|
|
memory.log( "Child", "{time} initial".format(time=Time))
|
|
|
|
# force GC when nothing happened
|
|
gc.enable(); gc.collect(); gc.disable()
|
|
|
|
Time = 10
|
|
time_step( Time + lab_time)
|
|
memory.log( "Child", "{time} empty GC".format(time=Time))
|
|
|
|
time.sleep( 1)
|
|
|
|
sys.exit(0)
|
|
|
|
Time = 4
|
|
time_step( Time + lab_time)
|
|
memory.log( "Parent", "{time} fork".format(time=Time))
|
|
|
|
# Wait for child process to finish
|
|
os.waitpid( pid, 0)
|