Xeon Skylake SMP를 통한 예상치 못한 예기치 못한 느린 (이상한) 메모리 성능

우리는 Supermicro X11DPH-I 마더 보드 및 96GB RAM이 장착 된 2x Xeon Gold 6154 CPU를 사용하여 서버를 테스트했으며, 1 개의 CPU (하나의 소켓 비우기)만으로 실행하는 것과 비교했을 때 메모리와 관련하여 매우 이상한 성능 문제를 발견했습니다. CPU Haswell Xeon E5-2687Wv3 (이 일련의 테스트에서는 다른 Broadwell도 비슷하게 수행), Broadwell-E i7 및 Skylake-X i9 (비교 용).

더 빠른 메모리를 가진 Skylake Xeon 프로세서는 다양한 memcpy 기능과 심지어 메모리 할당 (해결 방법을 찾은 아래의 테스트에서는 다루지 않음)과 관련하여 Haswell보다 더 빠르게 수행되지만 두 CPU가 모두 설치되어있을 것으로 예상됩니다 Skylake Xeon은 Haswell Xeon보다 거의 절반 속도로 작동하며 i7-6800k와 비교할 때 훨씬 느립니다. 낯선 점은 Windows VirtualAllocExNuma를 사용하여 메모리 할당을 위해 NUMA 노드를 할당하는 경우이며, 일반 메모리 복사 기능은 원격 노드와 로컬 노드에 비해 성능이 저하 될 것으로 예상됩니다. 원격 NUMA 노드에서 로컬 노드보다 빠릅니다 (무엇입니까?). 위에서 언급했듯이 Skylake Xeons에서는

이것이 마더 보드 또는 CPU의 버그인지 또는 UPI 대 QPI의 버그인지 또는 위의 어느 것도 확실하지 않지만 BIOS 설정 조합이이 기능을 사용하지 못하는 것 같습니다. BIOS에서 NUMA (테스트 결과에 포함되지 않음)를 비활성화하면 SSE, MMX 및 AVX 레지스터를 사용하는 모든 복사 기능의 성능이 향상되지만 다른 모든 일반 메모리 복사 기능도 크게 손실됩니다.

테스트 프로그램의 경우 인라인 어셈블리 함수와 _mm내장 함수를 모두 테스트 했으며 어셈블리 함수를 제외한 모든 것에 Windows 10을 Visual Studio 2017과 함께 사용했습니다 .msvc ++는 x64의 asm을 컴파일하지 않으므로 mingw / msys에서 gcc를 사용했습니다. -c -O2msvc ++ 링커에 포함 된 플래그를 사용하여 obj 파일을 컴파일하십시오 .

시스템이 NUMA 노드를 사용하는 경우, 각 NUMA 노드에 대해 VirtualAllocExNuma를 사용하여 새로운 메모리 할당에 대해 두 연산자를 모두 테스트하고 각 메모리 복사 기능에 대해 각각 16MB의 누적 평균 100 개의 메모리 버퍼 사본을 수행하고 현재 사용중인 메모리 할당을 회전시킵니다. 각 테스트 세트 사이.

100 개의 소스 및 100 개의 대상 버퍼는 모두 64 바이트로 정렬되며 (스트리밍 기능을 사용하여 AVX512까지 호환 가능) 소스 버퍼의 증분 데이터로, 대상 버퍼의 경우 0xff로 한 번 초기화됩니다.

각 구성에 따라 각 시스템에서 평균화되는 사본 수는 일부에서 훨씬 더 빠르고 다른 시스템에서는 훨씬 느리기 때문에 다양합니다.

결과는 다음과 같습니다.

32GB DDR4-2400 (10c / 20t, 25MB의 L3 캐시)이있는 Supermicro X10DAi의 Haswell Xeon E5-2687Wv3 1 CPU (빈 소켓 1 개 ). 그러나 벤치 마크는 100MB의 16MB 버퍼를 통해 회전하므로 L3 캐시 적중을 얻지 못할 수 있습니다.

---------------------------------------------------------------------------
Averaging 7000 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy                      averaging 2264.48 microseconds
asm_memcpy (asm)                 averaging 2322.71 microseconds
sse_memcpy (intrinsic)           averaging 1569.67 microseconds
sse_memcpy (asm)                 averaging 1589.31 microseconds
sse2_memcpy (intrinsic)          averaging 1561.19 microseconds
sse2_memcpy (asm)                averaging 1664.18 microseconds
mmx_memcpy (asm)                 averaging 2497.73 microseconds
mmx2_memcpy (asm)                averaging 1626.68 microseconds
avx_memcpy (intrinsic)           averaging 1625.12 microseconds
avx_memcpy (asm)                 averaging 1592.58 microseconds
avx512_memcpy (intrinsic)        unsupported on this CPU
rep movsb (asm)                  averaging 2260.6 microseconds

64GB 램이있는 Supermicro X10DAi의 Haswell Dual Xeon E5-2687Wv3 2 CPU

---------------------------------------------------------------------------
Averaging 6900 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 0(local)
---------------------------------------------------------------------------
std::memcpy                      averaging 3179.8 microseconds
asm_memcpy (asm)                 averaging 3177.15 microseconds
sse_memcpy (intrinsic)           averaging 1633.87 microseconds
sse_memcpy (asm)                 averaging 1663.8 microseconds
sse2_memcpy (intrinsic)          averaging 1620.86 microseconds
sse2_memcpy (asm)                averaging 1727.36 microseconds
mmx_memcpy (asm)                 averaging 2623.07 microseconds
mmx2_memcpy (asm)                averaging 1691.1 microseconds
avx_memcpy (intrinsic)           averaging 1704.33 microseconds
avx_memcpy (asm)                 averaging 1692.69 microseconds
avx512_memcpy (intrinsic)        unsupported on this CPU
rep movsb (asm)                  averaging 3185.84 microseconds
---------------------------------------------------------------------------
Averaging 6900 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 1
---------------------------------------------------------------------------
std::memcpy                      averaging 3992.46 microseconds
asm_memcpy (asm)                 averaging 4039.11 microseconds
sse_memcpy (intrinsic)           averaging 3174.69 microseconds
sse_memcpy (asm)                 averaging 3129.18 microseconds
sse2_memcpy (intrinsic)          averaging 3161.9 microseconds
sse2_memcpy (asm)                averaging 3141.33 microseconds
mmx_memcpy (asm)                 averaging 4010.17 microseconds
mmx2_memcpy (asm)                averaging 3211.75 microseconds
avx_memcpy (intrinsic)           averaging 3003.14 microseconds
avx_memcpy (asm)                 averaging 2980.97 microseconds
avx512_memcpy (intrinsic)        unsupported on this CPU
rep movsb (asm)                  averaging 3987.91 microseconds
---------------------------------------------------------------------------
Averaging 6900 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy                      averaging 3172.95 microseconds
asm_memcpy (asm)                 averaging 3173.5 microseconds
sse_memcpy (intrinsic)           averaging 1623.84 microseconds
sse_memcpy (asm)                 averaging 1657.07 microseconds
sse2_memcpy (intrinsic)          averaging 1616.95 microseconds
sse2_memcpy (asm)                averaging 1739.05 microseconds
mmx_memcpy (asm)                 averaging 2623.71 microseconds
mmx2_memcpy (asm)                averaging 1699.33 microseconds
avx_memcpy (intrinsic)           averaging 1710.09 microseconds
avx_memcpy (asm)                 averaging 1688.34 microseconds
avx512_memcpy (intrinsic)        unsupported on this CPU
rep movsb (asm)                  averaging 3175.14 microseconds

48GB DDR4-2666 (18c / 36t, 24.75MB의 L3 캐시)이있는 Supermicro X11DPH-I의 Skylake Xeon Gold 6154 1 CPU (빈 소켓 1 개 )

---------------------------------------------------------------------------
Averaging 5000 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy                      averaging 1832.42 microseconds
asm_memcpy (asm)                 averaging 1837.62 microseconds
sse_memcpy (intrinsic)           averaging 1647.84 microseconds
sse_memcpy (asm)                 averaging 1710.53 microseconds
sse2_memcpy (intrinsic)          averaging 1645.54 microseconds
sse2_memcpy (asm)                averaging 1794.36 microseconds
mmx_memcpy (asm)                 averaging 2030.51 microseconds
mmx2_memcpy (asm)                averaging 1816.82 microseconds
avx_memcpy (intrinsic)           averaging 1686.49 microseconds
avx_memcpy (asm)                 averaging 1716.15 microseconds
avx512_memcpy (intrinsic)        averaging 1761.6 microseconds
rep movsb (asm)                  averaging 1977.6 microseconds

