MATSUZAKIの日記 RSSフィード

Back to Peppermint.jp

2010-09-08

HSPをJIT実行

ようやくraytraceが1.7倍速くらいで動くようになった。

http://peppermint.jp/products/hsp/

http://github.com/zakki/openhsp/tree/jit


まんまhsp3cnvと同じだとインタプリタ実行と等速か若干遅いくらいなので、次のあたりを実装した。

  • 実行時にトレースしつつ型をチェックする
  • 型が一定ならスタック操作を経由せずに四則演算やロード・ストアを直接計算する
  • ローカル変数として使われている変数を検出してメモリアクセスをサボる

パフォーマンス的に効きそうな項目も結構残ってる。

完全に変数の型を解析してかつグローバルに最適化かけられれば10倍速くらいで動いてもいいはずなんだよなー

  • hsp3cnv由来で関数引数が値渡しで済むはずの箇所も参照渡ししている
  • (関数で無い)コマンドはそのまま
  • 自動型変換が必要な箇所は以前hspvarにまかせている
  • ベーシックブロック単位でしか処理していない

あと、機能的にユーザー定義関数モジュールが使えないのが痛い。

HSPの1行が

 d = 1.0 / os.hit

次のようなLLVM-IRになって

  %ptr = load i8** getelementptr inbounds (%struct.PVal* @Var__HspVar43, i32 0, i32 4) ; <i8*> [#uses=1]
  %0 = bitcast i8* %ptr to i32*                   ; <i32*> [#uses=1]
  %1 = load i32* %0                               ; <i32> [#uses=1]
  %ptr1 = load i8** getelementptr inbounds (%struct.PVal* @Var__HspVar13, i32 0, i32 4) ; <i8*> [#uses=1]
  %2 = bitcast i8* %ptr1 to double*               ; <double*> [#uses=1]
  call void @HspVarCoreReset(%struct.PVal* @Var__HspVar13)
  call void @HspVarCoreArray2(%struct.PVal* @Var__HspVar13, i32 %1)
  %offset = load i32* getelementptr inbounds (%struct.PVal* @Var__HspVar13, i32 0, i32 8) ; <i32> [#uses=1]
  %3 = getelementptr double* %2, i32 %offset      ; <double*> [#uses=1]
  %4 = load double* %3                            ; <double> [#uses=1]
  %5 = fdiv double 1.000000e+000, %4              ; <double> [#uses=1]
  %ptr2 = load i8** getelementptr inbounds (%struct.PVal* @Var__HspVar71, i32 0, i32 4) ; <i8*> [#uses=1]
  %6 = bitcast i8* %ptr2 to double*               ; <double*> [#uses=1]
  store double %5, double* %6

最終的にx86命令に落ちると

	movl	_Var__HspVar43+28, %eax
	movl	(%eax), %esi
	movl	_Var__HspVar13+28, %edi
	movl	$_Var__HspVar13, (%esp)
	call	_HspVarCoreReset
	movl	%esi, 4(%esp)
	movl	$_Var__HspVar13, (%esp)
	call	_HspVarCoreArray2
	movsd	LCPI89_0, %xmm0
	movl	_Var__HspVar13+40, %eax
	divsd	(%edi,%eax,8), %xmm0
	movl	_Var__HspVar71+28, %eax
	movsd	%xmm0, (%eax)

Cに比べるとだいぶ無駄がある。ループのフロー見て配列の自動拡張必要ないことを特定できれば真ん中の当たりは消せるな。

2009-07-16

and演算子

HSPは&も&&もandもビットごとの論理積でしかなくて、短絡評価してくれないことにいまさら気づく。

やっぱ、ふつーのプログラマがふつーにコード書くには罠多いな。

HSPletのFile I/O

もしかしてJava6u10からのJNLP使うようにすれば、dialog命令で選択したファイル限定ならローカル読み書きできる?

2009-03-24

HSPLetでも AO bench

aobenchの続き。

HSPLetに通してみたらローカル変数のサポートが無かったので適当にでっちあげる。

http://peppermint.jp/products/hsp/hsplet-localvar.patch

関数呼び出しでスタックを積まず再帰はサポートしないって条件のようなのでローカル変数を含めた引数全部をあらかじめフィールドとして全部作っておくように。

http://peppermint.jp/products/hsp/ao.html

同じ環境のJava6で76.8sec

2009-03-23

HSPでAO bench

f:id:MATSUZAKI:20090323235616p:image

http://lucille.atso-net.jp/aobench/のコードをHSPに移植してみた。

http://peppermint.jp/products/hsp/ao.hsp

Core2Duo E6850 3GHzで259秒。スクリプト言語的には普通の遅さのよう。

ローカル変数や#deffunc/#defcfunc使わずに全部グローバル変数とgosubで頑張ればもうちょい早くはなりそう。

それはともかく機械生成でデータ込み数千行みたいなのを除けば、初めてHSPで300行越えのコードを書いたけど構造化したりスコープ切ったりするやりかたがよく分からない。

各種命令の使い方やAPIの呼び出し方みたいな解説ページはいっぱいあるんだけど、プログラムの構成の仕方みたいな解説はどこをみればいいんだろう。

2009-03-20

hsp3cnv

半年遅れぐらいだけど、http://dev.onionsoft.net/trac/browser/trunk/hsp3cnv をいじってみる。

extvarへのアクセスと配列の自動拡張対応追加で

http://taillove.jp/mia/のraytracing.hspとかは動くようになった。

ベンチマークとしてレイトレーシングで1回レンダリングするのにかかった時間を図ってみると。

  • hsp3.1(オフィシャルで配布されてるもの)

20sec

  • hsp3.2 svn head(/Ox&リンク時のコード生成を使用)

17.7sec

  • hsp3cnv + hsp3rtest(/Ox&リンク時のコード生成を使用)

15.1sec

  • hsp3cnv + hsp3rtest(/O2&リンク時のコード生成なし)

28sec

hsp3cnvが吐くC++のコードはほぼ関数呼び出しだけなのでC++コンパイラ経由せずにネイティブコード生成してJITコンパイラとして使えるようにするのにさほど無茶な手間はかからない気がするけど、上の結果見る限りパフォーマンス向上が得られるかっていうと微妙そう。