我正在用gprof分析我的代码,我得到以下输出:
% cumulative self self total
time seconds seconds calls ms/call ms/call name
59.22 0.58 0.58 48 12.09 18.81 _GLOBAL__sub_I_inputHeight
inputHeight是一个全局变量。我不知道 GLOBAL _sub_I_inputHeight意味着什么,但它被调用了48次,并且占用了执行时间的60%(0,6)。
有什么想法吗?
答案 0 :(得分:1)
让我们看一下行为相似的一些最小例子:
1 #include <iostream>
2
3 int global_int = 42;
4
5 int main(int argc, const char *argv[])
6 {
7 std::cout << "global_int = " << global_int << "\n";
8 }
(gdb) bt
#0 global constructors keyed to global_int() () at global.cxx:8
#1 0x0804875d in __do_global_ctors_aux ()
#2 0x080484ec in _init ()
#3 0x080486f9 in __libc_csu_init (argc=1, argv=0xbffff0c4, envp=0xbffff0cc) at elf-init.c:79
#4 0xb7d2069c in __libc_start_main () from /lib/libc.so.6
#5 0x08048591 in _start () at ../sysdeps/i386/elf/start.S:119
这种回溯应该给我们至少一些谷歌。这些是全球价值观的构建者。
191 080486b1 <_GLOBAL__I_global_int>:
192 80486b1: 55 push %ebp
193 80486b2: 89 e5 mov %esp,%ebp
194 80486b4: 83 ec 18 sub $0x18,%esp
195 80486b7: c7 44 24 04 ff ff 00 movl $0xffff,0x4(%esp)
196 80486be: 00
197 80486bf: c7 04 24 01 00 00 00 movl $0x1,(%esp)
198 80486c6: e8 a6 ff ff ff call 8048671 <_Z41__static_initialization_and_destruction_0ii>
199 80486cb: c9 leave
200 80486cc: c3 ret
反汇编并没有让我们在这里变得更聪明,它调用了函数__static_initialization_and_destruction_0(int,int)
,这更令人感兴趣:
171 08048671 <_Z41__static_initialization_and_destruction_0ii>:
172 8048671: 55 push %ebp
173 8048672: 89 e5 mov %esp,%ebp
174 8048674: 83 ec 18 sub $0x18,%esp
175 8048677: 83 7d 08 01 cmpl $0x1,0x8(%ebp)
176 804867b: 75 32 jne 80486af <_Z41__static_initialization_and_destruction_0ii+0x3e>
177 804867d: 81 7d 0c ff ff 00 00 cmpl $0xffff,0xc(%ebp)
178 8048684: 75 29 jne 80486af <_Z41__static_initialization_and_destruction_0ii+0x3e>
179 8048686: c7 04 24 d4 a0 04 08 movl $0x804a0d4,(%esp)
180 804868d: e8 9e fe ff ff call 8048530 <_ZNSt8ios_base4InitC1Ev@plt>
181 8048692: b8 50 85 04 08 mov $0x8048550,%eax
182 8048697: c7 44 24 08 20 a0 04 movl $0x804a020,0x8(%esp)
183 804869e: 08
184 804869f: c7 44 24 04 d4 a0 04 movl $0x804a0d4,0x4(%esp)
185 80486a6: 08
186 80486a7: 89 04 24 mov %eax,(%esp)
187 80486aa: e8 61 fe ff ff call 8048510 <__cxa_atexit@plt>
188 80486af: c9 leave
189 80486b0: c3 ret
这里的重要部分是在atexit()上注册了一个函数,该函数位于0x8048550
并且名为std::ios_base::Init::~Init()
,但仅当此函数的参数为0x1
且{ {1}}。然后这个函数也调用ctor 0xffff
,它正在初始化使用std :: cout所需的全局内容。
现在我们知道它在做什么,但不知道为什么。这里有一个初始gcc知识的人会知道更多,但我的猜测是,这是gcc确保每当调用一些代码来初始化一些全局/静态变量(在main之前运行)时的方式,也就是i /的ctor o子系统被调用,因此您可以随时使用std::ios_base::Init::Init()
。
至于为什么在代码中经常调用它,以及为什么需要这么长时间,我不能说太多,也许你可以在调试器中找到更多安装断点的方法。也许由于优化,这也是对该功能的一些错误的会计。
答案 1 :(得分:1)
当你运行一个gprofiled程序时,它会将数据写入一个文件,通常是gmon.out
。该文件包含函数的地址,而不是名称。使用gprof
实用程序读取数据时,它会使用程序中的调试信息解析名称。
这意味着如果你运行程序,重新编译它并执行gprof
而不重新运行程序,输出就毫无意义。