Compilation 公共Lisp编译和执行时间

Compilation 公共Lisp编译和执行时间,compilation,lisp,common-lisp,Compilation,Lisp,Common Lisp,我有一个lisp文件,它在循环中执行大量采样、文件I/O和算术运算。(我使用common lisp)我正在使用compile file命令编译我的lisp文件。我还使用lisp文件开头的(declaim(优化(速度3)(调试0)(安全0)),因为我希望尽快得到结果。 我使用(time(load)/myfile.lisp)和(time(load)/myfile.dx64fsl)衡量速度。问题是编译没有给我带来任何好处。没有任何改进。我做错了什么吗?有什么方法可以改进吗?速度是最重要的标准,所以我可

我有一个lisp文件,它在循环中执行大量采样、文件I/O和算术运算。(我使用common lisp)我正在使用
compile file
命令编译我的lisp文件。我还使用lisp文件开头的
(declaim(优化(速度3)(调试0)(安全0))
,因为我希望尽快得到结果。
我使用
(time(load)/myfile.lisp)和
(time(load)/myfile.dx64fsl)
衡量速度。问题是编译没有给我带来任何好处。没有任何改进。我做错了什么吗?有什么方法可以改进吗?速度是最重要的标准,所以我可以牺牲很多来获得快速响应。我不知道这类问题,所以希望能得到任何帮助。
此外,当我将粒子数(每个粒子是一个大小约为40的向量)增加到10000个时,代码会变得非常慢,因此也可能存在一些内存问题。
事先非常感谢

编辑:这是1000个粒子和50次迭代的分析结果

(LOAD "/.../myfile.dx64fsl") took 77,488,810 microseconds (77.488810 seconds) to run 
                    with 8 available CPU cores.
During that period, 44,925,468 microseconds (44.925470 seconds) were spent in user mode
                    32,005,440 microseconds (32.005440 seconds) were spent in system mode
2,475,291 microseconds (2.475291 seconds) was spent in GC.
 1,701,028,429 bytes of memory allocated.
 1,974 minor page faults, 0 major page faults, 0 swaps.
; Warning: Function CREATE-MY-DBN has been redefined, so times may be inaccurate.
;          MONITOR it again to record calls to the new definition.
; While executing: MONITOR::MONITOR-INFO-VALUES, in process repl-thread(10).


                                                               Cons   
                             %      %                          Per      Total     Total
Function                    Time   Cons    Calls  Sec/Call     Call     Time      Cons
------------------------------------------------------------------------------------------
SAMPLE:                    25.61   26.14  2550000  0.000005      174    13.526   443040000
DISCRETE-PARENTS:          19.66    3.12  4896000  0.000002       11    10.384    52800000
LINEAR-GAUSSIAN-MEAN:       8.86    3.12  1632000  0.000003       32     4.679    52800000
DISCRETE-PARENT-VALUES:     7.47   12.33  3264000  0.000001       64     3.946   208896000
LIST-DIFFERENCE:            6.41   25.69  6528000  0.000001       67     3.384   435392000
CONTINUOUS-PARENTS:         6.33    0.00  1632000  0.000002        0     3.343           0
PF-STEP:                    5.17    0.23       48  0.056851    80080     2.729     3843840
CONTINUOUS-PARENT-VALUES:   4.13    7.20  1632000  0.000001       75     2.184   122048000
TABLE-LOOKUP:               3.85    8.39  2197000  0.000001       65     2.035   142128000
PHI-INVERSE:                3.36    0.00  1479000  0.000001        0     1.777           0
PHI-INTEGRAL:               3.32    1.38  2958000  0.000001        8     1.755    23344000
PARENT-VALUES:              2.38   10.65  1122000  0.000001      161     1.259   180528016
CONDITIONAL-PROBABILITY:    1.41    0.00   255000  0.000003        0     0.746           0
------------------------------------------------------------------------------------------
TOTAL:                     97.96   98.24  30145048                       51.746  1664819856
Estimated monitoring overhead: 21.11 seconds
Estimated total monitoring overhead: 23.93 seconds
使用10000个粒子和50次迭代:

(LOAD "/.../myfile.dx64fsl") took 809,931,702 microseconds (809.931700 seconds) to run 
                    with 8 available CPU cores.
During that period, 476,627,937 microseconds (476.627930 seconds) were spent in user mode
                    328,716,555 microseconds (328.716550 seconds) were spent in system mode
54,274,625 microseconds (54.274624 seconds) was spent in GC.
 16,973,590,588 bytes of memory allocated.
 10,447 minor page faults, 417 major page faults, 0 swaps.
; Warning: Funtion CREATE-MY-DBN has been redefined, so times may be inaccurate.
;          MONITOR it again to record calls to the new definition.
; While executing: MONITOR::MONITOR-INFO-VALUES, in process repl-thread(10).


                                                               Cons    
                             %      %                          Per       Total     Total
Function                    Time   Cons    Calls  Sec/Call     Call      Time      Cons
-------------------------------------------------------------------------------------------
SAMPLE:                    25.48   26.11  25500000  0.000006       174   144.211  4430400000
DISCRETE-PARENTS:          18.41    3.11  48960000  0.000002        11   104.179   528000000
LINEAR-GAUSSIAN-MEAN:       8.61    3.11  16320000  0.000003        32    48.751   528000000
LIST-DIFFERENCE:            7.57   25.66  65280000  0.000001        67    42.823  4353920000
DISCRETE-PARENT-VALUES:     7.50   12.31  32640000  0.000001        64    42.456  2088960000
CONTINUOUS-PARENTS:         5.83    0.00  16320000  0.000002         0    32.980           0
PF-STEP:                    5.05    0.23       48  0.595564    800080    28.587    38403840
TABLE-LOOKUP:               4.52    8.38  21970000  0.000001        65    25.608  1421280000
CONTINUOUS-PARENT-VALUES:   4.25    7.19  16320000  0.000001        75    24.041  1220480000
PHI-INTEGRAL:               3.15    1.38  29580000  0.000001         8    17.849   233440000
PHI-INVERSE:                3.12    0.00  14790000  0.000001         0    17.641           0
PARENT-VALUES:              2.87   10.64  11220000  0.000001       161    16.246  1805280000
CONDITIONAL-PROBABILITY:    1.36    0.00  2550000  0.000003         0     7.682           0
-------------------------------------------------------------------------------------------
TOTAL:                     97.71   98.12  301450048                       553.053  16648163840
Estimated monitoring overhead: 211.08 seconds
Estimated total monitoring overhead: 239.13 seconds
有几点:

  • 如果可能的话,尝试将文件I/O移出循环;在迭代之前批量将数据读入内存。文件I/O比内存访问慢几个数量级

  • 如果执行速度对您很重要,请尝试

  • 输入增加十倍会导致执行时间增加大约十倍,这是线性的,所以您的算法看起来很好;只需要处理常量因子

  • 利用Lisp工作流程:编辑函数、编译函数和测试运行,而不是编辑文件、编译文件和测试。当您的项目变得更大时(或者当您尝试SBCL时,需要更长的时间来分析/优化您的程序以生成更快的代码),差异会变得明显

  • 首先,永远不要在顶级(即全局)声明
    (speed 3)
    (safety 0)
    。这迟早会回来咬你的头。在这些级别上,大多数常见的lisp编译器比C编译器做的安全检查要少。对于instnace,一些lisp放弃检查
    中的中断信号(安全0)
    代码。接下来,
    (安全0)
    很少有显著的收益。我会在热函数中声明
    (速度3)(安全1)(调试1)
    ,如果这带来显著的收益,可能会转到
    (调试0)

    否则,如果不实际查看一些实际代码,就很难提出建议。从time()看,GC压力似乎有点高。确保在热函数中使用开放编码算法,并且不要不必要地使用框浮点或int。使用
    (反汇编“我的昂贵函数”)
    仔细查看编译器生成的代码。SBCL将在高速编译时提供大量有用的输出,尝试消除其中一些警告是值得的

    使用快速数据结构表示粒子也很重要,如果需要,可以使用可实例化的数组和宏。欢迎使用Clozure Common Lisp 1.7-r14925M(DarwinX8664)!
    Welcome to Clozure Common Lisp Version 1.7-r14925M  (DarwinX8664)!
    ? (inspect 'print)
    [0]     PRINT
    [1]     Type: SYMBOL
    [2]     Class: #<BUILT-IN-CLASS SYMBOL>
            Function
    [3]     EXTERNAL in package: #<Package "COMMON-LISP">
    [4]     Print name: "PRINT"
    [5]     Value: #<Unbound>
    [6]     Function: #<Compiled-function PRINT #x30000011C9DF>
    [7]     Arglist: (CCL::OBJECT &OPTIONAL STREAM)
    [8]     Plist: NIL
    
    Inspect> (defun test (x) (+ x 1))
    TEST
    Inspect> (inspect 'test)
    [0]     TEST
    [1]     Type: SYMBOL
    [2]     Class: #<BUILT-IN-CLASS SYMBOL>
            Function
    [3]     INTERNAL in package: #<Package "COMMON-LISP-USER">
    [4]     Print name: "TEST"
    [5]     Value: #<Unbound>
    [6]     Function: #<Compiled-function TEST #x302000C5EFFF>
    [7]     Arglist: (X)
    [8]     Plist: NIL
    Inspect> 
    
    ?(检查“打印件”) [0]打印 [1] 类型:符号 [2] 类别:# 作用 [3] 外包装:# [4] 打印名称:“打印” [5] 价值:# [6] 功能:# [7] Arglist:(CCL::对象和可选流) [8] 普利斯特:零 检查>(除雾试验(x)(+x 1)) 试验 检查>(检查“测试”) [0]测试 [1] 类型:符号 [2] 类别:# 作用 [3] 包装内部:# [4] 打印名称:“测试” [5] 价值:# [6] 功能:# [7] Arglist:(X) [8] 普利斯特:零 检查>
    请注意,#“print”和#“test”都列为“compiled”。这意味着加载.lisp文件和加载编译文件之间唯一的性能差异是编译时间。我假设编译时间不是您场景中的瓶颈。通常不是,除非您使用大量宏,并且执行代码转换不是瓶颈他是你计划的主要目的

    这是我从不处理已编译的lisp文件的主要原因之一。我只需在核心文件中加载我需要的所有共享库/包,然后在处理特定项目时加载一些特定的.lisp函数/文件。而且,至少对于我来说的SBCL和CCL,所有内容都列为“已编译”。

    “myfile.lisp”中包含的代码是进行计算的部分,不,编译该文件不会显著提高运行时。这两种情况之间的区别可能是“我们编译了几个循环”,调用在这两种情况下编译或解释的函数

    为了从编译中获得改进,您还需要编译调用的代码。您可能还需要为代码键入注释,以使编译器能够更好地优化。SBCL对遗漏的注释有很好的编译器诊断功能(人们抱怨编译时太冗长)


    就加载时间而言,加载一个编译过的文件实际上可能需要更长的时间(如果您不经常更改代码,而是更改处理的数据,则会发生大量本质上动态的链接,使用已在core中的粒子过滤代码准备一个新的core文件可能是一个优势).

    通用Lisp中典型的算术知识可能很慢。改进它是可能的,但需要一些知识

    原因:

    • 通用Lisp编号不是机器提供的(bignums、rational、complex等)
    • 自动从fixnum更改为bignum并返回
    • 一般数学运算
    • 标记使用单词大小的位
    • 考虑数字
    你可以从p