簡體   English   中英

如何讓 SBCL 優化掉對 FDEFINITION 的可能調用?

[英]How to make SBCL optimize away possible call to FDEFINITION?

道歉:我沒有足夠的知識將其重新編寫為易於理解的代碼片段。

我一直在使用 SBCL 編譯器注釋作為可以改進的標志,但我對此並不了解——

; compiling (DEFUN EXECUTE-PARALLEL ...)
; file: /home/dunham/8000-benchmarksgame/bench/spectralnorm/spectralnorm.sbcl-8.sbcl
; in: DEFUN EXECUTE-PARALLEL
;     (FUNCALL FUNCTION START END)
; --> SB-C::%FUNCALL THE 
; ==>
;   (SB-KERNEL:%COERCE-CALLABLE-FOR-CALL FUNCTION)
; 
; note: unable to
;   optimize away possible call to FDEFINITION at runtime
; because:
;   FUNCTION is not known to be a function

#+sb-thread
(defun execute-parallel (start end function)
  (declare (type int31 start end))
  (let* ((num-threads 4))
    (loop with step = (truncate (- end start) num-threads)
          for index from start below end by step
          collecting (let ((start index)
                           (end (min end (+ index step))))
                       (sb-thread:make-thread
                        (lambda () (funcall function start end))))
          into threads
          finally (mapcar #'sb-thread:join-thread threads))))

#-sb-thread
(defun execute-parallel (start end function )
  (funcall function start end))

(程序在這里。類似程序的測量在這里。)

讓 SBCL “優化對 FDEFINITION 的可能調用”是否可行,或者編譯器是否注意到解釋而不是機會?

The reason for the possible call to fdefinition is that it doesn't know that function is a function: it might be the name of one: in general it may be a function designator rather than a function. 為了讓編譯器保持安靜,向它解釋它是一個帶有合適類型聲明的 function,即(declare (type function function)) :你只需要聲明它的類型是function

Rainer 是對的:考慮到您正在啟動一個新線程,這有可能成為性能問題。 特別是添加聲明很可能根本沒有區別:

  • 如果沒有聲明,對funcall的調用將被編譯為“檢查 object 的類型:如果它是 function,則調用它; 如果不是,則對其調用fdefinition並調用結果;';
  • 有一個聲明,那么整個 function 看起來像“檢查 object 是一個 function,如果不是...調用函數則發出錯誤信號”。

在這兩種情況下,如果 object 是 function,則有一次類型檢查和一次調用:類型檢查只是在不同的位置。 在第一種情況下,如果 object 只是 function 的名稱,則代碼仍然有效,而通過類型檢查則不會。

在這兩種情況下,這是您關心調用make-thread的代碼:如果這與 function 調用一樣快,即使通過fdefinition我也會對線程系統印象深刻。 幾乎可以肯定,這個 function 的性能完全由創建線程的開銷決定。

在實際代碼中,避免這樣的優化——除非真的需要

讓 SBCL “優化對 FDEFINITION 的可能調用”是否可行,或者編譯器是否注意到解釋而不是機會?

通常這無關緊要,特別是因為大多數 Lisp 代碼應該以優化質量(speed 3) (safety 0) (space 0)編譯,因為它可能會根據實現和使用的程序打開軟件運行時錯誤和崩潰. 除了函數或符號命名函數之外,通過funcall調用未經檢查的事物(沒有safety )可能足以導致程序崩潰。

對於特定的基准測試,可以通過時間檢查類型聲明和專門的fdefinition編譯是否帶來任何優勢。

類型聲明

用於明確名為fn的變量引用 function 類型的function的類型聲明將是:

(declare (type function fn))

在特定的基准程序中,無論如何都不會調用 FDEFINITION

在您提供的示例中,無論如何都不會調用fdefinition

(setf foo (lambda (x) x))       ; foo references a function object

(funcall foo 3)

funcall可能是這樣實現的:

(etypecase f
  ((or cons symbol) (funcall (fdefinition f) ...))
  (function         ...))

由於您的代碼通過了 function object,因此無需調用fdefinition

那么優化的好處將是可以刪除運行時類型分派以及用於缺點或符號情況的死代碼......

你問了一個關於刪除 fdefinition 的問題,但實際上你的問題依賴於一個前提,即 sbcl 注釋是推動優化和改進的好方法。 注釋是發現明顯問題和類型聲明可以提供幫助的地方的好方法。 他們沒有告訴你是什么讓你的程序變慢了。 提高程序性能的正確方法是 1. 想想是否有更快的算法,以及 2. 衡量它的性能並找出慢的地方。

一個單一的 fdefinition 調用只有在它發生在一個緊密的循環中時才有意義(即它不是單一的而是非常復數的)

在這種情況下,它恰好啟動了一個線程。 如果您在緊密循環中啟動線程,那么您的性能問題來自於在緊密循環中啟動線程。 不要那樣做。

如果你沒有在一個緊密的循環中啟動線程(查看你的代碼,你似乎沒有),還有更大的魚要炸。 當您可以優化內部 function 時,為什么要浪費時間在每次調用execute-parallel時可能會被調用 4 次的fdefinition上。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM