Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
require 'json'
require 'fiddle'
module HeapUtils
SIZEOF_HEAP_PAGE_HEADER_STRUCT = Fiddle::SIZEOF_VOIDP
HEAP_PAGE_ALIGN_LOG = 14
HEAP_PAGE_ALIGN = 1 << HEAP_PAGE_ALIGN_LOG
HEAP_PAGE_ALIGN_MASK = ~(~0 << HEAP_PAGE_ALIGN_LOG)
# SIZEOF_RVALUE = 56 # Only when GC_DEBUG is enabled
SIZEOF_RVALUE = 40
REQUIRED_SIZE_BY_MALLOC = Fiddle::SIZEOF_SIZE_T * 5 # padding needed by malloc
HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN - REQUIRED_SIZE_BY_MALLOC
HEAP_PAGE_OBJ_LIMIT = (HEAP_PAGE_SIZE - SIZEOF_HEAP_PAGE_HEADER_STRUCT) / SIZEOF_RVALUE
def NUM_IN_PAGE object_address
(object_address & HEAP_PAGE_ALIGN_MASK) / SIZEOF_RVALUE
end
def GET_PAGE_BODY object_address
object_address & ~HEAP_PAGE_ALIGN_MASK
end
# Calculate the address given an object id
def id_to_addr object_id
object_id << 1
end
# Calculate page body address from object address
def page_addr_from_object_addr object_address
GET_PAGE_BODY(object_address)
end
# Offset from the start of a page. E.g. the address for the 4th object in
# a page will return 4
def page_number_from_object_addr object_address
NUM_IN_PAGE(object_address)
end
class Page < Struct.new :addr, :start, :total_slots
def finish
start + total_slots
end
end
# Get a page given an address
def page_for_address addr
page page_addr_from_object_addr addr
end
# Get a page for a live object
def page_for_object obj
page_for_address id_to_addr obj.object_id
end
def page page_body
limit = HEAP_PAGE_OBJ_LIMIT
start = page_body + SIZEOF_HEAP_PAGE_HEADER_STRUCT
if start % SIZEOF_RVALUE != 0
delta = SIZEOF_RVALUE - (start % SIZEOF_RVALUE)
start = start + delta
limit = (HEAP_PAGE_SIZE - (start - page_body)) / SIZEOF_RVALUE
end
Page.new page_body, start, limit
end
end
include HeapUtils
pages = { }
File.open(ARGV[0], 'r') do |f|
f.each_line do |line|
object = JSON.load line
if object['type'] != 'ROOT'
address = object['address'].to_i 16
page = page_for_address address
pages[page.addr] ||= []
pages[page.addr] << object
end
end
end
puts "pinned,unpinned,empty"
pinning = pages.sort_by { |k,v| v.select { |obj| obj.key?('flags') && obj['flags']['pinned'] }.length }.reverse
pinning.each do |page_addr, objs|
page_obj = page_for_address page_addr
pinned = objs.select { |o| o.key?('flags') && o['flags']['pinned'] }.length
empty = page_obj.total_slots - objs.length
puts "#{pinned},#{objs.length - pinned},#{empty}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment