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
()

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

loglogav
()

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

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

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

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

mittorn ★★★★★
()

есть же cglm

anonymous
()

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

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

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

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

a1ba ★★★
()

Кстати так макросы пишут только в Си++ (или, возможно, новомодных Сях с расширениями). В Си пишут do { ... } while(0);

zx_gamer ★★★
()

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

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

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)

Стиль у тебя конечно безумный в ОП-посте %) Я на сохранение в редакторе настроил запуск clang-format для своих проектов. Набираю в итоге как попало, а после сохранения он делает красиво.

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

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

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

Gyros
() автор топика
Ответ на: комментарий от 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 ★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.