URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9938
[ Назад ]

Исходное сообщение
"Должны ли быть видны в inline-функции в профиляторе Gprof ?"

Отправлено xintrea , 12-Ноя-14 17:02 
Вопрос в следующем.

У меня есть функции (точнее, методы, но все происходит в пределах одного класса, причем экземпляр класса один), которые много раз вызываются в цикле. Представляют собой несложные математические вычисления, этакий синтаксический сахар.

Такие функции, да еще и вызываемые в циклах, имеет смысл объявлять инлайновыми. Это необходимо, чтобы не тратилось время на работу со стеком/регистрами при подготовке вызова, на сам вызов функции, на возврат результата.

То есть предполагается, что в машинном коде вызовов этих функций не должно быть, ибо они непосредственно встаиваются в машинный код вместо своего CALL.

При профилировании через gprof я вижу, что эти inline функции показываются в gprof, и gprof показывает число их вызовов.

Вопрос:

Это gprof такой умный, видит работу инлайновых функций, подсчитывает число их "виртуальных" вызов? Или данные функции, несмотря на директиву inline, скомпилены таки в виде обычных функций, и поэтому их видит gprof?

Пример функций:

inline unsigned char RC5Simple::RC5_GetByteFromWord(RC5_TWORD w, int n)
{
unsigned char b=0;

switch (n) {                                                                                  
   case 0:
       b=(w & 0x000000FF);
       break;
   case 1:
       b=(w & 0x0000FF00) >> 8;
       break;
   case 2:
       b=(w & 0x00FF0000) >> 16;
       break;
   case 3:
       b=(w & 0xFF000000) >> 24;
}

// RC5_LOG(( "GetByteFromWord(%.8X, %d)=%.2X\n", w, n, b ));

return b;
}    


inline RC5_TWORD RC5Simple::RC5_GetWordFromByte(unsigned char b0,
                                                unsigned char b1,
                                                unsigned char b2,
                                                unsigned char b3)
{
return b0+
        (b1 << 8)+
        (b2 << 16)+
        (b3 << 24);
}

А вот как они выглядят в профилировщике:

  0.00      0.73     0.00  4289320     0.00     0.00  RC5Simple::RC5_GetByteFromWord(unsigned long, int)
  0.00      0.73     0.00  1072330     0.00     0.00  RC5Simple::RC5_GetWordFromByte(unsigned char, unsigned char, unsigned char, unsigned char)
...
                0.00    0.00 4289320/4289320     RC5Simple::RC5_GetByteFromWord(unsigned long, int) [423]
                0.00    0.00 1072330/1072330     RC5Simple::RC5_GetWordFromByte(unsigned char, unsigned char, unsigned char, unsigned char) [424]


Содержание

Сообщения в этом обсуждении
"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено skb7 , 12-Ноя-14 18:28 
Не знаю как в C++, но в чистом C "inline" -- это лишь рекомендация компилятору встраивать эти функции. Компилятор часто игнорирует эту рекомендацию (когда функция больше 1-2 строк). Единственный способ реально инлайнить функции, который я знаю, -- это макросы (#define). Даже attribute((always_inline)) на помогает, он просто говорит сохранять смысл inline (рекомендация на встраивание) при отключенных оптимизациях (-O0).

Смотрим http://en.wikipedia.org/wiki/Inline_function :


The compiler may ignore the programmer’s attempt to inline a function, mainly if it is particularly large.

Например вот код:


#include <stdio.h>
#include <stdlib.h>

inline int f1(int a)
{
    return a + 1;
}

inline int f2(int a)
{
    int i;

    for (i = 0; i < 10; ++i) {
        if (a < 5)
            a += 2;
        else
            a += 3;
    }

    printf("f2 done\n");

    return a;
}

int main(void)
{
    int x = 5;

    x = f1(x);
    x = f2(x);

    printf("x = %d\n", x);

    return EXIT_SUCCESS;
}

Компилируем и смотрим какие функции заинлайнились, а какие нет:


$ gcc -Wall -O2 main.c
$ objdump -DCS a.out | less

Видем следующую картину:


0000000000400450 <main>:
  400454:       bf 06 00 00 00          mov    $0x6,Мi
  400459:       e8 22 01 00 00          callq  400580 <f2>
  ...

Т.е. компилятор вообще соптимизировал вызов f1(), на этапе компиляции выполнив "5+1=6", а вот f2() уже не инлайнил и она действительно вызывается.

Вывод: проверяйте через objdump, какие функции заинлайнились, а какие нет. Соответственно те, которые не заинлайнились, gprof может видеть.
Вывод 2: если реально нужно инлайнить, попробуйте always_inline, а есть не поможет, то используйте макросы через #define


"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено pavlinux , 13-Ноя-14 03:38 
>[оверквотинг удален]

 
#include <stdio.h>
#include <stdlib.h>

static inline int f1(int a) __attribute__((always_inline));
static inline int f2(int a) __attribute__((always_inline));

static inline int f1(int a)
{
        return a + 1;
}

static inline int f2(int a)
{
        int i;

        for (i = 0; i < 10; ++i) {
                if (a < 5)
                        a += 2;
                else
                        a += 3;
        }

        printf("f2 done\n");

        return a;
}

int main(void)
{
        int x = 5;

        x = f1(x);
        x = f2(x);

        printf("x = %d\n", x);

        return EXIT_SUCCESS;
}


> Компилируем и смотрим какие функции заинлайнились, а какие нет:
>
 
> $ gcc -Wall -O2 main.c
> $ objdump -DCS a.out | less
>

> Видем следующую картину:

 
0000000000400546 <main>:
  400546:       55                      push   %rbp
  400547:       48 89 e5                mov    %rsp,%rbp
  40054a:       48 83 ec 10             sub    $0x10,%rsp
  40054e:       c7 45 fc 05 00 00 00    movl   $0x5,-0x4(%rbp)
  400555:       8b 45 fc                mov    -0x4(%rbp),%eax
  400558:       89 45 f8                mov    %eax,-0x8(%rbp)
  40055b:       8b 45 f8                mov    -0x8(%rbp),%eax
  40055e:       83 c0 01                add    $0x1,%eax
  400561:       89 45 fc                mov    %eax,-0x4(%rbp)
  400564:       8b 45 fc                mov    -0x4(%rbp),%eax
  400567:       89 45 f4                mov    %eax,-0xc(%rbp)
  40056a:       c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%rbp)
  400571:       eb 14                   jmp    400587 <main+0x41>
  400573:       83 7d f4 04             cmpl   $0x4,-0xc(%rbp)
  400577:       7f 06                   jg     40057f <main+0x39>
  400579:       83 45 f4 02             addl   $0x2,-0xc(%rbp)
  40057d:       eb 04                   jmp    400583 <main+0x3d>
  40057f:       83 45 f4 03             addl   $0x3,-0xc(%rbp)
  400583:       83 45 f0 01             addl   $0x1,-0x10(%rbp)
  400587:       83 7d f0 09             cmpl   $0x9,-0x10(%rbp)
  40058b:       7e e6                   jle    400573 <main+0x2d>
  40058d:       bf 44 06 40 00          mov    $0x400644,%edi
  400592:       e8 79 fe ff ff          callq  400410 <puts@plt>
  400597:       8b 45 f4                mov    -0xc(%rbp),%eax
  40059a:       89 45 fc                mov    %eax,-0x4(%rbp)
  40059d:       8b 45 fc                mov    -0x4(%rbp),%eax
  4005a0:       89 c6                   mov    %eax,%esi
  4005a2:       bf 4c 06 40 00          mov    $0x40064c,%edi
  4005a7:       b8 00 00 00 00          mov    $0x0,%eax
  4005ac:       e8 6f fe ff ff          callq  400420 <printf@plt>
  4005b1:       b8 00 00 00 00          mov    $0x0,%eax
  4005b6:       c9                      leaveq
  4005b7:       c3                      retq  
  4005b8:       0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  4005bf:       00


