LINUX.ORG.RU

Стоит ли делать always_inline для простеньких функций?

 , ,


0

2

Всех приветствую!

Мне не нравиться библиотека glm из-за своей многословности, сложности и большого кол-ва файлов.

Поэтому я, как программирующий на C естественно, пишу свою библиотеку.

Вопрос 1: Стоит ли делать always_inline для простеньких функций в своей библиотеке, например

...
static inline __attribute__((always_inline)) void   vec3_add     (VEC3 *v, const VEC3 *u,const VEC3 *w)    { v->X = u->X + w->X; 
                                                                                                             v->Y = u->Y + w->Y; 
                                                                                                             v->Z = u->Z + w->Z; }

static inline __attribute__((always_inline)) void   vec3_sub     (VEC3 *v, const VEC3 *u,const VEC3 *w)    { v->X = u->X - w->X; 
                                                                                                             v->Y = u->Y - w->Y; 
                                                                                                             v->Z = u->Z - w->Z; }
...

или компилятор лучше знает когда и что ему оптимизировать. И сделать их обычными static vec3_add(…)

Если такие ф-ции присутствуют внутри какого-то цикла, который не известно на уровне исполнения когда закончится, то компилятор не даст сделать такие ф-ции встроенными (_inline). Верно?

Вопрос 2: Имеет ли смысл держать еще аналогичные макросы

#define vec3_ADD(v,u,w)       { \
                                 (v).X = (u).X + (w).X; \
                                 (v).Y = (u).Y + (w).Y; \
                                 (v).Z = (u).Z + (w).Z; \
                              }
#define vec3_SUB(v,u,w)       { \
                                 (v).X = (u).X - (w).X; \
                                 (v).Y = (u).Y - (w).Y; \
                                 (v).Z = (u).Z - (w).Z; \
                              }

Они кажутся естественными. Даже иногда не знаешь, что лучше ф-ция или такой аналогичный макрос. Как быть, что выбрать? Или оставить и то, то это (на всякий случай).

Вопрос 3: Или все таки использовать glm, потому что..1).. 2)..3)?

Интересуют мысли по существу и про по такие вещи вообще.

Спасибо!


  1. Не надо.

  2. Не надо.

  3. Если для себя (jff, курсовика, диплома, etc), то помудохаться и написать свой велосипед стоит. Я в своё время для работы с матрицами и т.п. нарисовал библиотечку - было и интересно и познавательно и на допотомном тогдашнем железе работало в разы быстрее, чем «оптимизированная» \m/ библиотека используемая в проекте. Если для работы, если не хочешь проклятий и лучей счастья, то используй уже существующие библиотеки.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)

always_inline вроде как очень сильно нарушает автоматическое распараллеливание кода компиляторами, сейчас это может не так актуально и не является чем-то важным, но возможно в будущем что то изменится.

loglogav
()

Вопрос 1: Стоит ли делать always_inline для простеньких функций в своей библиотеке, например

Оставляй просто inline. Компилятор инлайнит даже функции которые не помечены inline, always_inline для особых ситуаций, тебе он не нужен.

Если такие ф-ции присутствуют внутри какого-то цикла, который не известно на уровне исполнения когда закончится, то компилятор не даст сделать такие ф-ции встроенными (_inline). Верно?

Нет, как ты пришел к такому выводу вообще?

Вопрос 2: Имеет ли смысл держать еще аналогичные макросы

Если можно обойтись inline, то макросы делать не надо.

Интересуют мысли по существу и про по такие вещи вообще.

Через -S/godbolt легко проверить что получается.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от loglogav

Влияет не столько на распараллеливание по разным ЦП сколько на оптимизации во время компиляции или при работе с памятью и спекулятивные вычисления цп, потому что это тоже распараллеливание, ветвистость кода или выполнения. У меня плохо с терминами, но крч влияет на предсказания вроде как и оптимизациями связанные с этим на разных уровнях, компилятора, памяти, цп и прочее. Но я не очень разбираюсь в этом, могу ошибаться.

loglogav
()
Ответ на: комментарий от loglogav

Ну ты намешал... У gcc свой планировщик инструкций, который работает после всех этих встраиваний, inline не могут сами по себе что то сбить.

https://godbolt.org/z/ec8qn4de8

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от loglogav

Влияет, но скорее положительно. Так как constant folding/propagation и другие проходы оптимизации могут упрощать inline версии функции если окажется, что её аргументы постоянны.

opcode
()

Мне не нравиться библиотека glm

При всём неуважении к glm, сначала https://tsya.ru/, а потом glm переписывайте

