このCommonLisp関数は、非常に単純な幼稚園レベルの演算で壁のワイヤーフレームエッジの4つの頂点を単純に計算し、いくつかの「ケース」テストがレンダリングされたフレームごとに196608バイトを動的に割り当てる役割を果たしているようです。SBCLのプロファイラーは、これが私の最も問題のある機能であると言っています。私が取り組んでいることの概要を説明すると、これは小さな一人称ダンジョンクローラーゲームであり、ダンジョンは正確に32x32セルであり、各セルには4つの壁があります。32 * 32 * 4 * x = 196608であるため、xは48になり、これはたまたま4 * 12になります(壁ごとに4つの壁* 12のフロート?多分そうではありません)。
これで、ゲームプレイモードでOpenGLディスプレイリストを使用することで、このパフォーマンスの問題を簡単に軽減できます。これを先に進めて実行すると思います。それでも、1)私は一般的に時期尚早に最適化することはなく、さらに重要なことに2)このような厄介なかゆみを傷つけずに残すのは好きではありません。私の機能は現状のままで、次のとおりです。
(defun calculate-wall-points (x y wall)
(declare (integer x y)
(keyword wall))
"Return the 4 vertices (12 floats) of a given dungeon cell wall"
(let ((xf (coerce x 'float))
(yf (coerce y 'float)))
(case wall
(:SOUTH
(values xf yf 0.0
(1+ xf) yf 0.0
(1+ xf) yf 1.0
xf yf 1.0))
(:WEST
(values xf yf 0.0
xf yf 1.0
xf (1+ yf) 1.0
xf (1+ yf) 0.0))
(:NORTH
(values xf (1+ yf) 0.0
xf (1+ yf) 1.0
(1+ xf) (1+ yf) 1.0
(1+ xf) (1+ yf) 0.0))
(:EAST
(values (1+ xf) (1+ yf) 0.0
(1+ xf) (1+ yf) 1.0
(1+ xf) yf 1.0
(1+ xf) yf 0.0))
(otherwise
(error "Not a valid heading passed for wall in function calculate-wall-points: ~A" wall)))))
私がこれを修正しようとしたいくつかのことを要約すると:
'declare'を実行して'speed'を3に、その他すべてを0に(この関数とそれを呼び出す唯一の関数の両方で)最適化します。不思議なことに、プロファイラーはこの関数の結果をわずかに少なく報告しました...しかしそれでも問題はありません。ゼロコンシングを目指しています。算術は短所であってはなりません。
それから私は「値」がこれをしているのではないかと思いました。おそらく、それは内部的には関数'list'のようなものであり、間違いなくそれを意味します('list'関数は宇宙での唯一の目的です)。これを軽減するために私は何をしましたか?実験のために、ファイルを変更して単一のwall-vertex-bufferを作成しましたグローバル配列、float型の12個の要素に適合するサイズで、この関数を変更して変更し、呼び出し元の関数を変更して、この関数を呼び出した後にそれから読み取ります(したがって、同じに保持されている12個のfloatの1つのセットを常に更新します何かを割り当てる代わりに、メモリに配置します)。不思議なことに、これはこの関数がおしゃべりになるのを止めませんでした!それで...「ケース」はconsingをしていましたか?前述のように、ミステリー番号が48であったことは興味深いと思います。48= 4 * 12、おそらくこれらの4つのケーステストに「値」呼び出しごとに12フロートを掛けたものです。または、それは偶然の一致である可能性があり、48バイトは他の何かを意味します(floatは1バイトではないので、私は-is-何か他のものだと思います)。これは重要なことのように思えますが、次のアプローチがどうあるべきかについて頭を悩ませることはできません。
'case'を'cond'に置き換えようとしましたが、この時点でストローをつかんでも何もしませんでした。
では、この関数の「ミステリー・コンシング」はどこから来ているのでしょうか?より経験豊富なLispプログラマーは、このトリッキーな問題のグレムリンにどのようにアプローチしますか?
(EDIT)@FaheemMithaの場合、calculate-wall-points関数を使用した関数です。その厄介な関数は、calculate-wall-pointsの定義の直前に(declaim(inlinecalculate-wall-points))でインライン化されました。
(defun render-dungeon-room (dungeon-object x y)
(declare (optimize (speed 3) (space 0) (debug 0)))
(declare (type fixnum x y))
(let ((cell (cell-at dungeon-object x y)))
(unless (null cell)
(dolist (wall-heading +basic-headings+)
(unless (eq wall-heading (opposite-heading *active-player-heading*))
(when (eql (get-wall-type cell wall-heading) :NORMAL)
(multiple-value-bind (v1x v1y v1z v2x v2y v2z v3x v3y v3z v4x v4y v4z)
(calculate-wall-points x y wall-heading)
(declare (type float v1x v1y v1z v2x v2y v2z v3x v3y v3z v4x v4y v4z))
(gl:with-primitive :quads
(if (is-edit-mode)
(case wall-heading
(:NORTH
(gl:color 0.4 0.4 0.4))
(:WEST
(gl:color 0.4 0.0 0.0))
(:SOUTH
(gl:color 0.0 0.0 0.4))
(:EAST
(gl:color 0.0 0.4 0.0)))
(gl:color 0.1 0.1 0.1))
(gl:vertex (the float v1x)
(the float v1y)
(the float v1z))
(gl:vertex (the float v2x)
(the float v2y)
(the float v2z))
(gl:vertex (the float v3x)
(the float v3y)
(the float v3z))
(gl:vertex (the float v4x)
(the float v4y)
(the float v4z)))
(gl:color 1.0 1.0 1.0)
(gl:with-primitive :line-loop
(gl:vertex (the float v1x)
(the float v1y)
(the float v1z))
(gl:vertex (the float v2x)
(the float v2y)
(the float v2z))
(gl:vertex (the float v3x)
(the float v3y)
(the float v3z))
(gl:vertex (the float v4x)
(the float v4y)
(the float v4z)))))))))
nil)