2015-09-26 76 views
0

使用Logtalk時,看起來我的程序用Logtalk對象執行比普通Prolog更長。我做了一個標杆純的Prolog與logtalk對象的封裝相當於下面的簡單謂詞的執行比較:Logtalk方法調用性能優化

%% 
% plain prolog predicate 
plain_prolog_simple :- 
    fail. 

%% 
% object encapsulation 
:- object(logtalk_obj). 

    :- public([simple/0]). 
    simple :- 
     fail. 

:- end_object. 

這裏就是我得到:

?- benchmark(plain_prolog_simple). 

Number of repetitions: 500000 
Total time calls: 0.33799099922180176 seconds 
Average time per call: 6.759819984436035e-7 seconds 
Number of calls per second: 1479329.3346604244 
true. 

?- benchmark(logtalk_obj::simple). 

Number of repetitions: 500000 
Total time calls: 2.950408935546875 seconds 
Average time per call: 5.90081787109375e-6 seconds 
Number of calls per second: 169468.0333888435 
true. 

我們可以看到logtalk_obj::simple call慢於plain_prolog_simple通話。 我使用SWI Prolog作爲後端,我試圖設置一些日誌談話標誌,但沒有成功。

編輯:我們可以找到標杆代碼樣本https://github.com/koryonik/logtalk-experiments/tree/master/benchmarks

有什麼不對?爲什麼這種表現差異?如何優化Logtalk方法調用?

回答

2

簡而言之,你的標杆::/2目標Logtalk編譯在頂層解釋器。這是一個經典的基準測試錯誤。頂層的目標,簡單的Prolog目標,模塊明確定義的謂詞目標,或者消息發送目標總是要被解釋,即時編譯。

您可以在編譯的源文件中獲得性能接近普通Prolog的郵件發送目標,這是最常見的情況。請參閱Logtalk發行版中的benchmarks示例,以瞭解避免上述陷阱的基準測試解決方案。

性能差距(普通的Prolog和Logtalk目標之間)取決於所選的後端Prolog編譯器。當可以進行靜態綁定時,成熟的Prolog VM(例如SICStus Prolog或ECLiPSe)可以忽略該差距。然而,一些Prolog虛擬機(例如SWI-Prolog)缺少一些可以使間隙更大的優化,特別是在緊密循環中。

P.S. Logtalk是一款開箱即用的設置配置,而不是性能。請特別參閱有關optimize標誌的文檔,該標誌應打開以進行靜態綁定優化。

UPDATE

從您的存儲庫中的代碼開始,並假設SWI-Prolog的作爲後端的編譯器,嘗試:

----- code.lgt ----- 
% plain prolog predicate 
plain_prolog_simple :- 
    fail. 

% object encapsulation 
:- object(logtalk_obj). 

    :- public(simple/0). 
    simple :- 
     fail. 

:- end_object. 
-------------------- 

----- bench.lgt ----- 
% load the SWI-Prolog "statistics" library 
:- use_module(library(statistics)). 

:- object(bench). 

    :- public(bench/0). 
    bench :- 
     write('Plain Prolog goal:'), nl, 
     prolog_statistics:time({plain_prolog_simple}). 
    bench :- 
     write('Logtalk goal:'), nl, 
     prolog_statistics:time(logtalk_obj::simple). 
    bench. 

:- end_object. 
--------------------- 

保存這兩個文件,然後啓動Logtalk:

$ swilgt 
... 
?- set_logtalk_flag(optimize, on). 
true. 

?- {code, bench}. 
% [ /Users/pmoura/Desktop/bench/code.lgt loaded ] 
% (0 warnings) 
% [ /Users/pmoura/Desktop/bench/bench.lgt loaded ] 
% (0 warnings) 
true. 

?- bench::bench. 
Plain Prolog goal: 
% 2 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 125000 Lips) 
Logtalk goal: 
% 2 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 285714 Lips) 
true. 

謂詞time/1是一個元謂詞。 Logtalk編譯器使用meta-predicate屬性來編譯time/1參數。 {}/1控制結構是一個Logtalk編譯器旁路。它確保它的參數在普通的Prolog數據庫中按原樣調用。

+0

謝謝,真的。你說「爲了編譯源文件中的消息發送目標而使性能接近普通Prolog」,但是如何從swilgt('log talk_load/2-3'只能在編譯時編譯)進行編譯? – Koryonik

+0

'logtalk_load/1-2'既可以編譯和加載源文件(對於'logtalk_load/1',您可以在頂層使用上面示例中的{{}/1'快捷鍵)。解釋頂層的任何調用,但隻影響調用謂詞的性能,而不影響謂詞。 –

0

一個標杆技巧與SWI-Prolog的和YAP(可能還有其他),提供一個time/1元謂詞是使用這個謂詞Logtalk的<</2調試控制結構和內置對象的logtalk工作。使用SWI-Prolog的作爲後臺編譯:

?- set_logtalk_flag(optimize, on). 
... 
?- time(true). % ensure the library providing time/1 is loaded 
... 
?- {code}. 
... 
?- time(plain_prolog_simple). 
% 2 inferences, 0.000 CPU in 0.000 seconds (59% CPU, 153846 Lips) 
false. 
?- logtalk<<(prolog_statistics:time(logtalk_obj::simple)). 
% 2 inferences, 0.000 CPU in 0.000 seconds (47% CPU, 250000 Lips) 
false. 

快速解釋,<</2控制結構調用前編譯的目標參數。由於optimize標誌已打開且time/1是元謂語,因此其參數已完全編譯,並且靜態綁定用於發送消息。因此,我們得到的推理數量相同。因此,這個技巧允許您在Logtalk消息發送目標的頂層進行快速基準測試。

使用YAP類似但更簡單,因爲time/1是一個內置的元謂語,而不像SWI-Prolog中的元元謂語。