Стоит ли делать always_inline для простеньких функций в своей библиотеке

Сложный вопрос. С одной стороны мы хотим, чтобы даже с -O0/-O1/Og они по возможности заинлайнились, а компилятор порой может не додуматься это сделать
С другой стороны на таргетах без simd подобные функции сгенерируют много кода и куда лучше оставить их функциями.
Я бы в любом случае если и делал inline, то вынес его под макрос т.к аттрибуты эти непортабельные, а принудительный инлайнинг не всегда полезен.

mittorn ★★★★★
()

Я конечно не знаю какие твои вводные, но если ты придумываешь математику – то лучше придумывать её на питоне в каком-нибудь Jupyter Notebook + pandas/scipy. Если математика уже придумана, оттестирована и меняться больше не планирует, а твоя задача оптимизировать её для железа – то выбор использовать/не использовать библиотеку будет зависеть от железа (микроконтроллер, CPU SIMD, GPU).

snizovtsev ★★★★★
()
Ответ на: комментарий от mittorn

Ты что-то перепутал, ибо я заменял MSVC-шный __inline на static inline. :)

Хотя формально компилятору ничто не мешает забить на флаг inline, и оставлять можно действительно только static. Вот он куда полезнее.

a1ba ★★
()

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

компилятор без тебя разберется, что ему делать.

alysnix ★★★
()
Ответ на: комментарий от zx_gamer

Какие расширения? Это же валидный ANSI C. Это кстати тоже:

int main(void) 
{
    int a;
    ;;; {
        int b;
        {
            int c;
            a=0, b=a, c=b;
        }
        } ;;;
    return 0;
}
А do { ... } while(0); на помойку.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 3)
Ответ на: комментарий от MOPKOBKA
typedef float vec3 __attribute__((ext_vector_type(3)));

Но это что-то новое и не оч. кроссплатформенное?

vec3 add(vec3 a, vec3 b) {
    return a + b;
}

Выглядит красиво.

А вы хотели показать, что вышенаписанное и написанное по-старинке это

vec3 add2(vec3 a, vec3 b) {
    vec3 c;
    c.x = a.x + b.x;
    c.y = a.y + b.y;
    c.z = a.z + b.z;
    return c;
}

дает один и тот же ассебл. код, я так понимаю.

Gyros
() автор топика
Ответ на: комментарий от Gyros

Но это что-то новое и не оч. кроссплатформенное?

Поддерживается только clang. Есть еще расширение gcc для векторов, оно чуть менее удобное, но поддерживается и gcc и clang. Сами расширения довольно старые.

vec3 add(vec3 a, vec3 b)
vec3 add2(vec3 a, vec3 b)
дает один и тот же ассебл. код, я так понимаю.

Да, ну и пример что можно обращаться по разному к этим векторам. В том числе делать вот так

vec3 a;
vec2 b;
b = a.yz;

И вот еще тебе пример по упаковке структур в регистры: https://godbolt.org/z/hscdbTW8e

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Да, спасибо! Я все понял. Оставлю просто static inline

Нет, как ты пришел к такому выводу вообще?

Было как-то давно компилятор ругался, именно внутри цикла стояла ф-ция always_inline. Но не было времени разбираться, заменил на аналогич. макрос и все заработало. Осадок остался. Ложный. Другое, видимо, что-то было.

Gyros
() автор топика
Ответ на: комментарий от MOPKOBKA

Спасибо! Т.е. маленькие структуры лучше передавать по значению.

А я и их чаще по указателю в ф-ции передаю. Думал быстрее будет. Напрасно..

А что значит?

а тело функции не видно

Откуда его должно быть «видно»?

Gyros
() автор топика
Последнее исправление: Gyros (всего исправлений: 1)
Ответ на: комментарий от Gyros

А что значит?

а тело функции не видно

У тебя наверное типичный проект, где есть разделение на .h/.c файлы, и .c файлы превращаются в .o а потом линкуются в .exe.

Так вот, когда компилятор компилирует A.c, где есть вызов функции которая закодирована в B.c, то он НЕ может произвести оптимизацию функции из B.c или встроить ее вместо вызова. Потому что весь код что он видит, это A.c и заголовочные файлы.

То есть B.c он не видит, и тела функций в B.c он тоже не видит.

Именно поэтому нужно определять inline функции не в B.c если их нужно вызвать из A.c, а нужно определять их именно в B.h где компилятор их сможет увидеть, если этот заголовочный файл будет подключен к А.c

MOPKOBKA: Если они передаются по указателю, а тело функции не видно, то не пакует