96GB DDR4-2666의 Supermicro X11DPH-I의 Skylake Xeon Gold 6154 2 CPU

---------------------------------------------------------------------------
Averaging 4100 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 0(local)
---------------------------------------------------------------------------
std::memcpy                      averaging 3131.6 microseconds
asm_memcpy (asm)                 averaging 3070.57 microseconds
sse_memcpy (intrinsic)           averaging 3297.72 microseconds
sse_memcpy (asm)                 averaging 3423.38 microseconds
sse2_memcpy (intrinsic)          averaging 3274.31 microseconds
sse2_memcpy (asm)                averaging 3413.48 microseconds
mmx_memcpy (asm)                 averaging 2069.53 microseconds
mmx2_memcpy (asm)                averaging 3694.91 microseconds
avx_memcpy (intrinsic)           averaging 3118.75 microseconds
avx_memcpy (asm)                 averaging 3224.36 microseconds
avx512_memcpy (intrinsic)        averaging 3156.56 microseconds
rep movsb (asm)                  averaging 3155.36 microseconds
---------------------------------------------------------------------------
Averaging 4100 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 1
---------------------------------------------------------------------------
std::memcpy                      averaging 5309.77 microseconds
asm_memcpy (asm)                 averaging 5330.78 microseconds
sse_memcpy (intrinsic)           averaging 2350.61 microseconds
sse_memcpy (asm)                 averaging 2402.57 microseconds
sse2_memcpy (intrinsic)          averaging 2338.61 microseconds
sse2_memcpy (asm)                averaging 2475.51 microseconds
mmx_memcpy (asm)                 averaging 2883.97 microseconds
mmx2_memcpy (asm)                averaging 2517.69 microseconds
avx_memcpy (intrinsic)           averaging 2356.07 microseconds
avx_memcpy (asm)                 averaging 2415.22 microseconds
avx512_memcpy (intrinsic)        averaging 2487.01 microseconds
rep movsb (asm)                  averaging 5372.98 microseconds
---------------------------------------------------------------------------
Averaging 4100 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy                      averaging 3075.1 microseconds
asm_memcpy (asm)                 averaging 3061.97 microseconds
sse_memcpy (intrinsic)           averaging 3281.17 microseconds
sse_memcpy (asm)                 averaging 3421.38 microseconds
sse2_memcpy (intrinsic)          averaging 3268.79 microseconds
sse2_memcpy (asm)                averaging 3435.76 microseconds
mmx_memcpy (asm)                 averaging 2061.27 microseconds
mmx2_memcpy (asm)                averaging 3694.48 microseconds
avx_memcpy (intrinsic)           averaging 3111.16 microseconds
avx_memcpy (asm)                 averaging 3227.45 microseconds
avx512_memcpy (intrinsic)        averaging 3148.65 microseconds
rep movsb (asm)                  averaging 2967.45 microseconds

스카이 레이크-X i9-7940X 32기가바이트 DDR4-4266와 ASUS ROG 램 페이지 VI 익스트림에 (14C / 28t, L3 캐시의 19.25 MB)을 (3.8GHz의 / 4.4GHz 터보, 4040MHz에서 DDR, 대상 AVX 주파수 3737MHz, 대상 AVX-에 오버 클럭 512 주파수 3535MHz, 대상 캐시 주파수 2424MHz)

---------------------------------------------------------------------------
Averaging 6500 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy                      averaging 1750.87 microseconds
asm_memcpy (asm)                 averaging 1748.22 microseconds
sse_memcpy (intrinsic)           averaging 1743.39 microseconds
sse_memcpy (asm)                 averaging 3120.18 microseconds
sse2_memcpy (intrinsic)          averaging 1743.37 microseconds
sse2_memcpy (asm)                averaging 2868.52 microseconds
mmx_memcpy (asm)                 averaging 2255.17 microseconds
mmx2_memcpy (asm)                averaging 3434.58 microseconds
avx_memcpy (intrinsic)           averaging 1698.49 microseconds
avx_memcpy (asm)                 averaging 2840.65 microseconds
avx512_memcpy (intrinsic)        averaging 1670.05 microseconds
rep movsb (asm)                  averaging 1718.77 microseconds

24GB DDR4-2400 (6c / 12t, 15MB의 L3 캐시)가 장착 된 ASUS X99의 Broadwell i7-6800k

