Эффекты выравнивания данных (ошибок)

Я использую машину Intel x86 и Windows 7, а также Visual C ++ (версии 2005/2012 Express)

Я играл с выравниванием (я только делал это как учебное упражнение.) Конечно, я понимаю влияние на размер класса / структуры с точки зрения заполнения. Я полагаю, что я понимаю, что это также лучше выровнено из-за того, как инструкции процессора работают и ожидают данные.

Я смотрел на много разных ресурсов в целом, например (интересно)
C ++ выравнивание данных / порядок членов & наследование
(и другие ссылки, такие как Википедия) http://en.wikipedia.org/wiki/Data_structure_alignment

Похоже, что одной из областей, на которые это может повлиять (я читаю), является производительность, поскольку из-за того, что для регистров требуются данные определенного размера, смещение данных может вызвать проблемы (см. Википедию).

Я написал некоторый код, в котором я создал 3 структуры, все с одинаковыми элементами с упаковкой 1, нормальным выравниванием и перестановкой элементов. Это дало мне объекты с размерами 8, 10 и 12. Я запустил код, подобный следующему для каждого:

struct MixedData1
{
char Data1;
short Data2;
int Data3;
char Data4;

void operator() (MixedData1& md)
{
md.Data1 = 'a';
md.Data2 = 1024;
md.Data3 = 1000000;
md.Data4 = 'b';
}
};

typedef std::vector<MixedData1> MDVector;int main(int argc, char* argv[])
{
MixedData1 md;
for(int count = 0; count < 10 ; count++)
{
{
std::cout << sizeof(md) << std::endl;
boost::timer::auto_cpu_timer t;
MDVector mdv(10000000);
std::fill(mdv.begin(),mdv.end(),md );
std::for_each(mdv.begin(),mdv.end(),md);
}
}
}

Меня не очень интересуют значения, поэтому каждый элемент вектора инициализируется одинаково. В любом случае я получил результаты, которые показали, что время выполнения увеличилось с размером структуры — I.E с пакетом (1) (8 байт). Я получил самые быстрые 0,08 с, а с нормальным выравниванием (12 байт) я получил самый медленный 0,105.

Мои вопросы касаются последствий неправильного выравнивания. Я не думаю, что когда-либо у меня были какие-либо проблемы с выравниванием по всему Икс годы программиста на C ++, но, конечно, это могло бы просто пройти мимо меня.

(1) Выравнивание оказало влияние (я полагаю) в моем тесте (правка) однако, как написал Нейл, это было только из-за разницы в размере структуры. Я попытался получить доступ к участнику согласно его ответу, но я не увидел никакого реального эффекта там …. есть ли более ясный пример? Есть ли способ увидеть драматический эффект смещения?
(2) Есть ли способ вызвать сбой, вызванный смещением, если это возможно.

2

Решение

Все, что делает ваш код, это проверяет, насколько быстро процессор может копировать память. Чем больше памяти, тем медленнее копия. Выравнивание отдельных элементов в структуре не имеет значения для скорости копирования, важен только размер структуры.

Если вы хотите увидеть эффект выравнивания, вам нужно написать код, который фактически обращается к отдельным невыровненным элементам структуры. Например, вы можете написать цикл для увеличения членов data3 каждой структуры. В зависимости от архитектуры компилятор может понимать, что он должен использовать различные инструкции для выполнения арифметики; на x86 это обычно не так, и компилятор генерирует естественный код, потому что процессор способен справляться с не выровненным доступом. Некоторые процессоры могут фактически читать и записывать невыровненные данные с той же скоростью, что и выровненные данные. Тривиальным примером этого является 8088, поскольку он имеет только 8-битную шину данных, поэтому все 16-битные инструкции в любом случае эмулируются с использованием двух нагрузок, но последние процессоры тратят большую часть своего времени на чтение из строк кэша и, таким образом, единственное время, не выровненное данные могут иметь значение, когда данные пересекают строку кэша.

Если вы хотите вызвать сбой из-за смещения, то обычно вам нужно приводить указатели между различными типами. Компилятор может не всегда понимать, что ваш указатель может быть смещен, и не будет генерировать правильные инструкции для смещенного доступа. Например, вы можете попытаться вызвать инструкцию SSE для указателя типа char *.

4

Другие решения

Краткий ответ: на практике это не имеет значения.

И вот почему: 1 или 2 пропуска кэша могут занять менее миллисекунды, поэтому доступ к невыровненным данным будет проблемой только в том случае, если:

  1. Данные пересекают две строки кэша
  2. Вы получаете доступ к множеству невыровненных фрагментов данных, которые не являются непрерывными в памяти.

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

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

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector