Информация об изменениях

Сообщение Re: new vs. malloc от 26.04.2018 9:55

Изменено 26.04.2018 10:11 watchmaker

Re: new vs. malloc
Здравствуйте, _NN_, Вы писали:

_NN>Если вручную определить в своём проекте new, то можем получить существенное ускорение

Я согласен, что лучше бы иметь такое свойство изначально, чем не иметь. Но не считаю, что этого достаточно.
В этом примере память используется сразу после выделения malloc'ом или new. Но как часто такая ситуация встречается в программах? Кажется, что обычно память выделяется где-то в одном месте, а используется чуть в другом. А между ними встречается всякая логика RAII, которая позволяет не утечь памяти, но при этом которая сохраняет указатель где-то в своих внутренностях (т.е. создавая возможность для alising'а где-то в другом месте). Или память может выделяться из memory-pool и возвращаться в него неоднократно. Или к ней может быть слишком сложный способ доступа (как, например, в in-place алгоритмах умножения Штрассена, где доказательство отсутствия aliasing — это предмет целой научной статьи).
То есть обычно у компилятора просто недостаточно ресурсов чтобы сохранить это свойство от момента выделения памяти, до момента её использования. Есть десяток мест, где можно эту информацию потерять, так как компилятор не сможет доказать отсутствие aliasing.

Считаю, что наивно было бы полагать, что компилятор сумеет всегда дотащить нужные атрибуты от далёкого new или malloc.
Поэтому, если нужна векторизация в критичном по производительности месте, используют другой подход: пишут restrict у переменных, а не у функций.
В примере по ссылке приведена сигнатура функции
void multiply(float * a, float * b, float * c)

Но гораздо надёжнее было бы просто написать
void multiply(float * a, float * b, float * restrict c)

То есть просто сказать, что программой и программистом гарантируется, что память под c не пересекается с a или b. И пусть компилятор оптимизирует исходя из этой гарантии. А уж каким способом выделена память под матрицы не важно: malloc это, или глобальный массив, или может вообще отображение файла в память.
Re: new vs. malloc
Здравствуйте, _NN_, Вы писали:

_NN>Если вручную определить в своём проекте new, то можем получить существенное ускорение

Я согласен, что лучше бы иметь такое свойство изначально, чем не иметь. Но не считаю, что этого достаточно.
В этом примере память используется сразу после выделения malloc'ом или new. Но как часто такая ситуация встречается в программах? Кажется, что обычно память выделяется где-то в одном месте, а используется чуть в другом. А между ними встречается всякая логика RAII, которая позволяет не утечь памяти, но при этом которая сохраняет указатель где-то в своих внутренностях (т.е. создавая возможность для alising'а где-то в другом месте). Или память может выделяться из memory-pool и возвращаться в него неоднократно. Или к ней может быть слишком сложный способ доступа (как, например, в in-place алгоритмах умножения Штрассена, где доказательство отсутствия aliasing — это предмет целой научной статьи).
То есть обычно у компилятора просто недостаточно ресурсов чтобы сохранить это свойство от момента выделения памяти, до момента её использования. Есть десяток мест, где можно эту информацию потерять, так как компилятор не сможет доказать отсутствие aliasing.

Считаю, что наивно было бы полагать, что компилятор сумеет всегда дотащить нужные атрибуты от далёкого new или malloc.
Поэтому, если нужна векторизация в критичном по производительности месте, используют другой подход: пишут restrict у переменных, а не у функций.
В примере по ссылке приведена сигнатура функции
void multiply(float * a, float * b, float * c)

Но гораздо надёжнее было бы просто написать
void multiply(float * a, float * b, float * restrict c)

То есть просто сказать, что программой и программистом гарантируется, что память под c не пересекается с a или b. И пусть компилятор оптимизирует исходя из этой гарантии. А уж каким способом выделена память под матрицы не важно: malloc это, или глобальный массив, или может вообще отображение файла в память.


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