---------------------------------------------------------------------------
Averaging 64900 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy                      averaging 2522.1 microseconds
asm_memcpy (asm)                 averaging 2615.92 microseconds
sse_memcpy (intrinsic)           averaging 1621.81 microseconds
sse_memcpy (asm)                 averaging 1669.39 microseconds
sse2_memcpy (intrinsic)          averaging 1617.04 microseconds
sse2_memcpy (asm)                averaging 1719.06 microseconds
mmx_memcpy (asm)                 averaging 3021.02 microseconds
mmx2_memcpy (asm)                averaging 1691.68 microseconds
avx_memcpy (intrinsic)           averaging 1654.41 microseconds
avx_memcpy (asm)                 averaging 1666.84 microseconds
avx512_memcpy (intrinsic)        unsupported on this CPU
rep movsb (asm)                  averaging 2520.13 microseconds

어셈블리 함수는 xine-libs의 fast_memcpy에서 파생되며 주로 msvc ++의 옵티 마이저와 비교하는 데 사용됩니다.

테스트를위한 소스 코드는 https://github.com/marcmicalizzi/memcpy_test 에서 확인할 수 있습니다 (게시하기에는 약간 길다)

다른 사람이 이것을 겪었거나 왜 이것이 일어날 수 있는지에 대한 통찰력이 있습니까?


업데이트 2018-05-15 13 : 40EST

Peter Cordes가 제안한 것처럼 프리 페치와 프리 페치, NT 스토어와 일반 스토어를 비교하기 위해 테스트를 업데이트했으며 각 기능에서 수행되는 프리 페치를 조정했습니다 (프리 페칭 을 작성하는 데 의미있는 경험은 없습니다. 나는 이것으로 실수를하고 있습니다. 알려주십시오. 그리고 테스트를 적절히 조정할 것입니다. 프리 페치는 영향을 미치므로 최소한 무언가를하고 있습니다 ). 이러한 변경 사항은 이전에 소스 코드를 찾는 사람을 위해 만든 GitHub 링크의 최신 개정판에 반영됩니다.

SSE4.1 내가 이전에 어떤 찾을 수 없기 때문에 나는 또한, SSE4.1의 방어 적이기를 추가했습니다 _mm_stream_load(I 특별히 사용 _mm_stream_load_si128하므로,) SSE 기능 sse_memcpysse2_memcpyNT 저장소를 사용하여 완전하게 될 수없고,뿐만 아니라 avx_memcpy기능 AVX2 함수를 사용 스트림 로딩 용.

순수한 저장소와 순수한로드 액세스 패턴에 대한 테스트를 수행하지 않기로 선택했습니다. 순수한 저장소가 액세스하는 레지스터에 대한로드가 없으면 데이터가 의미가없고 검증 할 수 없기 때문에 순수한 저장소가 의미가 있는지 확신 할 수 없기 때문입니다.

새로운 테스트의 흥미로운 결과는 Xeon Skylake Dual Socket 설정과 해당 설정 에서만 16MB 메모리 복사를위한 NT 스트리밍 기능보다 실제로 저장 기능이 훨씬 빠르다는 것입니다. 뿐만 아니라 단지 그 설정에 대한뿐만 아니라, 몇 가지 테스트에서 prefetchnta (SSE, SSE4.1) prefetcht0없이 프리 페치 모두를 능가하는 성능을 (만 LLC와 프리 페치는 BIOS에서 활성화).

이 새로운 테스트의 원시 결과는 게시물에 추가하기에 너무 길기 때문에 소스 코드와 동일한 git 저장소에 게시됩니다. results-2018-05-15

정규 저장소를 사용하는 것이 로컬 NUMA 노드보다 여전히 빠르지 만 NT 저장소를 스트리밍하는 이유는 Skylake SMP 설정에서 더 빠릅니다.



답변

메모리가 잘못된 순위입니까? 아마도 두 번째 CPU를 추가 할 때 보드에 메모리 순위와 이상한 점이 있습니까? 쿼드 CPU 시스템을 사용하면 메모리가 올바르게 작동하기 위해 모든 종류의 이상한 일을 수행하며 잘못된 순위의 메모리가있는 경우 때때로 작동하지만 속도의 1/4 또는 1/2과 같이 다시 클럭합니다. 아마도 SuperMicro는 DDR4 및 듀얼 CPU를 쿼드 채널로 만들기 위해 보드에서 무언가를 수행했으며 비슷한 수학을 사용하고 있습니다. 잘못된 순위 == 1/2 속도.