プロファイラの速度向上チャレンジと挫折
プロファイラの速度向上のため、メソッドコールのたびに呼ばれるhandle_call/ handle_returnをハンドコンパイルしてインライン化してみようと思いました。
def handle_call(obj) now = Process.times[0] @@objstk.push obj @@stack.push [now, 0.0] end def handle_return(method) # print "#{obj}:#{method}\n" obj = @@objstk.pop now = Process.times[0] if tick = @@stack.pop key = [obj.class, method] data = (@@map[key] ||= [0, 0.0, 0.0, key]) data[0] += 1 cost = now - tick[0] data[1] += cost data[2] += cost - tick[1] @@stack[-1][1] += cost if @@stack[-1] end end
ただハンドコンパイルするのではなく、使える変数はグローバル変数だけで、速度向上のため事実上ワーキングメモリはスタックだけしか使えないという状態でした。作っていて挫折しました。どう考えてもまともに動くとは思えなくなってきました。
とりあえず、handle_call部分だけ作りました。
[:getglobal, :$__prof_stack], [:dup], [:dup], # 現在のプロセス時間 [:putnil], [:getconstant, :Process], [:send, :times, 0, nil, 0, nil], [:putobject, 0], [:send, :[], 0, nil, 0, nil], # Process.times[0] [:send, :push, 1, nil, 0, nil], [:pop] # レシーバー receiver, [:send, :push, 1, nil, 0, nil], [:pop] # 時間 [:putobject, 0.0], [:send, :push, 1, nil, 0, nil], [:pop]
これを作っていて、Rubyバイトコードオプティマイザが作れないかなと考えました。バイトコードを読み込んで、インライン化や変数アクセスをスタック操作に変換するなどのオプティマイズを行って、バイトコードを出力するプログラムです。Rubyの本体ではRubyの言語仕様の柔軟性から大胆なオプティマイズが出来ないようですが、外付け・自己責任前提プログラムなら大胆な最適化が出来そうです。