我正在尝试使用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)中的“优化”方法调用?
答案 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