Add graphviz output
This adds a method to blocks to get outgoing ids, then uses the outgoing ids to generate a graphviz graph. Two methods were added to the Block object. One method returns an id for the block, which is just the address of the underlying block. The other method returns a list of outgoing block ids. We can use Block#id in conjunction with Block#outgoing_ids to construct a graph of blocks
This commit is contained in:
parent
f54e6e1310
commit
46d5e10279
37
yjit.rb
37
yjit.rb
@ -55,6 +55,43 @@ module YJIT
|
||||
def self.comments_for(start_address, end_address)
|
||||
Primitive.comments_for(start_address, end_address)
|
||||
end
|
||||
|
||||
def self.graphviz_for(iseq)
|
||||
iseq = RubyVM::InstructionSequence.of(iseq)
|
||||
buff = ''
|
||||
blocks = blocks_for(iseq)
|
||||
buff << "digraph g {"
|
||||
buff << " node [shape=record];"
|
||||
blocks.each do |block|
|
||||
buff << "b#{block.id} [label=\"#{disasm_block(block).gsub(/\n/, "\\l\n")}\"];"
|
||||
block.outgoing_ids.each do |id|
|
||||
buff << "b#{block.id} -> b#{id};"
|
||||
end
|
||||
end
|
||||
buff << "}"
|
||||
buff
|
||||
end
|
||||
|
||||
def self.disasm_block(block)
|
||||
cs = YJIT::Disasm.new
|
||||
comments = comments_for(block.address, block.address + block.code.length)
|
||||
comment_idx = 0
|
||||
str = ''
|
||||
cs.disasm(block.code, block.address).each do |i|
|
||||
while (comment = comments[comment_idx]) && comment.address <= i.address
|
||||
str << " ; #{comment.comment}\n"
|
||||
comment_idx += 1
|
||||
end
|
||||
|
||||
str << sprintf(
|
||||
" %<address>08x: %<instruction>s\t%<details>s\n",
|
||||
address: i.address,
|
||||
instruction: i.mnemonic,
|
||||
details: i.op_str
|
||||
)
|
||||
end
|
||||
str
|
||||
end
|
||||
end
|
||||
|
||||
# Return a hash for statistics generated for the --yjit-stats command line option.
|
||||
|
51
yjit_iface.c
51
yjit_iface.c
@ -1025,6 +1025,55 @@ rb_yjit_call_threshold(void)
|
||||
return rb_yjit_opts.call_threshold;
|
||||
}
|
||||
|
||||
# define PTR2NUM(x) (LONG2NUM((long)(x)))
|
||||
|
||||
/**
|
||||
* call-seq: block.id -> unique_id
|
||||
*
|
||||
* Returns a unique integer ID for the block. For example:
|
||||
*
|
||||
* blocks = blocks_for(iseq)
|
||||
* blocks.group_by(&:id)
|
||||
*/
|
||||
static VALUE
|
||||
block_id(VALUE self)
|
||||
{
|
||||
block_t * block;
|
||||
TypedData_Get_Struct(self, block_t, &yjit_block_type, block);
|
||||
return PTR2NUM(block);
|
||||
}
|
||||
|
||||
/**
|
||||
* call-seq: block.outgoing_ids -> list
|
||||
*
|
||||
* Returns a list of outgoing ids for the current block. This list can be used
|
||||
* in conjunction with Block#id to construct a graph of block objects.
|
||||
*/
|
||||
static VALUE
|
||||
outgoing_ids(VALUE self)
|
||||
{
|
||||
block_t * block;
|
||||
TypedData_Get_Struct(self, block_t, &yjit_block_type, block);
|
||||
|
||||
VALUE ids = rb_ary_new();
|
||||
|
||||
rb_darray_for(block->outgoing, branch_idx) {
|
||||
branch_t* out_branch = rb_darray_get(block->outgoing, branch_idx);
|
||||
|
||||
for (size_t succ_idx = 0; succ_idx < 2; succ_idx++) {
|
||||
block_t* succ = out_branch->blocks[succ_idx];
|
||||
|
||||
if (succ == NULL)
|
||||
continue;
|
||||
|
||||
rb_ary_push(ids, PTR2NUM(succ));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Can raise RuntimeError
|
||||
void
|
||||
rb_yjit_init(struct rb_yjit_options *options)
|
||||
@ -1069,9 +1118,11 @@ rb_yjit_init(struct rb_yjit_options *options)
|
||||
// YJIT::Block (block version, code block)
|
||||
cYjitBlock = rb_define_class_under(mYjit, "Block", rb_cObject);
|
||||
rb_define_method(cYjitBlock, "address", block_address, 0);
|
||||
rb_define_method(cYjitBlock, "id", block_id, 0);
|
||||
rb_define_method(cYjitBlock, "code", block_code, 0);
|
||||
rb_define_method(cYjitBlock, "iseq_start_index", iseq_start_index, 0);
|
||||
rb_define_method(cYjitBlock, "iseq_end_index", iseq_end_index, 0);
|
||||
rb_define_method(cYjitBlock, "outgoing_ids", outgoing_ids, 0);
|
||||
|
||||
// YJIT disassembler interface
|
||||
#if HAVE_LIBCAPSTONE
|
||||
|
Loading…
x
Reference in New Issue
Block a user