C ++: сравнение производительности указателей, указывающих на различные местоположения в массиве символов (пытаясь изучить выравнивание) - PullRequest
3 голосов
/ 24 ноября 2010

Контекст:

char buffer[99]; int* ptr_int=(int*)(buffer+n);

Затем я выполняю некоторые трудоемкие операции с * ptr_int и измеряю время выполнения с помощью windows.h / QueryPerformanceCounter.

Путаница: Для значений n: от 0 до 4 время выполнения составляет около 12 секунд. Для значений n: 5,6,7 время выполнения составляет около 20 секунд. Для значения n: 32,33 время выполнения снова составляет около 12 секунд.с.

Это может быть связано с выравниванием, но может кто-нибудь объяснить, как именно?

Двухъядерный процессор Pentium T2410 / winxp / g ++ 3.4.2 (mingw-special)

Редактировать Я не пытаюсь избежать проблемы выравнивания, используя лучшие подходы, вместо этого я пытаюсь выяснить, почему у меня внезапно возникла проблема выравнивания с int* ptr_int=(int*)(buffer+5);

Нет проблем с: int* ptr_int=(int*)(buffer+3); ИЛИ int* ptr_int=(int*)(buffer+33);

Ответы [ 3 ]

1 голос
/ 24 ноября 2010

На современных процессорах данные должны быть выровнены должным образом, иначе придется платить.32-разрядное целое число должно быть выровнено на 4 байта, иначе ЦПУ будет внутренне необходимо прочитать два целых числа и переместить все по размеру.Некоторые процессоры действительно будут зависать, если вы попытаетесь прочитать целое без выравнивания.

Аналогично, 128-битный __vector4 должен быть выровнен на 16 байтов и т. Д.

Кстати, есть и другие факторыкоторые вступают в игру, например строка кэша данных, поэтому при первом обращении к новой строке кэша будет большой штраф - последующее чтение будет намного быстрее.

0 голосов
/ 24 ноября 2010

Скорее всего, как говорили другие, это проблема выравнивания.Теперь есть несколько способов исправить это и протестировать.

Самый простой - использовать malloc или new для выделения буфера в куче.Malloc гарантирует, что возвращаемый указатель будет пригоден для выравнивания самого большого собственного типа данных.На 64-битных чипах Intel это будет означать, что он выровнен по 128-битному двойному.

char * buffer = malloc( n * sizeof(int) );

int * at = (int*)buffer + ndx;

Похоже, ваш оригинал +n также был неверным.То, как вы это сделали, состояло в том, чтобы сместить char ptr на 1 байт, а не int ptr, на 4 байта.Это также может объяснить замедление, если вы копировали целые числа.Это потому, что вы могли непреднамеренно использовать целые числа, которые перекрывают одну и ту же область памяти.

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

char cbuffer[1024+sizeof(int)];
int * ibuffer = (cbuffer / sizeof(int) + 1) * sizeof(int);

Тогда ibuffer будет выровнено целым числом.Фактическое значение указателя может быть не таким, как для cbuffer, но в некоторых случаях оно может быть (зависит от стека во время вызова).Вторая строка - это простая математика для указателя, чтобы убедиться, что она кратна sizeof (int), что означает, что он выровнен по int.

new: Кто-нибудь может подтвердить, что new char[x] также гарантирует выравнивание какmalloc?

0 голосов
/ 24 ноября 2010

См. Отличную статью Ульриха Дреппера " Что каждый программист должен знать о памяти " для полного объяснения этой и других проблем с памятью, а также примеры тестов, которые вы можете запустить самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...