【问题标题】:Delphi: How to organize source code to increase compiler performance?Delphi:如何组织源代码以提高编译器性能?
【发布时间】:2009-05-28 12:17:08
【问题描述】:

我正在开发一个包含大量依赖项的大型 delphi 6 项目。编译整个项目需要几分钟。一些更改后的重新编译有时会更长,因此可以更快地终止 Delphi,擦除所有 dcu 文件并重新编译所有内容。

有没有人知道一种方法来识别,是什么让编译器越来越慢?关于如何组织代码以提高编译器性能的任何提示?

我已经尝试过以下事情:

  • 明确包含 dpr 中的大多数单元,而不是依赖搜索路径:它没有任何改进。
  • 使用命令行编译器 dcc32:它并不快。
  • 尝试查看编译器做了什么(使用 SysInternals 的 ProcessExplorer):显然它大部分时间都在运行一个名为“KibitzGetOverloads”的函数。但我不能用这些信息做任何事情......

编辑,到目前为止的答案摘要:

对我来说效果最好的答案:

  • cnpack 中的“清理未使用的单元引用”功能。它几乎自动清理了 1000 多个引用,使“冷”编译快了大约两倍。 (“冷”编译 = 在编译前擦除所有 dcu 文件)。 它从编译器获取参考列表。因此,如果您有一些 {$IFDEF },请检查您的所有配置是否仍然可以编译。

接下来我想尝试:

  • 手动重构单元引用(最终使用抽象类) 但这是更多的工作,因为我首先需要确定问题出在哪里。一些可能有帮助的工具:
    • GExperts在delphi IDE中添加项目依赖浏览器(可惜不能显示每个分支的大小)
    • Delphi Unit Dependency Viewer V1.0 做同样的事情,但没有 Delphi。它可以计算一些简单的统计数据(哪些单位被引用最多,...)
    • Icarus 在其中一个答案中被 a link 引用。

对我来说没有任何改变的事情:

  • 将我程序中的每个文件和所有组件放在一个文件夹中,不包含子文件夹。
  • 磁盘碎片整理(我尝试使用 ramdisk)
  • 对代码源和输出文件夹使用 ramdisk。
  • 关闭实时扫描杀毒软件
  • 列出 dpr 文件中的所有单元,而不是依赖搜索路径。
  • 使用命令行编译器 dcc32 或 ecc32。

不适用于我的情况的事情:

  • 避免依赖网络共享。
  • 使用DelphiSpeedUp,因为我已经有了它。
  • 对所有 dcu 使用单个文件夹(我总是这样做)

我没有尝试过的事情:

  • 升级到另一个 Delphi 版本。
  • 使用 dcc32speed.exe
  • 使用固态驱动器(我没有尝试过,但我尝试使用 ramdisk 来放置所有源代码。但也许我也应该在 ramdisk 上安装 delphi)

【问题讨论】:

  • 关于您的 $IFDEF 问题,您应该用适当的 $IFDEF 将使用过的单元本身括起来,以缓解 CnPack 将它们删除为未使用的问题。
  • @Lieven:用适当的 $IFDEf 封装整个单元是个好主意。但这并不总是可能的:如果该单元是您不想更改的库的一部分,则必须将 $IFDEF 放在“使用”中。

标签: delphi optimization compiler-construction


【解决方案1】:

一些可能会降低编译器速度的事情

  • uses 子句中的冗余单位。请参阅 this question 以获取指向 CnPack 的链接。
  • 没有明确地将单位添加到您的项目文件中。您似乎已经涵盖了这一点。
  • 更改了编译器设置,尤其是include TDD32 info

尝试去掉你的uses子句中未使用的单位,看看它是否会有所作为。

【讨论】:

  • 感谢您的回答。 cnpack 似乎很有趣。我会试一试。包括 TDD32 已停用。顺便说一句,还有一个名为 ecc32 的编译器(它调用 dcc32),我不知道确切的区别。
  • @Name,我不知道,抱歉编辑。现在你提到它,还有 dcc32speed.exe。它由 Andreas Hausladen 编写,并修补了几个函数以加速编译器。
  • cnpack 中的“清理未使用的单元引用”功能是一个非常好的答案。它几乎自动清理了 1000 多个引用,使“冷”编译快了大约两倍。
