yarv-dev:346
From: SASADA Koichi <ko1 atdot.net>
Date: Mon, 6 Dec 2004 07:34:52 +0900
Subject: [yarv-dev:346] Operand unification
ささだです。 どうにもわからない現象が起こってしましました。お知恵を拝借できれば幸 いです。 オペランドを統合して1命令にする実験をしていました。たとえば、スタッ ク上に true を push する命令は、通常は putobject true になりますが、これを統合して putobject_true という1命令にすれば、オペランドのフェッチのコストが下がります。 これを簡単に行うため、これを自動的に行えるようにしました。具体的には 「ある命令」について「どのオペランドを統合するか」を指定することで、 「その統合した命令の C の記述」と「コンパイル時自動的にその命令に変換 するためのオプティマイザ」を生成するように しました。 input: * 統合する命令 * 統合するオペランド output: * その命令を利用するコードに変換するコンパイラ(オプティマイザ) * その命令の C での記述 まぁこれは実際簡単に作れるんですが、こういうものを作っておけば、手軽 に試せるかなぁと思ったわけです。 で、これを実際に試してみたところ、不思議な現象が起こりました。 意に反して、命令統合を行った場合のほうが速度が遅くなってしまったので す。(なぜ語り口調) 結構期待していたんですが、がっかりです。(まだ語り口調) 理由を推測しました。 * 命令数が多くなったため、I-Cache から追い出された * 複数のVM命令がひとつのコードを共有していたとき、そのジャンプが 相対ジャンプの量を超えた(IA32 って、遠くへ飛ぼうとすると、実行 コストが増えますよね) そこで、自暴自棄になった私は、無駄な命令をどんどん突っ込んでみること にしました。つまり、ある命令 A があったとき、A_1 、A_2、...のように、 違う名前で同じ命令をどんどん突っ込んでみたのです(具体的には、ひとつの 命令につき、10 の無駄な命令を作りました)。ただし、無駄な命令は、何も 動作しない命令にしてみました(本当は、複製を複数作ろうとしたのだけれ ど、プログラムをミスって(ボディ部を複製するのを忘れていて)エントリポ イントだけになりました。replication も試してみたかったんですが)。する とどうしたことでしょう。gcc でコンパイルした結果が、非常に高速になった ではありませんか。(しつこいか) これは、gcc の場合だけだったのですが(VCではならず)、非常に不思議で す。命令統合については、残念ながら、あんまり芳しい結果にはならなかった のですが(でも、この命令を増やした後では少し速くなる(1.27 -> 1.17 (sec)))、命令を凄く増加させることで、かなりの高速化が果たせました (1.53->1.27(sec))。 かなり不思議です。 現象をまとめます。 ・環境:Celeron1.4Ghz, 256MB memory, Win2000, cygwin/gcc 3.3.3 ・命令を10倍ほどに多くするとけっこう性能が良くなった ・命令を10倍ほどに多くすると命令統合の効果が出た ・命令の中身は空(エントリポイントのみで、PCを進めるだけ) いくつか原因を考えてみました。 * I-Cache のラインがうまい具合に乗るようになった(可能性低) * GCC のスレッデッドコードが、なぜかよりよいものになった * ラベルが多すぎるので、GCC がコードを共有するのを諦めたらよりよい コードを生成した どうにもわかりません。 アセンブラを眺めればわかったりするんでしょうか。しかし、1関数がでか い(2000行くらいの C のコード)ので、あんまり見たくないなあ。 * この理由 * この理由を調査する方法 * アセンブラを見る方法、とくに C のある部分と照らし合わせながら を知っていれば・思いついたら教えてください。 ちなみに、きちんとボディ部も複製すると、1.5 sec。遅くはなってない が、速くもなってない。 -- // SASADA Koichi at atdot dot net // もうちょっと参考: so_ackermann: #!/usr/bin/ruby # -*- mode: ruby -*- # $Id: ackermann-ruby.code,v 1.4 2004/11/13 07:40:41 bfulgham Exp $ # http://www.bagley.org/~doug/shootout/ def ack(m, n) if m == 0 then n + 1 elsif n == 0 then ack(m - 1, 1) else ack(m - 1, ack(m, n - 1)) end end NUM = 7 ack(3, NUM) -- user system total real ruby 3.969000 0.078000 4.047000 ( 4.082000) yarv 0.328000 0.000000 0.328000 ( 0.331000) # 何もしない yarv 0.265000 0.000000 0.265000 ( 0.273000) # 命令増加+統合 -- ML: yarv-dev quickml.atdot.net 使い方: http://www.atdot.net/~ko1/quickml
-> 346 2004-12-06 07:34 [ko1 atdot.net ] Operand unification 347 2004-12-06 08:55 ┣[ko1 atdot.net ] 348 2004-12-06 09:06 ┣[matz ruby-lang.org ] 349 2004-12-06 09:10 ┃┗[ko1 atdot.net ] 350 2004-12-06 11:25 ┗[shudo computer.org ] 351 2004-12-06 16:47 ┗[ko1 atdot.net ]