跟踪Ruby使用TracePoint调用“优化”方法调用

时间:2015-07-20 16:43:32

标签: ruby

我正在尝试使用TracePoint跟踪Ruby程序中的所有方法调用。它运行良好,直到我按下方法调用“优化”方法调用。

Ruby通过用专门的指令替换YARV指令来“优化”运算符,以加速方法调用,例如大于,小于。其中一个优化

你可以通过运行

直接看到这个
code = <<END
   1 / 1
END
puts RubyVM::InstructionSequence.compile(code).disasm

# == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
# 0000 trace            1                                               (   1)
# 0002 putobject_OP_INT2FIX_O_1_C_
# 0003 putobject_OP_INT2FIX_O_1_C_
# 0004 opt_div          <callinfo!mid:/, argc:1, ARGS_SIMPLE>
# 0006 leave

您在此处看到opt_div而不是opt_send_without_block

您似乎无法跟踪这些优化的方法调用。例如:

trace = TracePoint.trace(:call, :c_call) do |tp|
  tp.disable
  puts "calling #{tp.defined_class}##{tp.method_id}"
  tp.enable
end

trace.enable
1.div(1)
1 / 1
1.div(2)

您可以看到1.div已被跟踪,但不是1/1

calling TracePoint#enable
calling Fixnum#div
calling Fixnum#div

所以我的问题是:如何跟踪所有方法调用,包括Ruby(MRI)中的“优化”方法调用?

1 个答案:

答案 0 :(得分:1)

从koichi,您可以使用以下方法禁用优化:

RubyVM::InstructionSequence.compile_option = { specialized_instruction: false }

这适用于我的情况,但我想它会减慢执行速度。

如果您在家中尝试此操作,另一个警告是,您无法在同一文件中设置compile_option,因为在执行文件已经编译时。相反,您需要在加载或需要您尝试跟踪的文件之前执行此代码。

您也可以在eval-d代码中使用此选项:

iseq = RubyVM::InstructionSequence.compile(<<EOS, nil, nil, 1, specialized_instruction: false)
   1 / 1
EOS

trace = TracePoint.trace(:call, :c_call) do |tp|
  tp.disable
  puts "calling #{tp.defined_class}##{tp.method_id}"
  tp.enable
end

iseq.eval