2016-06-09 1 views
6

정렬되지 않은로드를 수행하거나 페이지 경계 옆에 저장할 때 (예 : _mm_loadu_si128/_mm_storeu_si128 내장 함수를 사용하는 경우) 코드는 먼저 전체 벡터 (이 경우 16 바이트) 동일한 페이지에 속하며 그렇지 않은 경우 비 벡터 명령으로 전환합니다. 다음 페이지가 처리에 속하지 않는 경우 코어 덤프를 방지하는 데 필요하다는 것을 알고 있습니다.SSE : 페이지 경계를 넘는 정렬되지 않은로드 및 저장

하지만 두 페이지가 모두 프로세스에 속한 경우 (예 : 한 페이지가 한 개의 버퍼에 포함되어 있고 해당 버퍼의 크기를 알고있는 경우) 어떻게해야합니까? 정렬되지 않은로드를 수행하고 페이지 경계를 넘어서서 저장하는 작은 테스트 프로그램을 작성했으며 충돌하지 않았습니다. 이 경우 페이지 경계를 항상 확인해야합니까, 아니면 버퍼 오버플로를 방지 할만큼 충분합니까?

봉투 : 리눅스, x86_64에, GCC

답변

7

페이지 줄 분할 성능에 대한 나쁜 있지만, 정렬되지 않은 액세스의 정확성에 영향을 미치지 않습니다. 길이가 미리 알면 버퍼 끝을지나 읽지 않도록하십시오.


는 정확성을 위해, 당신은 자주 당신이 감시 값을 찾을 때 루프가 중지 strlen, 같은 것을 구현할 때 걱정해야합니다. 이 값은 벡터 내의 어느 위치 에나있을 수 있으므로 16B 정렬되지 않은로드를 수행하면 배열의 끝을지나 읽습니다. 0 종료가 한 페이지의 마지막 바이트에 있고 다음 페이지를 읽을 수없고 현재 위치 포인터가 정렬되지 않은 경우 0 바이트를 포함하는로드에는 읽을 수없는 페이지의 바이트도 포함되므로 오류가 발생합니다 .

한 가지 해결책은 포인터가 정렬 될 때까지 스칼라를 수행 한 다음 정렬 된 벡터를로드하는 것입니다. 정렬 된로드는 항상 한 페이지에서 이루어지며 하나의 캐시 라인에서도 발생합니다. 따라서 문자열의 끝 부분을지나 몇 바이트를 읽지 만 실수하지 않을 것입니다. Valgrind에 대해서는 불만 스러울 지 모르지만 표준 라이브러리 strlen 구현에서는 이것을 사용합니다.

정렬 된 포인터까지 스칼라 대신 문자열 시작 부분에서 정렬되지 않은 벡터를 수행하고 (페이지 줄을 넘지 않는 한) 정렬 된로드를 수행 할 수 있습니다. 첫 번째로 정렬 된로드는 첫 번째 정렬되지 않은로드와 겹치지 만 strlen과 같은 함수에서는 완전히 똑같습니다. 동일한 데이터를 두 번 보는 경우에는 상관 없습니다.


성능상의 이유로 페이지 줄이기를 피하는 것이 좋습니다. src 포인터가 잘못 정렬 되더라도 하드웨어가 캐시 라인 분할을 처리하도록하는 것이 더 빠릅니다. 그러나 Skylake가 출시되기 전에는 페이지 분할에 100c의 대기 시간이 추가되었습니다. (Down to 5c in Skylake). 서로 다르게 정렬 할 수있는 여러 포인터가있는 경우에는 항상 프롤로그를 사용하여 src를 정렬 할 수있는 것은 아닙니다. (예를 들어 c[i] = a[i] + b[i]c 정렬하지만 b은 아닙니다.)이 경우

, 그것은 앞에서 및 페이지 분할 후로드를 정렬 할 수있는 지점을 사용하여 가치, 그리고 palignr와 조합 할 수도 있습니다.

분기 예측 오류 (~ 15c)는 페이지 분할 대기 시간보다 저렴하지만로드뿐만 아니라 모든 것을 지연시킵니다. 따라서 이 아닌이 하드웨어와 계산에 대한 메모리 액세스 비율에 따라 가치가 있습니다.


당신이 정렬 포인터로 호출 일반적으로하는 함수를 작성하는 경우, 그냥 정렬되지 않은로드/저장 명령어를 사용하는 의미가 있습니다. 정렬 오류를 감지하는 모든 프롤로그는 이미 정렬 된 경우에 대한 추가 오버 헤드 일 뿐이며 현대 하드웨어 (Nehalem 및 그 이상)에서는 런타임에 정렬되도록 정렬되지 않은 주소의로드가 정렬 된로드 명령어와 동일한 성능을 보입니다. (그러나 정렬되지 않은로드가 메모리 피연산자와 같은 다른 명령어로 접히기 위해서는 AVX가 필요합니다. 예 : vpxor xmm0, xmm1, [rsi])

정렬되지 않은 입력을 처리하는 코드를 추가하면 일반적으로 정렬 된 대소 문자가 느려져 비 정렬 불일치가 발생합니다. 정렬되지 않은로드/저장소에 대한 빠른 하드웨어 지원을 통해 소프트웨어는 발생하는 경우가 거의없는 경우 하드웨어에 그대로 남겨 둡니다. 잘못 정렬 된 입력이 일반적인 경우

는 (다음 는 ESP, 귀하의 의견 포인터를 정렬하는 프롤로그를 사용하는 것이 가치가입니다. 당신이 온라인을 캐시합니다 AVX. 연속 32B AVX 부하를 사용하는 경우 다른 모든 부하를 분할합니다.)

자세한 내용은 Agner Fog's Optimizing Assembly guide 태그 위키의 다른 링크를 참조하십시오.

+0

@ ZheyuanLi : 예, 궁금한 점이 있습니다. Skylake는 두 개의 TLB 누락을 해결하기 위해 2 회의 페이지 워킹을 병렬 처리 할 수도 있습니다. 그 두 사실은 연결될 수 있습니다. –

+0

감사합니다. 또한 교차 페이지 액세스가 그렇게 높은 비용을 가질 수 있다는 것을 깨닫지 못했습니다. 그래서 이것은 확실히 찾을 것이 있습니다. –

+1

BTW, Valgrind에는 --partial-loads-ok = yes 옵션이 있습니다.이 옵션은로드 된 데이터가 버퍼의 끝을 지나면 벡터로드로 인해 "유효하지 않은 읽기"문제를 숨길 수 있습니다. –

관련 문제