有没有用于在C ++中追踪膨胀的工具?

时间:2010-06-29 14:20:28

标签: c++ profiler

这里有一个粗心写的模板,有些过分内联 - 在C ++中编写膨胀代码太容易了。原则上,重构以减少膨胀不是太难。问题在于跟踪最严重的违规模板和内联 - 跟踪那些在真实程序中导致真正膨胀的项目。

考虑到这一点,并且因为我确信我的图书馆比他们应该更容易臃肿,我想知道是否有任何工具可以自动追踪那些最严重的罪犯 - 即识别那些项目贡献最多(包括所有重复的实例化和调用)到特定目标的大小。

此时我对性能不太感兴趣 - 这完全取决于可执行文件的大小。

是否有适用于此作业的工具,可在Windows上使用,并适用于MinGW GCC或Visual Studio?

编辑 - 某些背景

我有一组多路树模板,可以替代红黑树标准容器。它们是围绕非类型安全的非模板代码编写的,但它们也是很久以前编写的,并且作为“将更好地缓存友好性提升实际性能”实验。关键是,它们并非真正用于长期使用。

因为它们支持一些方便的技巧(基于自定义比较/部分键搜索,有效的订阅访问,搜索最小的未使用的键),它们最终被我的代码中的所有地方使用。这些天,我几乎没有使用过std :: map。

在这些之上,我有一些更复杂的容器,例如双向地图。最重要的是,我有树和有向图类。除此之外...

使用地图文件,我可以追踪非内联模板方法是否会导致膨胀。这只是找到特定方法的所有实例化并添加大小的问题。但是不明智的内联方法呢?毕竟,模板是非模板代码的薄包装,但历史上我判断是否应该内联的能力并不是非常可靠。这些模板内联的膨胀影响并不容易衡量。

我知道哪些方法被大量使用,但这是众所周知的opimization-without-profiling错误。

5 个答案:

答案 0 :(得分:7)

结帐Symbol Sort。我用了一段时间来弄清楚为什么我们的安装程序在六个月内增长了4倍(事实证明答案是C运行时和libxml2的静态链接)。

答案 1 :(得分:5)

地图文件分析

我前段时间遇到过这样的问题,最后我编写了一个分析地图文件的自定义工具(可以指示Visual Studio链接器生成一个)。工具输出是:

  • 按代码大小降序排序的函数列表,仅列出第一个N
  • 按代码大小降序排序的源文件列表,仅列出第一个N

解析映射文件相对容易(函数代码大小可以计算为当前行和后续行之间的差异),最难的部分可能是以合理的方式处理损坏的名称。你可能会发现一些准备好使用的库,我几年前就做过了,我不知道目前的情况。

以下是地图文件的摘录,以便您知道会发生什么:

Address         Publics by Value              Rva+Base       Lib:Object

0001:0023cbb4       ?ApplyScheme@Input@@QAEXPBVParamEntry@@@Z 0063dbb4 f   mainInput.obj
0001:0023cea1       ?InitKeys@Input@@QAEXXZ    0063dea1 f   mainInput.obj
0001:0023cf47       ?LoadKeys@Input@@QAEXABVParamEntry@@@Z 0063df47 f   mainInput.obj

符号排序

正如在Ben Staub's answer中发布的那样,Symbol Sort是一个随时可用的命令行实用程序(附带一个完整的C#源代码),它可以完成所有这些操作,唯一的区别就是不分析地图文件,但是而是pdb / exe文件。

答案 2 :(得分:2)

所以我根据你的问题阅读的内容和你的意见是, 库真的太大了。

确定此命令所需的唯一工具是命令shell或Windows文件浏览器。查看文件大小。它是如此之大,以至于导致真正的实际问题? (不可接受的下载时间,不适合目标平台的内存,那种东西)?

如果没有,那么你应该担心代码的可读性和可维护性,而不是其他任何东西。 的工具就是你的眼睛。阅读代码,并采取必要的措施,以便在必要时使其更具可读性。

如果您可以指出可执行文件大小为问题的实际原因,请将其编辑到您的问题中,因为它是重要的上下文。

但是,假设文件大小 实际上是一个问题:

内联函数通常不是问题,因为编译器而不是其他人选择内联函数。简单地标记某些内容inline并不会内联实际生成的代码。如果编译器确定较大代码与较少间接之间的权衡是值得的,则编译器会内联。如果经常调用一个函数,它将不会内联,因为这会显着影响代码大小,这会影响性能。

如果您担心内联函数会导致代码膨胀,只需使用“optimize for size”标志进行编译即可。然后编译器会将内联限制为不会明显影响可执行文件大小的情况。

要找出哪些符号最大,请将地图文件解析为@Suma建议。

但实际上,当你提到“着名的opimization-without-profiling错误”时,你自己就说过了。

您需要做的第一个分析行为是要求可执行文件大小实际上是一个问题?在评论中你说你有“感觉”,在分析环境中没用,并且可以翻译成“不,可执行文件大小不是问题”。

资料。收集数据并识别问题点。在担心如何降低可执行文件大小之前,请先了解可执行文件的大小,然后确定这是否确实存在问题。你还没有那样做。您在一本书中读到“代码膨胀是C ++中的一个问题”,因此您认为代码膨胀是您程序中的一个问题。不是吗?为什么?你如何确定它是什么?

答案 3 :(得分:1)

基本上,您正在寻找您不需要的昂贵的东西。假设某些类别的函数不需要占用大部分空间,例如20%。然后,如果您从图像大小中选择了20个随机字节,平均其中4个(20 * 20%)将在该类别中,您将能够看到它们。所以基本上,你拿这些样本,看看它们,如果你看到一个你并不真正需要的明显的函数模式,那么删除它们。然后再做一遍,因为使用较少空间的其他类别的例程现在占用更高的百分比。

所以我同意Suma认为解析地图文件是一个好的开始。然后我会编写一个程序来遍历它,并且每5%(空间)打印我所处的例程。这样我就得到20个样本。通常我发现大量的对象空间来自极少数(如1)的源代码行,我可以很容易地用另一种方式。

你也担心过多的内联使功能变得更大。为了弄清楚这一点,我会采用每个样本,并且由于它代表特定函数中的特定地址,我会将其追溯到它所在的代码行。这样,我可以判断它是否在扩展功能。这是一项工作,但可行。

类似的问题是如何在磁盘充满时找到肿瘤。同样的想法是走路目录树,添加文件大小,然后再次走,当你通过每个5%点时,你打印出你所在文件的路径。这不仅告诉你你有大文件,它告诉你你是否有大量的小文件,它们埋藏的深度或分散的范围并不重要。当您清除一类不需要的文件时,可以再次执行以获取下一个类别,依此类推。

祝你好运。

答案 4 :(得分:1)

http://www.sikorskiy.net/prj/amap/index.html

这是从Visual Studio编译器映射文件生成的lib / library size analysis GUI工具中的精彩对象文件。此工具从地图文件中分析并生成报告。你也可以做过滤,它动态显示大小。只需将地图文件输入到此工具,此工具将列出占用哪个函数dll / exe生成的给定地图场的大小,检查上面文件中的屏幕截图/您也可以按大小排序。