|
$start_time=Time.new
|
|
|
|
# Monitor use of Resident and Virtual memory.
|
|
class Memory
|
|
|
|
shared_dirty = '.+?Shared_Dirty:\s+(\d+)'
|
|
priv_dirty = '.+?Private_Dirty:\s+(\d+)'
|
|
MEM_REGEXP = /#{shared_dirty}#{priv_dirty}/m
|
|
|
|
# get memory usage
|
|
def self.get_memory_map( pids)
|
|
memory_map = {}
|
|
memory_map[ :pids_found] = {}
|
|
memory_map[ :shared_dirty] = 0
|
|
memory_map[ :priv_dirty] = 0
|
|
|
|
pids.each do |pid|
|
|
begin
|
|
lines = nil
|
|
lines = File.read( "/proc/#{pid}/smaps")
|
|
rescue
|
|
lines = nil
|
|
end
|
|
if lines
|
|
lines.scan(MEM_REGEXP) do |shared_dirty, priv_dirty|
|
|
memory_map[ :pids_found][pid] = true
|
|
memory_map[ :shared_dirty] += shared_dirty.to_i
|
|
memory_map[ :priv_dirty] += priv_dirty.to_i
|
|
end
|
|
end
|
|
end
|
|
memory_map[ :pids_found] = memory_map[ :pids_found].keys
|
|
return memory_map
|
|
end
|
|
|
|
# get the processes and get the value of the memory usage
|
|
def self.memory_usage( )
|
|
pids = [ $$]
|
|
result = self.get_memory_map( pids)
|
|
|
|
result[ :pids] = pids
|
|
return result
|
|
end
|
|
|
|
# print the values of the private and shared memories
|
|
def self.log( process_name='', log_tag="")
|
|
if process_name == "header"
|
|
puts " %-6s %5s %-12s %10s %10s\n" % ["proces", "pid", "log", "priv_dirty", "shared_dirty"]
|
|
else
|
|
time = Time.new - $start_time
|
|
mem = Memory.memory_usage( )
|
|
puts " %-6s %5d %-12s %10d %10d\n" % [process_name, $$, log_tag, mem[:priv_dirty]/1000, mem[:shared_dirty]/1000]
|
|
end
|
|
end
|
|
end
|
|
|
|
# function to delay the processes a bit
|
|
def time_step( n)
|
|
while Time.new - $start_time < n
|
|
sleep( 0.01)
|
|
end
|
|
end
|
|
|
|
# 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=0)
|
|
result = []
|
|
count = size/20
|
|
|
|
if option > 3 or option < 1
|
|
count.times do
|
|
result << "%20.18f" % rand
|
|
end
|
|
elsif option == 1
|
|
count.times do
|
|
result << rand.to_s
|
|
end
|
|
elsif option == 2
|
|
count = count/10
|
|
count.times do
|
|
result << ("%20.18f" % rand)*30
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
##### main #####
|
|
|
|
puts "ruby version #{RUBY_VERSION}"
|
|
|
|
GC.disable
|
|
|
|
# print the column headers and first line
|
|
Memory.log( "header")
|
|
|
|
# Allocation of memory
|
|
big_memory = memory_object( 1000 * 1000 * 10)
|
|
|
|
Memory.log( "Parent", "post alloc")
|
|
|
|
lab_time = Time.new - $start_time
|
|
if lab_time < 3.9
|
|
lab_time = 0
|
|
end
|
|
|
|
# start the forking
|
|
pid = fork do
|
|
time = 4
|
|
time_step( time + lab_time)
|
|
Memory.log( "Child", "#{time} initial")
|
|
|
|
# force GC when nothing happened
|
|
GC.enable; GC.start; GC.disable
|
|
|
|
time = 8
|
|
time_step( time + lab_time)
|
|
Memory.log( "Child", "#{time} empty GC")
|
|
|
|
sleep( 1)
|
|
STDOUT.flush
|
|
exit!
|
|
end
|
|
|
|
time = 4
|
|
time_step( time + lab_time)
|
|
Memory.log( "Parent", "#{time} fork")
|
|
|
|
# wait for the child to finish
|
|
Process.wait( pid)
|
|
|