Как много прирост скорости при использовании __INLINE__? - PullRequest
0 голосов
/ 16 января 2019

В моем понимании, INLINE может ускорить выполнение кода, не так ли?

Какую скорость мы можем получить от этого?

Ответы [ 3 ]

0 голосов
/ 16 января 2019

Использование inline заставляет систему использовать модель замещения оценки , но это не гарантируется для постоянного использования.Если это используется, сгенерированный код будет длиннее и может быть быстрее, но если активны некоторые оптимизации, модель Sustitution не будет быстрее не все время.

0 голосов
/ 16 января 2019

Причина, по которой я использую inline спецификатор функции (в частности, static inline), не из-за "скорости", а потому, что часть

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

  2. inline часть сообщает компилятору, что она может включать реализацию функции при вызовеsite, если он хочет

  3. static inline сообщает компилятору, что он может полностью пропустить функцию, если она вообще не используется в текущем модуле перевода

    (В частности, компилятор, который я использую чаще всего с опциями, которые я использую чаще всего, gcc -Wall, выдает предупреждение, если функция, помеченная static, не используется, но не выдает предупреждение, если функция, помеченная static inline, не используется.)

  4. static inline сообщает нам, что эта функция является вспомогательной функцией, подобной макросу, и дополнительно добавляет средство проверки типов к тому же поведению, что и макрос.

Таким образом, в моем опиnion, предположение, что inline имеет какое-либо отношение к speed per se, неверно.Ответ на поставленный вопрос прямым ответом будет вводить в заблуждение.


В моем коде вы видите их связанные с некоторыми структурами данных или иногда глобальными переменными.

Типичным примером является случай, когдаЯ хочу реализовать генератор псевдослучайных чисел Xorshift в своем собственном коде C:

#include <inttypes.h>

static uint64_t  prng_state = 1; /* Any nonzero uint64_t seed is okay */

static inline uint64_t  prng_u64(void)
{
    uint64_t  state;

    state = prng_state;
    state ^= state >> 12;
    state ^= state << 25;
    state ^= state >> 27;
    prng_state = state;

    return state * UINT64_C(2685821657736338717);
}

static uint64_t prng_state = 1; означает, что prng_state является переменной типа uint64_t, видимой тольков текущем модуле компиляции и инициализируется значением 1. Функция prng_u64() возвращает беззнаковое 64-битное псевдослучайное целое число.Однако, если вы не используете prng_u64(), компилятор также не будет генерировать для него код.

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

#ifndef   GRID_H
#define   GRID_H
#include <stdlib.h>

typedef struct {
    int            rows;
    int            cols;
    unsigned char *cell;
} grid;
#define  GRID_INIT { 0, 0, NULL }

#define  GRID_OUTSIDE -1

static inline int grid_get(grid *const g, const int row, const int col)
{
    if (!g || row < 0 || col < 0 || row >= g->rows || col >= g->cols)
        return GRID_OUTSIDE;
    return g->cell[row * (size_t)(g->cols) + col];
}

static inline int grid_set(grid *const g, const int row, const int col,
                           const unsigned char value)
{
    if (!g || row < 0 || col < 0 || row >= g->rows || col >= g->cols)
        return GRID_OUTSIDE;
    return g->cell[row * (size_t)(g->cols) + col] = value;
}

static inline void grid_init(grid *g)
{
    g->rows = 0;
    g->cols = 0;
    g->cell = NULL;
}

static inline void grid_free(grid *g)
{
    free(g->cell);
    g->rows = 0;
    g->cols = 0;
    g->cell = NULL;
}

int grid_create(grid *g, const int rows, const int cols,
                const unsigned char initial_value);

int grid_load(grid *g, FILE *handle);

int grid_save(grid *g, FILE *handle);

#endif /* GRID_H */

Этот заголовочный файл определяет некоторые полезные вспомогательные функции и объявляет функции grid_create(), grid_load() и grid_save(), которые будут реализованы в отдельном файле .c.

(Да, эти три функции можно было бы также реализовать в заголовочном файле , но это сделало бы заголовочный файл довольно большим. Если у вас был большой проект, распределите его по множеству единиц перевода(исходные файлы .c), каждый из которых, включая файл заголовка, получал бы свои собственные локальные копии функций. Функции доступа, определенные как static inline выше, являются короткими и тривиальными, так что их вполне можно копировать здесь и там.. Три функции, которые я пропустил, намного больше.)

0 голосов
/ 16 января 2019

Разорвано с здесь :

Да и нет. Иногда. Может быть.

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

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

встроенные функции могут замедлять работу : слишком большое встраивание может привести к раздуванию кода, что может вызвать «перебои» в системах виртуальной памяти с подкачкой. Другими словами, если размер исполняемого файла слишком велик, система может проводить большую часть своего времени, выходя на диск, чтобы получить следующий фрагмент кода.

встроенные функции могут сделать его больше : это понятие раздувания кода, как описано выше. Например, если система имеет 100 встроенных функций, каждая из которых расширяется до 100 байт исполняемого кода и вызывается в 100 местах, это увеличение на 1 МБ. Это 1 МБ будет вызывать проблемы? Кто знает, но возможно, что последние 1 МБ могут вызвать «зависание» системы, что может замедлить процесс.

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

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

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

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

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

встроенные функции могут не иметь отношения к скорости : большинство систем не привязаны к процессору. Большинство систем привязаны к вводу / выводу, к базе данных или к сети, что означает, что узким местом в общей производительности системы является файловая система, база данных или сеть. Если ваш «измеритель ЦП» не установлен на 100%, встроенные функции, вероятно, не сделают вашу систему быстрее. (Даже в системах с привязкой к ЦП встроенный метод поможет только при использовании внутри самого узкого места, а узкое место обычно составляет лишь небольшой процент кода.)

Нет простых ответов : Вы должны поиграть с ним, чтобы увидеть, что лучше. Не соглашайтесь на упрощенные ответы, такие как «Никогда не используйте встроенные функции» или «Всегда используйте встроенные функции» или «Используйте встроенные функции, если и только если функция меньше N строк кода». Эти правила одного размера могут быть легко записаны, но они приведут к неоптимальным результатам.

Авторские права (C) Marshall Cline

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