Инструкция MOVDQU + граница страницы

У меня есть простая тестовая программа, которая загружает регистр xmm с инструкцией movdqu для доступа к данным через границу страницы (OS = Linux).

Если отображается следующая страница, это работает нормально. Если он не сопоставлен, я получаю SIGSEGV, что, вероятно, ожидаемо.

Однако это несколько снижает полезность невыровненных нагрузок. Кроме того, инструкции SSE4.2 (например, pcmpistri), которые позволяют использовать невыровненные ссылки на память, также демонстрируют это поведение.

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

Еще одно замечание - похоже, что реализация библиотеки GNU C для 64-битной Linux имеет вариант __strcmp_sse42, который, по-видимому, использует инструкцию pcmpistri более безопасным образом. Реализация этого strcmp довольно сложна, но, похоже, она тщательно пытается избежать проблемы с границами страницы. Я не уверен, связано ли это с проблемой, которую я описал выше, или это просто побочный эффект попытки повысить производительность за счет выравнивания данных.

В любом случае, у меня в первую очередь вопрос - где я могу узнать больше об этой проблеме? Я ввел «movdqu, пересекающий границу страницы» и все варианты, которые я мог придумать для Google, но не нашел ничего особенно полезного. Если кто-нибудь может указать мне на дополнительную информацию по этому поводу, я был бы очень признателен.


person user3299291    schedule 11.02.2014    source источник
comment
Реализация __strcmp_sse42, вероятно, делает это, чтобы избежать снижения производительности при пересечении границы страницы. Процессоры Intel (не уверен в последних версиях) всегда демонстрировали ужасающую производительность при несогласованном доступе, выходящем за границы страницы. Однако проблема с ошибкой страницы не должна иметь значения.   -  person Mysticial    schedule 12.02.2014
comment
Мне очень любопытен ответ на этот вопрос. В Руководстве по оптимизации Intel (раздел 10.3.6) только сказано, что при доступе к невыровненной 128-битной памяти SIMD можно извлекать данные межстраничной границы, поскольку системное программное обеспечение управляет правами доступа к памяти с детализацией страницы. Может быть, попробуйте воспроизвести ту же ошибку в какой-нибудь другой ОС?   -  person Daniel Kamil Kozar    schedule 12.02.2014
comment
Или, скорее, ОС отреагирует на ошибку страницы и внесет ее в страницу - невидимая для приложения (кроме огромного снижения производительности). Или завершите работу приложения, если оно не выделено. В этом случае это стандартный UB от доступа к нераспределенной памяти.   -  person Mysticial    schedule 12.02.2014
comment
В чем именно проблема? strcmp также сгенерирует SIGSEG, если вы передадите незавершенную строку и позволите ей перейти на не отображенную страницу. Это как раз то, что делает доступ к несопоставленной странице.   -  person Damon    schedule 12.02.2014
comment
В ответ на последний комментарий ... Я тщательно построил тест, в котором строка находится со смещением 4090 страницы 4K с тестом значения и байтом '\ 0'. Следующая страница памяти не отображается. Когда я использую strcmp с этой строкой в ​​качестве аргумента, все работает нормально. Когда я пробую сопоставимую инструкцию pcmpistri, делается попытка загрузить весь 16-байтовый блок - переход на следующую страницу, запускающий SIGSEGV. Это то, что ограничивает для меня полезность pcmpistri, а также то, почему мне интересно узнать о некоторых реализациях strcmp, использующих его, которые я нашел.   -  person user3299291    schedule 12.02.2014


Ответы (2)


Во-первых, любой алгоритм, который пытается получить доступ к несопоставленному адресу, вызовет SegFault. Если поток кода, отличного от AVX, использовал 4-байтовую загрузку для доступа к последнему байту страницы и первым 3 байтам «следующей страницы», которые оказались не отображенными, то это также вызвало бы SegFault. Нет? Я считаю, что «проблема» в том, что регистры AVX (1/2/3) намного больше, чем «типичные», что алгоритмы, которые были небезопасными (но безнаказанно), попадают в ловушку, если их тривиально расширить до более крупных регистров. .

Выровненные нагрузки (MOVDQA) никогда не могут иметь этой проблемы, поскольку они не пересекают границ своего собственного размера или больше. Невыровненные нагрузки МОГУТ иметь эту проблему (как вы отметили) и "часто". Причина этого в том, что инструкция определена для загрузки полного размера целевого регистра. Вам нужно внимательно изучить типы операндов в определениях инструкций. Не имеет значения, какая часть данных вас интересует. Важно то, для чего предназначена инструкция.

Тем не мение...

AVX1 (Sandybridge) добавил возможность «маскированного перемещения», которая работает медленнее, чем movdqa или movdqu, но не будет (архитектурно) обращаться к несопоставленной странице, пока маска не включена для той части доступа, которая упала бы на эту страницу. . Это предназначено для решения проблемы. В общем, продвигаясь вперед, оказывается, что замаскированные части (см. AVX512) загрузок / хранилищ также не вызовут нарушений доступа на IA.

(Это облом по поводу поведения PCMPxSTRx. Возможно, вы могли бы добавить 15 байтов заполнения к своим "строковым" объектам?)

person Mike Julier    schedule 20.06.2014

Столкнувшись с аналогичной проблемой с библиотекой, которую я писал, я получил некоторую информацию от очень полезного участник.

Суть идеи состоит в том, чтобы выровнять 16-байтовые чтения с концом строки, а затем обработать оставшиеся байты в начале. Это работает, потому что конец строки должен находиться на доступной странице, и вам гарантируется, что усеченный 16-байтовый начальный адрес также должен находиться на доступной странице.

Поскольку мы никогда не читаем строку дальше, мы не можем потенциально попасть на защищенную страницу.

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

person Shepmaster    schedule 17.05.2015