【解决方案2】:

使用 Delphi 7 和 2009,上周我从将近 2 分钟的编译时间和另外 45 秒的时间从按下 f9 并获得我的应用程序的主要形式到 20 秒的编译和运行时间。这件事让我发疯了大约 6 个月,但我尝试的任何方法似乎都不起作用。使用来自 SysInternals 的 filemon,我意识到编译器需要的每个单元(主要是组件)都在搜索路径中的每个文件夹中进行了搜索,是的,这会产生很多 FileOpen、FileExists 和 FileNotFound 等。我所做的是,把每个来自组件的 DCU、DFM、RES 等都在一个文件夹中,并且在搜索路径中只有这个文件夹,以及项目所需的其他几个文件夹;结果是惊人的。修复之前的其他问题是调试。调试时按F7、F8键大约需要40秒,这个也已经修复了。希望这些信息可以帮助你。来自委内瑞拉玛格丽塔岛的问候。请原谅我的英语,如果有任何错误;)

【讨论】:

  • 不是很实用,但可能值得一试。
【解决方案3】:

检查搜索路径中是否有任何不在本地计算机上的路径。

即不要链接到网络共享上的二进制文件,并检查搜索路径是否未检查任何网络共享。

【讨论】:

    【解决方案4】:

    我没有看到编译器随着时间的推移而变慢,但我们已经很久没有使用 Delphi 6 了。

    1. Delphi 社区似乎普遍认为,如果您不想升级到最新最好的(Delphi 2007 或 2009),那么 Delphi 7 是最好的/最快的/最稳定的。您可以考虑升级。
    2. KibitzGetOverloads 听起来像是来自 kibitz 编译器的东西——“后台”编译器为您提供代码完成、背景错误突出显示、代码工具提示等。听起来您最好检查一下命令的调用堆栈-行编译器,而不是 IDE;你会得到更有帮助的东西。
    3. 我从未发现删除 DCU 后编译速度更快。 DCU 可以使构建增量,因此更快。如果您在删除所有 DCU 后看到更快的编译,请检查您的硬件。你最近对硬盘进行碎片整理了吗?您的驱动器上有多少可用空间?

    【讨论】:

    • 命令行编译器也是如此,显然它在 KibitzGetOverloads 上花费了很多时间。磁盘空间不是问题,碎片整理可能无济于事,因为当我将整个源代码放在 ramdisk 上时,我得到了相同的结果。升级到较新的 Delphi 可能是一种选择,但我更想知道是什么让 Delphi 变慢。
    【解决方案5】:
    1. 您是否设置了一个文件夹来获取 DCU。否则,它们就会四处散落。
    2. 将所有单元及其隐式调用的单元(从库路径中安装的组件除外)放入 dpr。为确保您没有遗漏某些内容,请清空您的搜索路径,它仍然应该可以编译。
    3. 减少搜索路径后,您可以尝试通过将组件安装到更少的文件夹中来减少库路径。

    【讨论】:

    • 我系统地做第一,但对于不这样做的人来说,这可能是一个很好的提示。正如我原来的帖子中所说的那样,我已经尝试了 2 号。我不知道 3 号是否会有所帮助,但申请的工作量很大,所以这将是我可能尝试的最后一个。
    【解决方案6】:

    虽然与您的确切问题仅部分相关,但我听说固态驱动器的使用大大增加了 Delphi 的编译时间 - Nick Hodges 自己在几周前的 Delphi 播客上说过这一点。 布赖恩

    【讨论】:

    • 有趣的想法,给了我另一个想法:我试图把整个源代码放在一个ramdisk上。但我没有得到任何改善。 Windows 可能缓存文件足够好。
    【解决方案7】:

    【讨论】:

    • 在大多数情况下,我不知道在哪里划分代码源以缩短编译时间,因为我不知道是什么让编译器变慢。所以它可能会持续很长时间,直到我真正得到好结果。 +1 有关防病毒的提示。到现在才想到这个,值得一试。
    • 第三点如果AV允许路径异常可以缓解,可以在\Lib那里列出; \dcu; 等。因此编译时间不会很困难。我知道,阿瓦斯特!在家庭版上有这个选项。不认识其他人
    【解决方案8】:

    我们遇到了相同(或相似)的问题。 我们包的我有编译时间大约 12 分钟。 更改后,现在我们已移至 32 sg。

    经过多次测试,我们发现“问题情况”如下: 在单个包装中:

    • A 单元 在同一个包中使用了大量单元:U1、U2、U3、U4、... U100(接口使用)。这是集中所有初始化工作的重要单元。

    • 封装的所有单元,U1、U2、U3、..、U100 使用单元 A(使用实现)

    这个“循环引用”并没有因为用途不同而产生编译错误,而是造成了很大的编译时间。

    解决方案: 消除对A Unit中每个单元U1、U2、U3、....、U100的引用。

    现在,一个单位使用了大量的单位:U1, U2 ,...., U100,但是单位 U1, U2 ,..., U100,不使用单位A.

    在此更改之后,编译时间急剧下降。

    如果你有类似情况,可以试试这个。

    请原谅我的英语不好。

    您好。


    内夫塔利 - Germán Estévez-

    【讨论】:

    【解决方案9】:

    我遇到了同样的问题,我可以提出 (2) 个影响我的原因。

    1. 循环引用。这位先生说一个是正确的。我会有一些编译速度很快的大型项目,以及编译速度很慢的小型项目。直到我重组代码然后我获得了更快的编译速度才弄清楚。很多小单位。构建整体单元很容易。但是,它有很多惩罚。

    2. 我已经听过 1000 次了,在您的用户可能正在使用的慢速机器上进行开发。嘿,那是给测试部门的。我不能在编译、Delphi 加载速度、软件包等方面浪费时间。我出去买了一台带有固态驱动器(如前所述)、12GB RAM、超频“i7”英特尔芯片的“GAMERS”计算机(WOW) ,三块显卡(链接),全部在 Vista64 上(一旦它最终与所有已安装的部件一起运行,Vista 还不错)。把它全部设置好真的很痛苦。但是,我不再在我的电脑上等待。纯粹的编译速度、加载速度,再加上一台全新的机器,没有过去 2 年安装在最后一台机器上的所有废话。我什至卸载了 DelphiSpeedUp。不需要它。而且我不需要关闭防病毒软件,因为我也这样做了,并且受到了互联网垃圾的惩罚。所以防病毒软件会继续运行。纯粹和简单,得到一个 BALLS OUT 机器。你的时间比你花在一台新电脑上的时间更有价值。

    【讨论】:

    • 为什么停在 12 GByte,32 不是更多吗?不认真,您能否补充一些信息,为什么有人需要这台可笑的顶级机器来进行 Delphi 开发?
    • 他问过如何提高编译速度。从什么时候SLI/Crossfire/Solid state disk提高Delphi编译速度?从什么时候 Delphi 需要超过 2GB 的内存?
    • VM 缓存在可用 RAM 中,因此如果您有很多源文件,最终会缓存在 RAM 中。此外,固态磁盘的随机访问时间较短,因此可以更快地找到和读取文件。磁盘是编译过程中的瓶颈,所以任何加快磁盘速度的东西都会加快编译时间。
    【解决方案10】:

    尝试安装一个 ram 磁盘并将您的 dcu 输出路径设置为指向那里。这使我在 DelphiSpeedUp 之上使用 Delphi 2007 的编译时间减少了一半以上。

    【讨论】:

    • 我已经尝试过了,在 Brian Frost 告诉固态驱动器似乎可以提高性能之后。就我而言,它没有改变任何东西。可能是 Windows 在缓存文件方面已经做得很好了。
    【解决方案11】:

    编译器只会编译已更改的单元。如果您更改了接口部分中的代码,所有依赖于更改单元的单元都会被编译。如果仅更改了实现部分中的代码,则编译将只更改该单元,但可能会链接所有模块。意味着预先设计好的接口,但如果您重组代码以限制对实现的更改,编译时间可能会减少。我不知道多少。 Delphi 7 "Using Delphi" 中的 Multiple and indirect unit references 下的 Delphi 帮助文件中提到了这一事实。

    【讨论】:

    • 我想重构代码以提高编译速度。但我不知道从哪里开始。如果有一个工具可以显示哪些依赖项会导致问题,那就太好了。但是这样的工具可能不存在
    【解决方案12】:
    • 不要在网络驱动器上编译。寻道时间明显更差。
    • 考虑将 dcu(“单元输出”目录)指向 ramdrive。
    • 限制包含/单元目录的数量。
    • 尽量避免编译器仍然接受的次要循环引用,特别是对于大型单元(例如,为您的 OPF 生成的 ORM 单元)。它可能会导致大型单元被编译两次。 (Delphi 是否允许较小的相互循环,还是 FPC 独有的功能?)

    我从未尝试过,但在中心 .dpr 中对所有具有完整/相对路径的文件进行硬编码也可能会有所帮助(重新生成/更新的脚本?)。 (你在上面提到过,但是路径 xx 是 '\path\yyy' 符号吗?)。

    其他远射:

    • 使用 Kylix(根据我的经验,Linux 下的文件/目录 I/O 明显更好(尽管这是来自 FPC 的经验))。也许我们需要一个反向的跨 kylix :-)
    • 使用单独的(Windows)构建机器,并通过注册表调整 NTFS 以降低“安全性”。 (你不关心,因为一切都是一个修订系统开始)。 Afaik 这些选项只能对所有文件系统全局执行,因此是单独的系统。也可以加入 raid 阵列或 Raptor。
    • 忘记固态。不错的嗡嗡声atm,但高写入率最终会扼杀它(当它变得更满并且无法再优化分配时,寿命和性能都会受到影响),并且您需要昂贵的英特尔来击败两个 75 美元的 RAID 硬盘。

    附:抱歉 FPC 参考资料。我两者都做,有时我不知道什么属于什么。

    【讨论】:

    • “小互通”?由于我从未听说过它,我相信这是 FPC 独有的功能。
    【解决方案13】:

    我所做的始终是确保库路径中的目录非常少,以及大部分组件和静态代码。我还确保库路径中没有可用的源代码,只有.dcu/.res等。只有browsepath有源代码,特殊情况通过项目的searchpath处理。

    只要限制你在任何情况下编译的内容。

    【讨论】:

      【解决方案14】:

      几年后,我再次为编译时间的增加而苦苦挣扎。我目前正在使用 Delphi XE4,我正处于绝对需要重构单位引用的地步。我想到了一种新的方法来找出问题所在:

      我正在使用Process Monitor from Microsoft/SysInternals 来监控编译器:

      1. 我使用过滤器启动进程监视器以​​仅显示 dcc32.exe (或在 IDE 中工作时为 bds.exe)。
      2. 我从命令行构建我的项目。
      3. 最后我查看了进程监视器日志中的 CreateFile 操作。

      对于每个单元,都有一个 .PAS 文件条目(当编译器开始处理该单元时)和一个 .DCU 文件条目(当编译器对该单元进行复杂处理时)。通过使用文本编辑器和/或 Excel 处理日志,我可以提取此类信息:

      • 一种“树”,您可以在其中递归查看单元的编译顺序。
      • 对于每个单元,“.PAS 文件打开”和“.DCU 文件写入”之间的延迟。

      然后我尝试解释结果以找到进行重构会加快编译时间的地方。这并不容易,但我得到了一些令人鼓舞的结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-06
        • 1970-01-01
        • 1970-01-01
        • 2016-06-20
        • 1970-01-01
        • 2015-04-27
        • 1970-01-01
        相关资源
        最近更新 更多