在玩Logtalk的时候,我的程序似乎要更长时间来执行Logtalk对象而不是普通的Prolog。我做了一个基准测试,将平原Prolog中简单谓词的执行与下面等效的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方法调用?
发布于 2015-09-26 17:22:39
简而言之,您正在顶层解释器上对目标的Logtalk编译进行基准测试。这是一个典型的基准错误。顶层的目标,即简单的Prolog目标、模块明确限定的谓词目标或消息发送目标,总是会被解释,即动态编译。
在编译的源文件中,对于消息发送目标,性能接近于普通Prolog,这是最常见的场景。有关避免上述陷阱的基准测试解决方案,请参阅Logtalk发行版中的benchmarks示例。
性能差距(普通Prolog和Logtalk目标之间)取决于选择的后端Prolog编译器。对于成熟的Prolog (例如SICStus、Prolog或ECLiPSe)来说,当静态绑定是可能的时候,这种差距是可以忽略的。但是,一些Prolog VM(例如SWI)缺乏一些可以使差距更大的优化,特别是在紧环中。
P.S.Logtalk提供了用于开发的设置配置,而不是性能配置。尤其请参阅optimize标志上的文档,对于静态绑定优化,应该打开该标记。
更新
从存储库中的代码开始,假设Starting作为后端编译器,尝试:
----- 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编译器使用元谓词属性编译time/1参数。{}/1控件构造是Logtalk编译器旁路。它确保其参数在普通Prolog数据库中被调用为- is。
发布于 2016-05-20 11:01:05
用于提供time/1元谓词的SWI和YAP (可能还有其他)的基准测试技巧是,将该谓词与Logtalk的<</2调试控件构造和logtalk内置对象一起使用。使用SWI作为后端编译器:
?- 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是内置的元谓词,而不是simpler中的库元谓词。
发布于 2018-06-09 13:19:17
您还可以为非常快速的面向对象提供解释器。Jekejeke有一个纯解释的(::)/2操作符。到目前为止,头顶上没有太多的开销。这是测试代码:
Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland
?- [user].
plain :- fail.
:- begin_module(obj).
simple(_) :- fail.
:- end_module.这是一些实际的结果。普通调用与基于(::)/2操作符的调用之间没有太大的差别。在掩码下,两个谓词查找都是内联缓存的:
?- time((between(1,500000,_), plain, fail; true)).
% Up 76 ms, GC 0 ms, Thread Cpu 78 ms (Current 06/23/18 23:02:41)
Yes
?- time((between(1,500000,_), obj::simple, fail; true)).
% Up 142 ms, GC 11 ms, Thread Cpu 125 ms (Current 06/23/18 23:02:44)
Yes我们仍有一笔可能在将来取消的间接费用。必须这样做,我们仍然为每个(::)/2调用做了一个小型重写。但也许这件事已经过去了,我们正在努力。
编辑23.06.2018:我们现在有一个内置的/3之间,并且已经实现了一些优化。上面的数字显示了这一新的原型的预览,但还没有出来。
https://stackoverflow.com/questions/32799458
复制相似问题