Теперь когда понятно что значит видит/не видит, можно посмотреть на ситуацию, когда компилятор видит тело функции, пусть функция и использует указатели: https://godbolt.org/z/Phjv9aYKx

За счет того что компилятор увидел тело твоей функции с указателями, он может ее оптимизировать в нормальную.

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

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от Gyros

Спасибо. Но т.е. все равно небольшие структуры лучше по значению передавать в фун-ции.

Да, но главное не делать это обязательным правилом. Где удобнее указателем там надо указателем, где значением там значением. Если функция нагруженная и часто вызывается, то вместо выяснения «значение vs указатель» лучше сделать ее тело доступным что бы компилятор смог ее встроить, а перед встраиванием лучше сначала посмотреть на алгоритм. Нужно смотреть сверху вниз, сначала исправлять что то выше, а потом уже устраивать микро-оптимизации.

Но это наверное не относится к матрицам 4x4.

Да, на godbolt можешь проверить.

MOPKOBKA ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Я в sublime набираю тексты или вообще в Mousepad. Хотя Geany стоит, все никак не перейду.

Кстати

Вы в вашем посте про Geany писали про монитор измененией Git

  1. Монитор изменений Git

Будет подсвечивать измененные и добавленные строки в редакторе, определяя их через git.

Я что-то навскидку не нашел такого плагина внутри Geany, его доп скачивать/устанавливать надо?

на сохранение в редакторе настроил запуск clang-format

Это в каком редакторе? И почему безумный стиль? Я спец. ничего не делал для этого.

Gyros
() автор топика
Последнее исправление: Gyros (всего исправлений: 1)
Ответ на: комментарий от Gyros

Я в sublime набираю тексты или вообще в Mousepad. Хотя Geany стоит, все никак не перейду.

Да и не надо если удобно. Я сам много пишу в mousepad. В Sublime Text уже скорее всего есть плагин для clang-format. А для mousepad вместо плагина можно сделать опцию в Makefile, или скрипт в проекте format.sh, где просто будет вызываться clang-format для всех файлов.

Пользоваться clang-format просто, но man страница у него плохая.

# В папке проекта нужно сгенерировать конфиг по которому будет форматироваться
clang-format -style=Microsoft -dump-config > .clang-format

# Потом можно запускать переформатирование файла
clang-format -i main.c

Я что-то навскидку не нашел такого плагина внутри Geany, его доп скачивать/устанавливать надо?

apt install geany-plugins и потом в плагинах надо включить. В проекте уже должен быть настроен git.

Это в каком редакторе? И почему безумный? Я спец. ничего не делал для этого.

Я к Scintilla редакторам привык, в Linux мне больше всего понравился Geany, но как я уже выше показал, пользоваться можно в любом.

Безумным стиль я назвал, потому что тело очень близко к правому краю, не видел такого, и очень разные и одновременно большие отступы между элементами где их обычно не делают более одного, например:

) void   vec3_sub     (
Я просто никогда не любил комментарии с украшательствами или декоративные выравнивания как:
A    = B;
AAA  = B;
AAAA = B;
AA   = B;
AAA  = B;
Всегда представляю что люди мучают себя отбивая все эти украшательства.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Да, именно так я и выравнивал. Я без доп. средств форматирую, руками.

(Все равно потом через doxygen прогоню. И там, в html будет все красиво.)

Мук не испытывал.

Потом все ровненько.

Я просто его (плагин) в списке Tools->Plugin Manager->Plugins не нашел.

Это git-changebar?

Gyros
() автор топика
Ответ на: комментарий от Gyros

Потом все ровненько.

Но при изменении кода опять выравнивать, поэтому мне этот стиль и не нравится, исправляешь что то в чужом проекте, потом выравниваешь, потому что невежливо оставлять нормальный стиль.

Это git-changebar?

Да.

MOPKOBKA ★★★★★
()

Стоит ли делать always_inline для простеньких функций в своей библиотеке?

Для начала я бы постарался добиться того, чтобы твоя чудо-программа просто работала, как задумано изначально.

А насчёт оптимизаций, на мой взгляд, можно не заморачиваться: подумаешь, картинка отрисуется на сотню миллисекунд позже - никто же не умрёт от этого. Включаешь режим «-О3» при сборке исходных текстов в компиляторе и всё.

Если не секрет, то откуда ты понабрался мыслей о значимости ручного ускорения своего кода? Кто этим сейчас ещё занимается и в какой отрасли? Я на сигнальном процессоре, работающем без операционной системы, и то не думал о ручном ускорении кода, а просто включал режим сборки «-О3».

Enthusiast ★★★
()