Store Forwarding penalties



Представьте вы пишете по указателю данные. Далее по этому указателю или где-то рядом вы читаете эти данные. Современные процессоры нынче очень хитрые и могут не читать память при такой инструкции. Это называется «store-to-load forwarding» и ускоряет программы, поскольку load инструкции не нужно ждать, пока данные будут записаны в кэш, а затем снова считываться. Пример такой последовательности очень простой:





movaps %xmm0, (%rsp) # Сохраняем 16 байт по адресу

mov 2(%rsp), %eax # Читаем 4 байта с адреса +2





Процессоры могут в регистр %eax сразу писать из регистра %xmm0 не дожидаясь пока в память будет что-то записано. Там есть всякие пенальти, если данные поменялись в другом треде походу этой оптимизации, но речь немного не о них сегодня.



Так получилось, что мы нашли какие-то безумные штрафы на Intel и Arm. Например



Intel:

1. Загрузить 2 байта write_unaligned<2>(ptr)

2. Прочитать второй следующей инструкцией read_unaligned<1>(ptr + 1)



Работает в 2-3 раза дольше, чем



1. Загрузить 2 байта write_unaligned<2>(ptr)

2. Прочитать первый read_unaligned<1>(ptr)



Решил сделать бенчмарк, который загружает Х байт (X = 2,4,8,16), читает Y байт (Y = 1,2,4,8,16) по оффсету Z (Z = 0..15) с условием, что Y + Z <= X. Получились цифры как на картинках для AMD Rome, Intel Skylake и Graviton 2.



Выводы



1. AMD всегда хорошо применяет эту оптимизацию

2. Intel плохо работает, если грузить 2-й байт при загрузке 2. Также плохо, если при загрузке 16 байт мы читаем 4/8, и они переходят границу в 8 байт (размер регистра, походу)

3. Arm работают плохо, кроме выравнивания по 0, reg_size/2.



Это важно всяким small string optimization, rope/cord, compressors, потому что они используют стек как данные и одновременно как идентификаторы, а большие или маленькие они.



Решил сделать бенчмарк, на Rust. https://github.com/danlark1/store_forwarding



Agner Fog писал про это, но мало.



Если поменять layout absl::Cord на обратный, Arm ускоряется, по табличке грузить 1 байт по оффсету 0 лучше, чем по 15 :)