Skip to content

Commit

Permalink
Overly simple db generation -- takes much too long with much not bein…
Browse files Browse the repository at this point in the history
…g stored
  • Loading branch information
enebo committed May 30, 2014
1 parent 4119749 commit bb3b296
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 19 deletions.
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- ruby -*-

source "http://gems.github.com"
source "http://rubygems.org"
gem 'sequel'
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Alienist - Java Heap Memory Analyzer

Random crap for funz:
select count() from instances where class_id = (select id from classes where name = "org.jruby.RubyString");
6342

5 changes: 4 additions & 1 deletion bin/alienist
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'optparse'
require 'alienist/parser'
require 'alienist/reader'
require 'alienist/snapshot/sequel_snapshot'

debug = 0

Expand All @@ -15,7 +16,9 @@ end
opts.parse!(ARGV)

File.open(ARGV.shift, "rb") do |io|
dump = Alienist::Parser.new Alienist::Reader.new(io, debug), debug
reader = Alienist::Reader.new(io, debug)
snapshot = Alienist::SequelSnapshot.new
dump = Alienist::Parser.new reader, snapshot, debug
dump.parse
# p dump
end
5 changes: 4 additions & 1 deletion lib/alienist/model/java_field.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module Alienist
class JavaField
def initialize(*r)
attr_reader :id, :name, :type

def initialize(id, name, type)
@id, @name, @type = id, name, type
end
end
end
5 changes: 4 additions & 1 deletion lib/alienist/model/java_static.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module Alienist
class JavaStatic
def initialize(*r)
attr_reader :field, :value

def initialize(field, value)
@field, @value = field, value
end
end
end
29 changes: 13 additions & 16 deletions lib/alienist/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ class Parser
GC_ROOT_NATIVE_STACK, GC_ROOT_STICKY_CLASS = 0x04, 0x05
GC_ROOT_THREAD_BLOCK, GC_ROOT_MONITOR_USED = 0x06, 0x07

def initialize(io, debug=0)
@io, @debug = io, debug
def initialize(io, snapshot, debug=0)
@io, @snapshot, @debug = io, snapshot, debug
@names = Hash.new { |hash, k| "unresolved class #{k}" }
@names[0] = "" # For 0 id
@class_name_from_id = {}
Expand Down Expand Up @@ -99,15 +99,15 @@ def read_heap_dump(amount)
case(type)
when GC_ROOT_UNKNOWN then
puts "Subloading GC_ROOT_UNKNOWN" if @debug > 0
add_root @io.read_id, 0, UNKNOWN, ""
@snapshot.add_root @io.read_id, 0, UNKNOWN, ""
when GC_ROOT_THREAD_OBJ then
puts "Subloading GC_ROOT_THREAD_OBJ" if @debug > 0
id, thread_seq, stack_seq = @io.read_id, @io.read_int, @io.read_int
@thread_objects[thread_seq] = [id, stack_seq]
when GC_ROOT_JNI_GLOBAL then
puts "Subloading GC_ROOT_JNI_GLOBAL" if @debug > 0
id, _ = @io.read_id, @io.read_id # ignored global_ref_id
add_root @io.read_id, 0, NATIVE_STATIC, ""
@snapshot.add_root @io.read_id, 0, NATIVE_STATIC, ""
when GC_ROOT_JNI_LOCAL then
puts "Subloading GC_ROOT_JNI_LOCAL" if @debug > 0
id, thread_seq, depth = @io.read_id, @io.read_int, @io.read_int
Expand Down Expand Up @@ -156,8 +156,8 @@ def load_class
class_name_id = @io.read_id

name = @names[class_name_id].gsub('/', '.')
@class_name_from_id[class_name_id] = name
puts "ID: #{class_name_id}, NAME: #{name}" if @debug > 3
@class_name_from_id[class_id] = name
puts "ID: #{class_name_id}, NAME: #{name}"# if @debug > 3
@class_name_from_serial[class_id] = name
end

Expand All @@ -179,7 +179,10 @@ def read_primitive_array_dump
def read_instance_dump
read_section do |id, serial|
class_id, bytes_following = @io.read_id, @io.read_int
@io.skip_bytes bytes_following, "instance_dump" # FIXME: Process
@io.skip_bytes bytes_following, "instance_dump"
# FIXME: Process Unclear if perhaps I should process greedily
# OR save offset and keep io open OR save blob in DB as part of this
@snapshot.add_instance(id, serial, class_id, bytes_following)
end
end

Expand All @@ -195,7 +198,7 @@ def read_class_dump
statics = read_static_fields(@io.read_unsigned_short)
fields = read_fields(@io.read_unsigned_short)

add_class id, name, super_id, classloader_id, signers_id,
@snapshot.add_class id, name, super_id, classloader_id, signers_id,
protection_domain_id, statics, fields, instance_size
end
end
Expand All @@ -211,7 +214,7 @@ def read_static_fields(count)
type, _ = signature_for type_id
field_name = @names[name_id]
value = read_value_for(type)
statics << JavaStatic.new(JavaField.new(field_name, type), value)
statics << JavaStatic.new(JavaField.new(name_id, field_name, type), value)
end
end
end
Expand All @@ -221,7 +224,7 @@ def read_fields(count)
count.times do |i| # process all static fields
name_id, type_id = @io.read_id, @io.read_byte
type, _ = signature_for type_id
fields << JavaField.new(@names[name_id], type)
fields << JavaField.new(name_id, @names[name_id], type)
end
end
end
Expand All @@ -246,12 +249,6 @@ def skip_constant_pool_entries(count)
end
end

def add_class(*r)
end

def add_root(*r)
end

def signature_for(id)
return TYPES[id], TYPE_SIZES[id]
end
Expand Down
75 changes: 75 additions & 0 deletions lib/alienist/snapshot/sequel_snapshot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require 'sequel'

module Alienist
class SequelSnapshot
def initialize(db_string="jdbc:sqlite:db")
@db = Sequel.connect(db_string)
create_schema
end

def add_instance(id, serial, class_id, bytes_following)
@db[:instances].insert(id: id, class_id: class_id)
end

def add_root(*r)
end

def add_class(id, name, super_id, classloader_id, signers_id,
protection_domain_id, static_fields, fields, instance_size)
@db[:classes].insert(id: id, name: name, super_id: super_id,
classloader_id: classloader_id,
signers_id: signers_id,
protection_domain_id: protection_domain_id,
instance_size: instance_size)

# static_fields.each do |field|
# @db[:static_fields].insert(id: field.field.id, class_id: id,
# name: field.field.name,
# type: field.field.type)
# end

# fields.each do |field|
# @db[:fields].insert(id: field.id, class_id: id,
# name: field.name, type: field.type)
# end
end


def create_schema
@db.drop_table :classes if @db.table_exists?(:classes)
@db.drop_table :fields if @db.table_exists?(:fields)
@db.drop_table :static_fields if @db.table_exists?(:static_fields)
@db.drop_table :instances if @db.table_exists?(:instances)

@db.create_table(:instances) do
primary_key :id
Int :class_id, null: false
end

@db.create_table(:fields) do
primary_key :id
Int :class_id, null: false
String :name, null: false
String :type, null: false
end

@db.create_table(:static_fields) do
primary_key :id
Int :class_id, null: false
String :name, null: false
String :type, null: false
end
# FIXME: need to store value and deal with heap, object_ref, and value

@db.create_table(:classes) do
primary_key :id
String :name, null: false
Int :super_id, null: false
Int :classloader_id, null: false
Int :signers_id, null: false
Int :protection_domain_id, null: false
Int :instance_size, null: false
end
end
end
end

0 comments on commit bb3b296

Please sign in to comment.