"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено skb7 , 13-Ноя-14 13:23 
> static inline int f1(int a) __attribute__((always_inline));
> static inline int f2(int a) __attribute__((always_inline));

Я вам даже больше скажу, если удалить эти строки, функции всё равно заинлайнятся. Они у вас инлайнятся, потому что они у вас static, а не always_inline. always_inline только и позволяет что инлайнить с отключенными оптимизациями. Если хотите инлайнить всегда -- смотрите в сторону атрибута flatten. И то может не заинлайниться. Поэтому #define рулит :)

Отсюда https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attrib... :


always_inline
    Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level was specified.

flatten
    Generally, inlining into a function is limited. For a function marked with this attribute, every call inside this function will be inlined, if possible. Whether the function itself is considered for inlining depends on its size and the current inlining parameters.



"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено skb7 , 12-Ноя-14 18:50 
А еще хотелось бы покритиковать вашу функцию :) Которая RC5_GetByteFromWord().
1. Функция легко упрощается до формы:

inline unsigned char RC5Simple::RC5_GetByteFromWord(RC5_TWORD w, int n)
{
switch (n) {                                                                                  
case 0:
    return w & 0x000000FF;
case 1:
    return (w & 0x0000FF00) >> 8;
case 2:
    return (w & 0x00FF0000) >> 16;
case 3:
    return (w & 0xFF000000) >> 24;
default:
    return 0;
}

2. И вообще, то что вы хотите сделать, делается в одну строку :)

inline unsigned char RC5Simple::RC5_GetByteFromWord(RC5_TWORD w, int n)
{
    return (w >> (n*8)) & 0xff;
}

Тогда может и заинлайнится функция, а если нет, то:


#define GET_BYTE(w, n) ((w) >> ((n)*8) & 0xff)

Только у макроса свои недостатки, на которые можно напороться.


"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено xintrea , 12-Ноя-14 23:16 
>[оверквотинг удален]
> }
>

> 2. И вообще, то что вы хотите сделать, делается в одну строку
> :)
>
 
> inline unsigned char RC5Simple::RC5_GetByteFromWord(RC5_TWORD w, int n)
> {
>     return (w >> (n*8)) & 0xff;
> }
>

Ага, вместо того чтобы маскировать с разными масками и сдвигать в краю слова, можно сдвинуть к краю слова и отмаскировать фиксированной маской. Это я не додумал. Так реально без всяких переходов.

Но попробую макросами, чтоб наверняка.


"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено pavlinux , 13-Ноя-14 03:45 
> Это я не додумал.

Через пару лет поймешь, что написал в функции, а другие? :)


"Должны ли быть видны в inline-функции в профиляторе Gprof ?"
Отправлено pavlinux , 13-Ноя-14 03:52 
> Такие функции, да еще и вызываемые в циклах, имеет смысл объявлять инлайновыми.
> Это необходимо, чтобы не тратилось время на работу со стеком/регистрами при
> подготовке вызова, на сам вызов функции, на возврат результата.

Функции инлайнить нужно только те, в которых не вызываются другие функции.