Да, как выравнивание, так и расположение ваших данных могут сильно повлиять на производительность, не только на несколько процентов, но и на несколько сотен процентов.
Возьмите этот цикл, две инструкции имеют значение, если вы запускаете достаточно циклов.
.globl ASMDELAY
ASMDELAY:
subs r0,r0,#1
bne ASMDELAY
bx lr
С кешем и без него, а также с выравниванием по кешу и без него в прогнозировании ветвлений, и вы можете значительно увеличить производительность этих двух команд (отметки времени):
min max difference
00016DDE 003E025D 003C947F
Тест производительности вы можете очень легко сделать самостоятельно. добавлять или удалять nops вокруг тестируемого кода и выполнять точную работу по времени, перемещать тестируемые инструкции по достаточно широкому диапазону адресов, чтобы касаться границ строк кэша и т. д.
То же самое с доступом к данным. Некоторые архитектуры жалуются на невыровненный доступ (например, при выполнении 32-битного чтения по адресу 0x1001), сообщая о сбое данных. Некоторые из них вы можете отключить сбой и принять удар производительности. Другие, которые разрешают несогласованные доступы, просто получают удар по производительности.
Иногда это «инструкции», но в большинстве случаев это циклы часов / шин.
Посмотрите на реализации memcpy в gcc для различных целей. Скажем, вы копируете структуру размером 0x43 байта, вы можете найти реализацию, которая копирует один байт, оставляя 0x42, а затем копирует 0x40 байтов большими эффективными блоками, а затем последний 0x2, который он может сделать как два отдельных байта или как 16-битную передачу. Выравнивание и цель вступают в игру, если адреса источника и назначения находятся на одном и том же выравнивании, скажем, 0x1003 и 0x2003, тогда вы можете сделать один байт, затем 0x40 большими блоками, затем 0x2, но если один равен 0x1002, а другой 0x1003, то он получает очень уродливый и очень медленный
Большую часть времени это автобусные циклы. Или хуже количество переводов. Возьмите процессор с шиной данных 64-битной ширины, такой как ARM, и выполните передачу четырех слов (чтение или запись, LDM или STM) по адресу 0x1004, то есть адрес с выравниванием по словам, и вполне допустимый, но если шина равна 64 в битах шириной вероятно, что одна инструкция превратится в три передачи, в этом случае 32 бита в 0x1004, 64 бита в 0x1008 и 32 бита в 0x100A. Но если бы у вас была та же инструкция, но по адресу 0x1008, она могла бы выполнить однократную передачу четырех слов по адресу 0x1008. Каждой передаче соответствует время установки. Таким образом, разница адресов от 0x1004 до 0x1008 может быть в несколько раз быстрее, даже / esp при использовании кеша, и все это попадания в кеш.
Говоря о том, что даже если вы выполняете чтение двух слов по адресу 0x1000 против 0x0FFC, 0x0FFC с пропусками кэша вызовет две операции чтения строки кэша, где 0x1000 - одна строка кэша, у вас есть штраф за чтение строки кэша в любом случае для случайного доступ (чтение большего количества данных, чем использование), но тогда это удваивается. То, как ваши структуры выровнены или ваши данные в целом, а также ваша частота доступа к этим данным и т. Д., Может привести к перегрузке кэша.
Вы можете в конечном итоге разделить ваши данные таким образом, чтобы при обработке данных вы могли создавать выселения, вы могли бы получить реальную неудачу и в конечном итоге использовать только часть своего кэша, а при переходе через него следующий блок данных сталкивался с предыдущим блоком. , Смешивая ваши данные или переупорядочивая функции в исходном коде и т. Д., Вы можете создавать или удалять коллизии, поскольку не все кэши создаются одинаково, компилятор не поможет вам в этом, он на вас. Даже обнаружение снижения производительности или улучшения на вас.
Все, что мы добавили для повышения производительности, более широкие шины данных, конвейеры, кэши, прогнозирование ветвлений, множественные исполнительные блоки / пути и т. Д. Наиболее часто помогает, но у всех них есть слабые места, которые можно использовать намеренно или случайно. Компилятор или библиотеки мало что могут с этим поделать, если вам интересна производительность, которую вам нужно настроить, и одним из самых больших факторов настройки является выравнивание кода и данных, а не только выравнивание по 32, 64, 128, 256 битовые границы, но также там, где все относительно друг друга, вы хотите, чтобы интенсивно используемые циклы или повторно используемые данные не попадали в один и тот же способ кэширования, каждый из которых хочет иметь свой собственный. Компиляторы могут помочь, например, упорядочить инструкции для суперскалярной архитектуры, переупорядочив инструкции, которые не имеют значения,
Самым большим упущением является предположение, что процессор является узким местом. Уже десять или более лет это не так, проблема заключается в питании процессора, и именно здесь возникают такие проблемы, как снижение производительности выравнивания, перегрузка кэша и т. Д. Небольшая работа даже на уровне исходного кода, переупорядочение данных в структуре, упорядочение объявлений переменных / структур, упорядочение функций в исходном коде и немного дополнительного кода для выравнивания данных могут в несколько раз повысить производительность или Больше.