Необходимо ли 8-байтовое выравнивание для "двойного" типа?
Я понимаю выравнивание слов, которое заставляет процессор читать только один раз при чтении целого числа в регистр.
Но необходимо ли 8-байтовое выравнивание (предположим, 32-битная система) для "двойного"? В чем выгода? Что произойдет, если место для хранения "двойника" будет просто 4-байтовым выравниванием?
5 ответов
Существует несколько аппаратных компонентов, на которые могут отрицательно повлиять выровненные нагрузки или хранилища.
- Интерфейс памяти может иметь ширину восемь байтов и иметь доступ к памяти только с кратностью восьми байтов. Загрузка невыровненного восьмибайтового двойника затем требует двух чтений на шине. Хранилища хуже, потому что выровненное восьмибайтовое хранилище может просто записать восемь байтов в память, но не выровненное восьмибайтовое хранилище должно прочитать два восьмибайтовых фрагмента, объединить новые данные со старыми данными и записать два восьмибайтовых фрагмента,
- Строки кэша обычно составляют 32 или 64 байта. Если восьмибайтовые объекты выровнены с кратными восьми байтам, то каждый объект находится в одной строке кэша. Если они не выровнены, то некоторые объекты частично находятся в одной строке кэша, а частично - в другой. Загрузка или хранение этих объектов требует использования двух строк кэша вместо одной. Этот эффект происходит на всех уровнях кеша (три уровня не редкость в современных процессорах).
- Системные страницы памяти обычно имеют размер 512 байт или более. Опять же, каждый выровненный объект находится на одной странице, но некоторые невыровненные объекты находятся на нескольких страницах. Каждая страница, к которой осуществляется доступ, требует аппаратных ресурсов: виртуальный адрес должен быть преобразован в физический адрес, для этого может потребоваться доступ к таблицам перевода, и должны быть обнаружены конфликты адресов. (Процессоры могут одновременно выполнять несколько операций загрузки и сохранения. Даже если ваша программа может показаться однопоточной, процессор заранее читает инструкции и пытается выполнить те из них, которые могут. Таким образом, процессор может запустить инструкцию загрузки перед предшествующим инструкции завершены. Однако, чтобы убедиться, что это не вызывает ошибки, процессор проверяет каждую инструкцию загрузки, чтобы убедиться, что она не загружается с адреса, на который изменяется предыдущая инструкция сохранения. Если доступ пересекает границу страницы, два части загруженных данных должны проверяться отдельно.)
Реакция системы на невыровненные операции варьируется от системы к системе. Некоторые системы предназначены для поддержки только согласованного доступа. В этих случаях не выровненный доступ вызывает либо исключения, которые приводят к завершению программы, либо исключения, которые вызывают выполнение специальных обработчиков, которые эмулируют невыровненные операции в программном обеспечении (выполняя выровненные операции и объединяя данные по мере необходимости). Программные обработчики, такие как они, намного медленнее, чем аппаратные операции.
Некоторые системы поддерживают невыровненный доступ, но для этого обычно требуется больше аппаратных ресурсов, чем для согласованного доступа. В лучшем случае оборудование выполняет две операции вместо одной. Но некоторое оборудование предназначено для запуска операций, как если бы они были выровнены, а затем, обнаружив, что операция не выровнена, прерывает ее и начинает заново, используя различные пути в оборудовании для обработки невыровненной операции. В таких системах невыровненный доступ имеет существенное ухудшение производительности, хотя он не так велик, как в системах, где программное обеспечение обрабатывает невыровненные доступы.
В некоторых системах аппаратное обеспечение может иметь несколько исполнительных блоков сохранения нагрузки, которые могут выполнять две операции, требуемые для невыровненного доступа, так же быстро, как один блок может выполнять операцию выровненных доступов. Таким образом, не происходит прямого снижения производительности неприровненных обращений. Однако, поскольку несколько исполнительных блоков остаются занятыми из-за невыровненного доступа, они недоступны для выполнения других операций. Таким образом, программы, которые выполняют много операций сохранения нагрузки, обычно параллельно, будут выполняться медленнее при невыровненных доступах, чем при совмещенных доступах.
На многих архитектурах доступ без выравнивания для любого модуля загрузки / хранения (short, int, long) является просто исключением. Компиляторы несут ответственность за обеспечение того, чтобы это не происходило с потенциально неверно выровненными данными, путем выдачи меньших инструкций доступа и повторной сборки в регистрах, если они не могут доказать, что данный указатель в порядке.
С точки зрения производительности, 8-байтовое выравнивание двойников в 32-битных системах может быть полезным по нескольким причинам. Наиболее очевидным является то, что 4-байтовое выравнивание 8-байтового двойного означает, что один элемент может пересекать границу двух строк кэша. Доступ к памяти происходит в единицах целых строк кэша, и, таким образом, несовпадение удваивает стоимость доступа.
Кажется, я помню, что рекомендация для 486 состояла в том, чтобы выровнять double на границах 32 бита, поэтому требование выравнивания на 64 бита не является обязательным.
Вы, кажется, думаете, что существует связь между шириной шины данных и разрядностью процессора. Хотя это часто бывает, вы можете найти вариации в обоих направлениях. Например, Pentium был 32-битным процессором, но его размер шины данных составлял 64 бита.
Кэши предлагают что-то еще, что может объяснить полезность наличия 64-битного выравнивания для 64-битных типов. Здесь внешняя шина не является фактором, важен размер строки кэша. Данные, пересекающие линейный кеш, более дороги для доступа, чем данные, не пересекающие их (даже если они не выровнены в обоих случаях). Выравнивание типов по размеру гарантирует, что они не будут пересекать строки кэша, если размер строки кэша кратен размеру типа.
Я только что нашел ответ:
6. Когда чтение памяти эффективно при чтении 4 байтов за раз на 32-битной машине, почему двойной тип должен быть выровнен по границе 8 байтов?
Важно отметить, что большинство процессоров будет иметь математический сопроцессор, называемый блоком с плавающей запятой (FPU). Любая операция с плавающей точкой в коде будет преобразована в инструкции FPU. Основной процессор не имеет ничего общего с выполнением с плавающей запятой. Все это будет сделано за кадром.
По стандарту двойной тип будет занимать 8 байт. И каждая операция с плавающей запятой, выполняемая в FPU, будет иметь длину 64 бита. Даже типы с плавающей запятой будут переведены в 64-битную версию перед выполнением.
64-битная длина регистров FPU заставляет двойной тип выделяться на 8-байтовой границе. Я предполагаю (у меня нет конкретной информации) в случае операций FPU, выборка данных может быть другой, я имею в виду шину данных, так как она идет в FPU. Следовательно, адресное декодирование будет отличаться для двойных типов (что ожидается на 8-байтовой границе). Это означает, что схемы декодирования адреса блока с плавающей запятой не будут иметь последние 3 контакта."
Отредактировано:
Преимущество выравнивания байтов заключается в уменьшении количества циклов памяти для извлечения данных. Например, 8 байтов, которые могут занять один цикл, если он выровнен, теперь могут занимать 2 цикла, поскольку часть его получается в первый раз, а вторая часть - в следующем цикле памяти.
Я сталкивался с этим: "Выровненный доступ быстрее, потому что внешняя шина к памяти имеет ширину не один байт - обычно она составляет 4 или 8 байтов (или даже шире). Таким образом, процессор не извлекает ни одного байта за раз - он выбирает 4 или 8 байтов, начиная с запрошенного адреса, поэтому 2 или 3 младших бита адреса памяти фактически не отправляются ЦП - внешняя память может считываться или записываться только по адресам, кратным ширина шины. Если вы запросите байт по адресу "9", ЦП фактически запросит у памяти блок байтов, начинающийся с адреса 8, и загрузит второй в ваш регистр (отбрасывая остальные).
Это означает, что неправильный доступ может потребовать две операции чтения из памяти: если вы запрашиваете 8 байтов, начиная с адреса 9, ЦП должен извлечь 8 байтов, начинающихся с адреса 8, а также 8 байтов, начинающихся с адреса 16, а затем замаскировать байты вы хотели. С другой стороны, если вы запрашиваете 8 байтов, начиная с адреса 8, то требуется только одна выборка. Некоторые процессоры даже не будут выполнять такую смещенную нагрузку - они просто вызовут исключение (или даже тихо загрузят неправильные данные!)."
Вы можете увидеть эту ссылку для более подробной информации. http://www.ibm.com/developerworks/library/pa-dalign/