Почему переменная в моей программе использует 60% времени выполнения? - PullRequest
2 голосов
/ 15 декабря 2011

Я анализирую свой код с помощью 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) времени выполнения.

Есть идеи?

Ответы [ 2 ]

1 голос
/ 15 декабря 2011

при запуске программы gprofiled записывает данные в файл, обычно gmon.out. Этот файл содержит адреса функций, а не имена. Когда вы читаете данные с помощью утилиты gprof, она разрешает имена, используя отладочную информацию, представленную в программе.

Это означает, что если вы запустите программу, перекомпилируете ее и выполните gprof без перезапуска программы, вывод будет бессмысленным.

1 голос
/ 15 декабря 2011

Давайте посмотрим на некоторый минимальный пример, который ведет себя аналогично:

  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

Эта обратная трассировка должна дать нам хотя бы кое-что для Google.Это конструкторы для глобальных значений.

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 и 0xffff.И эта функция затем также вызывает ctor std::ios_base::Init::Init(), который инициализирует глобальный материал, необходимый для использования std :: cout.

Теперь мы знаем, что он делает, но не почему.Здесь кто-то с начальными знаниями gcc будет знать больше, но я предполагаю, что именно так gcc гарантирует, что всякий раз, когда некоторый код, вызываемый для инициализации некоторых глобальных / статических переменных (который выполняется перед main), также ctor для i /o Подсистема называется, так что вы всегда можете использовать std::cout там.

Относительно того, почему это так часто вызывается в вашем коде, и почему это занимает так много времени, я не могу сказать много, может бытьВы можете узнать больше об установке некоторой точки останова в отладчике.Может быть, это также неправильный учет этой функции из-за оптимизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...