Определение выровненного требования к памяти на целевом процессоре - PullRequest
3 голосов
/ 18 февраля 2012

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

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

На «стандартном» процессоре x86 не требуется выравниваемый доступ к памяти, но это требуется многим другим процессорам и выдает исключение, если правило не соблюдается.

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

Проблема в том, что компилятор настолько осторожен, что в процессе теряется много производительности.

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

А теперь вопрос: как обнаружить во время компиляции, что целевая архитектура требует строго ориентированного доступа к памяти?(или наоборот)

Ответы [ 2 ]

5 голосов
/ 18 февраля 2012

Нет реализации C, о которой я знаю, которая предоставляет какой-либо макрос препроцессора, чтобы помочь вам понять это.Поскольку ваш код предположительно работает на широком спектре машин, я предполагаю, что у вас есть доступ к широкому кругу машин для тестирования, поэтому вы можете найти ответ с помощью тестовой программы.Затем вы можете написать свой собственный макрос, например, как показано ниже:

#if defined(__sparc__)
/* Unaligned access will crash your app on a SPARC */
#define ALIGN_ACCESS 1
#elif defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC)
/* Unaligned access is too slow on a PowerPC (maybe?) */
#define ALIGN_ACCESS 1
#elif defined(__i386__) || defined(__x86_64__) || \
      defined(_M_IX86) || defined(_M_X64)
/* x86 / x64 are fairly forgiving */
#define ALIGN_ACCESS 0
#else
#warning "Unsupported architecture"
#define ALIGN_ACCESS 1
#endif

Обратите внимание, что скорость неприсоединенного доступа будет зависеть от границ, которые он пересекает.Например, если доступ пересекает границу страницы 4 КБ, это будет намного медленнее, и могут быть другие границы, которые заставляют это быть еще медленнее.Даже на x86 некоторые невыровненные обращения не обрабатываются процессором, а обрабатываются ядром ОС.Это невероятно медленно.

Также нет гарантии, что будущая (или текущая) реализация не изменит внезапно характеристики производительности невыровненных обращений.Это произошло в прошлом и может произойти в будущем;PowerPC 601 очень простил доступ без выравнивания, а PowerPC 603e - нет.

Еще больше усложняет тот факт, что код, который вы пишете для создания выравниваемого доступа, будет отличаться по реализации на разных платформах.Например, в PowerPC это упрощается тем, что x << 32 и x >> 32 всегда равны 0, если x равен 32 битам, но на x86 вам не повезло.

5 голосов
/ 18 февраля 2012

В любом случае, написание кода для строгого выравнивания памяти - хорошая идея. Даже в системах x86, которые разрешают доступ без выравнивания, ваши операции чтения / записи с выравниванием вызовут два обращения к памяти, и некоторая производительность будет потеряна. Нетрудно написать эффективный код, который работает на всех архитектурах ЦП. Запомните простое правило: указатель должен быть выровнен по размеру объекта, который вы читаете или пишете. например если вы пишете DWORD, то (dest_pointer & 3 == 0). Использование костылей типа UNALIGNED_PTR приведет к тому, что компилятор сгенерирует неэффективный код. Если у вас есть большой объем унаследованного кода, который должен работать немедленно, тогда имеет смысл использовать компилятор, чтобы «исправить» ситуацию, но если это ваш код, то напишите его с самого начала, чтобы работать на всех системах. 1001 *

...