我正在寻找旧的博客帖子 C++ Code Size 中第一个问题的Stack Overflow风格的答案,我将在下面重复:
我真的很喜欢一些工具(理想情况下,基于g ++),它向我展示了编译/链接代码的哪些部分是从C ++源代码的哪些部分生成的。例如,查看某个特定模板是否正在为数百种不同类型实例化(通过模板特化可修复),或者是否过度内联代码,或者特定函数是否大于预期。
答案 0 :(得分:7)
如果你想在C ++代码中找到代码膨胀的来源,那我就用'nm'。以下命令将列出应用中具有最大代码和数据块的所有符号:
nm --demangle --print-size --size-sort --reverse-sort <executable_or_lib_name> | less
答案 1 :(得分:5)
看起来像这样的事情应该存在,但我没有使用过类似的东西。不过,我可以告诉你我将如何编写这些脚本。可能有更快捷和/或更性感的方式。
addr2line命令接收一个地址,可以告诉你那里的机器代码实现的源代码。可执行文件需要使用调试符号构建,并且您可能不希望对它进行太多优化(-O0,-O1或-Os可能与您最初想要的一样高)。 addr2line有几个标志,你需要阅读它的手册页,但如果你想看到输出中有意义的C ++函数名,肯定需要使用-C或--demangle。
objdump命令可以在许多类型的目标文件中打印出有关这些东西的各种有趣的东西。它可以做的一件事就是打印出一个表格,该表格表示目标文件(包括可执行文件)中的符号或参考文件。
你想要的是objdump告诉你.text部分的地址和大小。这是实际的可执行机器代码所在的位置。有几种方法可以做到这一点,但最简单的(无论如何)可能是你要做的:
objdump -h my_exe | grep text
这应该会产生类似的结果:
12 .text 0000049 000000f000 0000000f000 00000400 2**4
如果你没有grep它会给你一个标题:
Idx Name Size VMA LMA File off Algn
我认为对于可执行文件,VMA和LMA应该是相同的,所以你使用哪个都没关系,但我认为LMA是最好的。你也想要这个尺寸。
使用LMA和大小,您可以重复调用addr2line,询问机器代码的源代码来源。我不确定如果你传递了一条指令内的地址,它会如何工作,但我认为它应该有效。
addr2line -e my_exe <address>
此输出将是路径/文件名,冒号和行号。 如果要计算每个唯一路径/文件的出现次数:num,您应该能够查看具有最高计数的那些。 Perl哈希使用路径/文件:num作为键,而计数器作为值将是一种简单的方法来实现这一点,但如果发现运行速度太慢,有更快的方法。 您还可以过滤掉您可以确定不需要尽早包含的内容。 要显示输出,您可能希望从同一函数中过滤掉不同的行,但您可能会注意到一个函数中的不同行具有不同的计数,这可能很有趣。无论如何,这可以通过让addr2line告诉你函数名称或在第一步中使用objdump -t并一次处理一个函数来完成。
如果您发现某些模板代码或其他代码行显示在您的可执行文件中的次数比您认为的要多,那么您可以轻松找到它们并仔细查看。宏和内联函数可能会显示出与预期不同的最终结果。
如果您不知道,objdump和addr2line来自GNU binutils包,其中包含其他一些有用的工具。
答案 2 :(得分:4)
我最近编写了一个工具bloat-blame,它与nategoose proposed类似。
答案 3 :(得分:1)
我不知道它是否会有所帮助,但是有一个gcc标志可以将它生成的汇编代码写入文本文件供您检查。
“的 -S 强> 用于代替-c以使用.s作为扩展名而不是目标文件来生成汇编程序源文件。如果需要检查生成的汇编代码,这可能很有用。 “
答案 4 :(得分:1)
在大多数C编译器中,有一种生成.map文件的方法。此文件列出了所有已编译的库的地址和大小。您可以使用该映射文件来帮助您确定首先要优化的文件。
答案 5 :(得分:1)
您可以查看 bloaty 以分析程序的二进制大小:
https://github.com/google/bloaty
./bloaty bloaty -d compileunits
FILE SIZE VM SIZE
-------------- --------------
34.8% 10.2Mi 43.4% 2.91Mi [163 Others]
17.2% 5.08Mi 4.3% 295Ki third_party/protobuf/src/google/protobuf/descriptor.cc
7.3% 2.14Mi 2.6% 179Ki third_party/protobuf/src/google/protobuf/descriptor.pb.cc
4.6% 1.36Mi 1.1% 78.4Ki third_party/protobuf/src/google/protobuf/text_format.cc
3.7% 1.10Mi 4.5% 311Ki third_party/capstone/arch/ARM/ARMDisassembler.c
1.3% 399Ki 15.9% 1.07Mi third_party/capstone/arch/M68K/M68KDisassembler.c
3.2% 980Ki 1.1% 75.3Ki third_party/protobuf/src/google/protobuf/generated_message_reflection.cc
3.2% 965Ki 0.6% 40.7Ki third_party/protobuf/src/google/protobuf/descriptor_database.cc
2.8% 854Ki 12.0% 819Ki third_party/capstone/arch/X86/X86Mapping.c
2.8% 846Ki 1.0% 66.4Ki third_party/protobuf/src/google/protobuf/extension_set.cc
2.7% 800Ki 0.6% 41.2Ki third_party/protobuf/src/google/protobuf/generated_message_util.cc
2.3% 709Ki 0.7% 50.7Ki third_party/protobuf/src/google/protobuf/wire_format.cc
2.1% 637Ki 1.7% 117Ki third_party/demumble/third_party/libcxxabi/cxa_demangle.cpp
1.8% 549Ki 1.7% 114Ki src/bloaty.cc
1.7% 503Ki 0.7% 48.1Ki third_party/protobuf/src/google/protobuf/repeated_field.cc
1.6% 469Ki 6.2% 427Ki third_party/capstone/arch/X86/X86DisassemblerDecoder.c
1.4% 434Ki 0.2% 15.9Ki third_party/protobuf/src/google/protobuf/message.cc
1.4% 422Ki 0.3% 23.4Ki third_party/re2/re2/dfa.cc
1.3% 407Ki 0.4% 24.9Ki third_party/re2/re2/regexp.cc
1.3% 407Ki 0.4% 29.9Ki third_party/protobuf/src/google/protobuf/map_field.cc
1.3% 397Ki 0.4% 24.8Ki third_party/re2/re2/re2.cc
100.0% 29.5Mi 100.0% 6.69Mi TOTAL
答案 6 :(得分:0)
我不知道如何映射代码 - >生成的程序集。
对于模板实例化,您可以使用“strings -a | grep | sort -u | gc ++ filt”之类的内容来粗略了解正在创建的内容。
你提到的其他两件事实际上看起来很主观。什么是“太多”内联?你担心你的二进制文件被夸大了吗?唯一要做的就是进入gdb并反汇编调用者以查看它生成的内容,一般不会检查“过度”内联。
对于功能大小,我很好奇为什么这很重要?您是否正在尝试查找在编译时意外扩展的代码?您如何定义工具的预期大小?同样,您可以随时解析您怀疑正在编译的任何函数,而不是您想要的代码,并查看编译器正在做什么。
答案 7 :(得分:0)
在Visual C ++中,这基本上是.PDB文件的用途。