這個Common Lisp函數簡單地用極簡單的幼兒園級算術和幾個'case'測試來計算牆壁線框邊緣的四個頂點,這似乎是每個渲染幀動態分配196608字節的原因; SBCL的分析人員告訴我,這是我的問題最重要的功能。爲了大致瞭解我的工作,它是一個小型的第一人稱地下城爬蟲遊戲,地牢正好是32x32的單元格,每個單元格有4個牆。 32 * 32 * 4 * x = 196608,所以x最終爲48,這恰好是4 * 12(4面牆* 12每面牆漂浮物?也許不是)。消除此Common Lisp函數中的「神祕感」?
現在,我可以輕鬆地通過在遊戲模式下使用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)))))
總結出幾件事情我已經嘗試了這一點:
做一個「聲明」到「優化」的「速度」在3和其他所有的0(在這個函數,以及唯一的函數調用它)。奇怪的是,剖析器確實報告這個函數稍微少一點......但它仍然coninc。我的目標是零負擔。算術不應該缺點。
然後我認爲'價值觀'可能會這樣做。也許,我想,它在內部就像函數'list',毫無疑問,它是conses('list'函數在宇宙中的唯一目的)。我做了什麼努力來減輕這一點?僅僅爲了實驗的緣故,我修改了文件來製作一個單一的牆頂點緩衝區全局數組,大小適合浮點類型12個元素,並且修改了這個函數來修改它,並且調用函數在它之後讀取它調用這個函數(所以它會不斷地更新保存在內存中同一個地方的一組12個浮點數,而不是分配任何東西)。奇怪的是,這並沒有阻止這個功能成爲吝嗇鬼!那麼...是'情況'在做什麼?我覺得有趣的是,前面提到的神祕數字是48.48 = 4 * 12,也許這4個案例測試每個'價值'調用乘以12個浮點數。或者,這可能是一個巧合,48字節意味着別的東西(因爲浮點數不是1個字節,我懷疑是其他的東西)。這似乎很重要,但我不能完全理解我的下一個方法應該是什麼。
試圖用'cond'替代'case',只是在這一點上抓住吸管,也沒有做任何事情。
那麼這個函數的「神祕感」來自哪裏呢?你如何更有經驗的Lisp程序員接近這個棘手的問題?
(EDIT)for @FaheemMitha,是使用計算壁點函數的函數;麻煩的功能,後來用內聯(朗誦(在線計算牆點))之前計算壁點的定義:
(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)))))))))
無)
謝謝生成 - 我從來沒有懷疑浮點數,所有的東西,是罪魁禍首(我抓到足夠紅鯡魚打開海鮮餐廳)。現在知道什麼更好找,我挖掘了SBCL的手冊,並且提到聲明這樣的「內聯」浮動函數會產生更好的性能。這似乎工作;現在在這個函數中還有調用函數(我認爲這個調用函數現在被內部融合到相同的函數中,編譯後),這個調用函數現在是零。 – valq
@valq:嗨。我感興趣的是你做了什麼來阻止函數的細節。您可以發佈您的優化前代碼和後期優化代碼的示例,無論是在問題中還是作爲單獨的答案?謝謝。 –
@FaheemMitha在做了一個(declaim(inline calculate-wall-points))之後,我記得我看到,在它和使用(使用)它的函數之間的剖析器中,重要性低得多。我將把代碼發佈到在單獨的答案中使用它的函數中。我不知道你是否需要更多的代碼來混淆它,因爲它還引用了超出其範圍的幾個函數和全局變量。 – valq