Инструкция MOVDQU + граница страницы
У меня есть простая тестовая программа, которая загружает регистр xmm с инструкцией movdqu для доступа к данным через границу страницы (OS = Linux).
Если следующая страница сопоставлена, это работает просто отлично. Если это не отображается, то я получаю SIGSEGV, что, вероятно, ожидается.
Однако это значительно снижает полезность невыровненных нагрузок. Кроме того, инструкции SSE4.2 (например, pcmpistri), которые допускают невыровненные ссылки на память, также демонстрируют это поведение.
Это все нормально - за исключением того, что есть много реализаций strcmp с использованием pcmpistri, которые, как я обнаружил, вообще не решают эту проблему, - и я смог создать тривиальные тестовые случаи, которые приведут к сбою этих реализаций, в то время как тривиальная реализация strcmp побайтового времени будет отлично работать с той же разметкой данных.
Еще одно замечание - похоже, что реализация библиотеки GNU C для 64-битного Linux имеет вариант __strcmp_sse42, который, по-видимому, использует инструкцию pcmpistri более безопасным образом. Реализация этого strcmp довольно сложна, но, похоже, она старается избежать проблемы с границами страницы. Я не уверен, связано ли это с проблемой, которую я описал выше, или это просто побочный эффект от попыток повысить производительность путем выравнивания данных.
Во всяком случае, у меня вопрос в первую очередь - где я могу узнать больше об этой проблеме? Я набрал "пересечение границы страницы movdqu" и все варианты, которые я могу придумать для Google, но не нашел ничего особенно полезного. Если кто-то может указать мне на дополнительную информацию по этому вопросу, это было бы очень признательно.
2 ответа
Во-первых, любой алгоритм, который пытается получить доступ к не отображенному адресу, вызовет SegFault. Если поток кода не AVX использовал 4-байтовую загрузку для доступа к последнему байту страницы и первым 3 байтам "следующей страницы", которые, как оказалось, не были отображены, то это также вызвало бы SegFault. Нет? Я считаю, что "проблема" заключается в том, что регистры AVX(1/2/3) намного больше, чем "типичные", что алгоритмы, которые были небезопасны (но им это не удавалось), попадают в ловушку, если их тривиально распространить на более крупные регистры.,
У выравниваемых нагрузок (MOVDQA) никогда не может быть этой проблемы, поскольку они не пересекают границ своего собственного размера или больше. Нераспределенные нагрузки МОГУТ иметь эту проблему (как вы заметили) и "часто". Причина этого заключается в том, что инструкция определена для загрузки полного размера целевого регистра. Вам нужно внимательно посмотреть на типы операндов в определениях инструкций. Неважно, какая часть данных вас интересует. Важно, для чего предназначена инструкция.
Тем не мение...
AVX1 (Sandybridge) добавил возможность "замаскированного перемещения", которая работает медленнее, чем movdqa или movdqu, но не будет (архитектурно) обращаться к не отображенной странице, если маска не включена для той части доступа, которая упала бы на этой странице, Это предназначено для решения проблемы. В целом, продвигаясь вперед, кажется, что замаскированные части (см. AVX512) нагрузок / хранилищ также не вызовут нарушений доступа на IA.
(Это облом из-за поведения PCMPxSTRx. Возможно, вы могли бы добавить 15 байтов заполнения для ваших "строковых" объектов?)
Столкнувшись с подобной проблемой с библиотекой, которую я писал, я получил некоторую информацию от очень полезного автора.
Суть идеи состоит в том, чтобы выровнять 16-байтовые чтения по концу строки, а затем обработать оставшиеся байты в начале. Это работает, потому что конец строки должен находиться на доступной странице, и вам гарантируется, что усеченный 16-байтовый начальный адрес также должен находиться на доступной странице.
Поскольку мы никогда не читаем за строкой, мы не можем потенциально попасть на защищенную страницу.
Для обработки начального набора байтов я решил использовать PCMPxSTRM
функции, которые возвращают битовую маску совпадающих байтов. Тогда это просто вопрос сдвига результата, чтобы игнорировать любые биты маски, которые встречаются до истинного начала строки.