Выравнивание памяти на 32-разрядном процессоре Intel
32-разрядные процессоры Intel, такие как Pentium, имеют 64-разрядную шину данных и поэтому получают 8 байт на доступ. Исходя из этого, я предполагаю, что физические адреса, которые эти процессоры излучают на адресной шине, всегда кратны 8.
во-первых, правильно ли это заключение?
во-вторых, если это правильно, то следует выровнять элементы структуры данных на 8-байтовой границе. Но я видел людей, использующих 4-байтовое выравнивание вместо этих процессоров.
как они могут быть оправданы в этом?
5 ответов
обычное эмпирическое правило (прямо из руководств Intels и AMD по оптимизации) заключается в том, что каждый тип данных должен быть выровнен по своему размеру. Ан int32
должен быть выровнен по 32-битной границе,int64
на 64-битной границе, и так далее. Чар подойдет где угодно.
другое эмпирическое правило, конечно же, "компилятору было сказано о требованиях к выравниванию". Вам не нужно беспокоиться об этом, потому что компилятор знает, чтобы добавить правильное заполнение и смещения, чтобы разрешить эффективный доступ к данным.
единственным исключением является работа с инструкциями SIMD, где вы должны вручную обеспечить выравнивание на большинстве компиляторов.
во-вторых, если это правильно, то одного следует выровнять элементы структуры данных по 8-байтовую границу. Но я видел люди, использующие 4-байтовое выравнивание вместо этого на этих процессорах.
Я не вижу, как это делает разницу. CPU может просто выдать чтение для 64-битного блока, который содержит 4 байта. Это означает, что он получает 4 дополнительных байта до запрошенных данных или после них. Но в обоих случаях требуется только одно чтение. 32-разрядное выравнивание 32-разрядных данных гарантирует, что оно не пересечет 64-разрядную границу.
физическая шина шириной 64 бит ...кратно 8 --> да
однако, есть еще два фактора для рассмотрения:
- некоторый набор инструкций x86 адресован байтом. Некоторые из них выровнены по 32bit (поэтому у вас есть 4-байтовая вещь). Но никакая (основная) инструкция не выровнена по 64bits. CPU может обрабатывать несоосный доступ к данным.
- если вы заботитесь о производительности, вы должны думать о строке кэша, а не основной памяти. Строки кэш-памяти значительно более широкий.
они оправданы в этом, потому что изменение на 8-байтовое выравнивание будет представлять собой изменение ABI, и предельное улучшение производительности не стоит проблем.
Как кто-то уже сказал, cachelines дело. Все обращения к фактической шине памяти осуществляются с точки зрения строк кэша (64 байта на x86, IIRC). Смотрите "что каждый программист должен знать о памяти" ДОК, о котором уже упоминал. Так что реальный трафик выравнивается 64 байта.
64-битная шина, на которую вы ссылаетесь, подает кэши. Как CPU, всегда считывайте и записывайте целые строки кэша. Размер строки кэша всегда кратен 8, и ее физический адрес действительно выровнен на 8 байтовых смещениях.
передача кэша в регистр не использует внешнюю базу данных, поэтому ширина этой шины не имеет значения.
для случайного доступа и до тех пор, пока данные не смещены (например, пересечение границы), я не думаю, что это имеет большое значение; правильный адрес и смещение в данных можно найти с помощью простого и конструктивного оборудования. Он становится медленным, когда одного доступа для чтения недостаточно для получения одного значения. Вот почему компиляторы обычно помещают небольшие значения (байты и т. д.) вместе, потому что они не должны быть на определенном смещении; шорты должны быть на четных адресах, 32-бит на 4-байтовых адресах и 64-разрядные 8-байтовые адреса.
обратите внимание, что если у вас есть кэширование и линейный доступ к данным, все будет по-другому.