Я декомпилирую двоичный файл, построенный на C ++, и заметил, что при распределении и перераспределении строк буферы выравниваются до ближайших 32 байтов, когда размер буфера ('alloc_bytes')> = 0x1000. Вот мой декомпилированный код, иллюстрирующий это:

if (alloc_bytes < 0x1000)
{
    new_char_buffer = STD__allocate_bytes(alloc_bytes)
}
else
{
    void *new_buffer_start = STD__allocate_bytes(alloc_bytes + 0x20 + 0x07)

    new_char_buffer = new_buffer_start + 0x20 + 0x07
    new_char_buffer = new_buffer_start & 0xffffffffffffffe0 // round to lower 0x20
    *(new_char_buffer -0x08) = new_buffer_start // guaranteed valid memory after rounding because we allocated 0x20 (32) plus an additional 0x07 (7)
}

Здесь, если alloc_bytes достаточно велик, начало буфера строки округляется до младших 0x20 байтов, а затем «реальное» начало буфера сохраняется за ним. Мне это кажется пустой тратой места, потому что я не понимаю никаких возможных причин, по которым выравнивание начала строкового буфера, как это, могло бы привести к улучшению производительности. Есть ли какая-то польза от выравнивания такого буфера, или для понимания рассуждений требуется больше контекста?

1
RecyclingBen 3 Май 2021 в 23:45

1 ответ

Лучший ответ

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

Прямые I инструкции M Конечные D инструкции - это операции, которые позволяют получить очень дешевый параллелизм. Однако у них действительно есть некоторые требования, прежде чем вы или, что более вероятно, ваш компилятор сможете их эффективно использовать.

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

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

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

N.B. На самом деле это не 4 раза. Авто-векторизованные циклы обычно имеют префиксную и постфиксную секцию для работы с несогласованными данными, поэтому реальный выигрыш заключается в том, чтобы просто пропустить префикс и перейти прямо к векторизованному циклу. Но эти технические детали не имеют большого значения для вашего вопроса.

3
Frank 3 Май 2021 в 22:36