Встроенная функция и стоимость вызова в C - PullRequest
3 голосов
/ 01 мая 2010

Я делаю библиотеку векторов / матриц. (GCC, ARM NEON, iPhone)

typedef struct{ float v[4]; } Vector;
typedef struct{ Vector v[4]; } Matrix;

Я передал struct data в качестве указателя, чтобы избежать снижения производительности при копировании данных при вызове функции. Итак, сначала я разработал такую ​​функцию:

void makeTranslation(const Vector* factor, Matrix* restrict result);

Но, если функция встроенная, есть ли причина передавать значения в качестве указателя производительности? Эти переменные тоже копируются? Как насчет регистрации и кешей? Я попытался изменить функцию так:

inline Matrix makeTranslation(const Vector factor) __attribute__ ((always_inline));

Как вы относитесь к стоимости звонков в каждом случае?

  • Я добавил 'const' во 2-ю подпись, чтобы отразить предложения.

1 Ответ

3 голосов
/ 01 мая 2010

Когда функция встроенная, как правило, копирование переменных напрямую не связано с вызовом. Переменные по-прежнему будут перемещаться и помещаться в стек иногда как обычная часть выполнения, но не как прямой результат вызова функции. (Когда у вас заканчиваются регистры, некоторые значения могут быть помещены в стек и т. Д., Но только в случае необходимости.) Таким образом, накладные расходы на «вызов» в основном исчезают, когда функция встроена (больше никаких настроек / сносов) кадр стека, больше нет безусловного перехода, больше нет параметров push / poping.)

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

Из-за передачи по указателю этот код ВСЕГДА будет иметь инструкцию для получения адреса объекта и, по крайней мере, одну разыменование для получения значения элемента. Если вы передадите по значению, это МОЖЕТ произойти, но компилятор МОЖЕТ оптимизировать все это.

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

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