[前][次][番号順一覧][スレッド一覧][生データ]

yarv-dev:354

From: SASADA Koichi <ko1 atdot.net>
Date: Tue, 7 Dec 2004 09:50:42 +0900
Subject: [yarv-dev:354] Stack caching

 ささだです。

 スタックキャッシングを実装してみました。

 2レベルのスタックキャッシュで次の状態を遷移しながら実行して
いきます。

xx: キャッシュに乗っていない
ax: レジスタ a にキャッシュとして乗っている
bx: レジスタ b にキャッシュとして乗っている
ab: レジスタ a, b にキャッシュとして乗っている b がトップ
ba: レジスタ a, b にキャッシュとして乗っている a がトップ

 たとえば、ローカル変数を取得する命令 getlocal が、ax の状態
で実行されると、一個スタックを上に積むわけですから、ab の状態
に遷移します。取得したローカル変数の値はキャッシュレジスタ b
に格納されます。


 これも、命令記述から吐くようにしたんですが。VC の -O2g- では
非常に大きな効果を上げました。

 しかし、gcc の -O2 や VC の -O2 では、遅くなりました。

 今日もさっぱり理由がわかりません。というか、今日のほうがわか
りません。

 試したプログラムは次のとおりです。

i=0
while i<10000000
  i+=1
end

 コンパイルすると、次のようになります。

0000 putobject_opopt_INT2FIX_OP_0_CP_
0001 setlocal_opopt_2
0002 getlocal_opopt_2
0003 putobject       10000000
0005 opt_lt
0006 unless          14
0008 getlocal_opopt_2
0009 putobject_opopt_INT2FIX_OP_1_CP_
0010 opt_plus
0011 setlocal_opopt_2
0012 jump            2
0014 putnil
0015 end             4

 スタックキャッシュを有効にすると、次のようになります。

0000 putobject_opopt_INT2FIX_OP_0_CP__SC_xx_ax
0001 setlocal_opopt_2_SC_ax_xx
0002 getlocal_opopt_2_SC_xx_ax
0003 putobject_SC_ax_ab  10000000
0005 opt_lt_SC_ab_ax
0006 unless_SC_ax_xx 14
0008 getlocal_opopt_2_SC_xx_ax
0009 putobject_opopt_INT2FIX_OP_1_CP__SC_ax_ab
0010 opt_plus_SC_ab_ax
0011 setlocal_opopt_2_SC_ax_xx
0012 jump_SC_xx_xx   2
0014 putnil_SC_xx_ax
0015 end_SC_ax_xx    4

 コンパイルした結果と見比べたりしてみましたが、スタックキャッ
シュを有効にしたほうが、明らかに命令数が少ないのです。

例:

gcc の出力したアセンブラ:

putobject_SC_ax_ab
	 # basic block 939
	movl	-296(%ebp), %ecx
	movl	4(%ecx), %eax     # ax = operand(1)
	addl	$8, %ecx          # #
	movl	%ecx, -296(%ebp)  # pc += 8
	movl	%eax, -324(%ebp)  # cache_regB = ax
	movl	(%ecx), %eax      # nextpc_ptr = *pc
	jmp	*%eax             # goto nextpc_ptr


putobject
	 # basic block 1309
	movl	-296(%ebp), %ecx  #
	movl	4(%ecx), %eax     # ax = operand(1)
	addl	$8, %ecx          # #
	movl	%ecx, -296(%ebp)  # pc store
	movl	-300(%ebp), %ebx  # #
	movl	%eax, (%ebx)      # *sp = ax
	addl	$4, %ebx          # #
	movl	%ebx, -300(%ebp)  # sp += 4
	movl	(%ecx), %eax      # nextpc_ptr = *pc
	jmp	*%eax             # goto nextpc_ptr


 ちなみに、見てわかるとおり、キャッシュ用レジスタ変数はマシン
レジスタではなく、スタック上に割り付けられています。


 だいたい、どの命令もこんな感じで命令数が少ないのですが、なぜ
か遅いです。(SC: スタックキャッシング)

gcc => SC あり: 1.765000 SC なし: 1.640000
VC  => SC あり: 1.016000 SC なし: 0.750000 (-Ox)

 VC が顕著に遅くなってます。

 はて、なんででしょうか? ほんと全然見当が付きません。

 あとは、Intel CPU のマイクロ命令への変換の過程でどうの、くら
いしか思いつきません。つまり、利用するローカル変数が多いと
Intel CPU は遅くなるとか?

 もしくは、ちょうどぴったりキャッシュラインが不幸にも一致して
しまったとか、ちょうどぴったりベンチマーク時、システム全体の負
荷が SC 有効時に高かったりとか(ありえねー)。


 ちなみに、「SC なし」とは、コンパイル時に SC 命令列に変換し
ないだけで、VM のループの中には命令はぎっしり詰まっています。
だから、icache がどうの、とかは違うと思う。命令の並び順かなー
とか考えて、並び替えてみたんですが、同様でしたし。


 何か思いつく方いらっしゃいますか?

-- 
// SASADA Koichi at atdot dot net
//


--
ML: yarv-dev quickml.atdot.net
使い方: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧][生データ]

->     354 2004-12-07 09:50 [ko1 atdot.net       ] Stack caching                           
       355 2004-12-07 10:10 ┣[ko1 atdot.net       ]                                       
       356 2004-12-07 10:46 ┣[shudo computer.org  ]                                       
       358 2004-12-07 13:43 ┃┗[ko1 atdot.net       ]                                     
       357 2004-12-07 10:57 ┗[maeda-yarv atusi.org]                                       
       359 2004-12-07 13:52  ┗[ko1 atdot.net       ]