Chúng tôi đã thử nghiệm máy chủ sử dụng 2 CPU Xeon Gold 6154 với bo mạch chủ Supermicro X11DPH-I và RAM 96GB và phát hiện một số vấn đề hiệu năng rất lạ xung quanh bộ nhớ khi so sánh với việc chỉ chạy 1 CPU (một ổ cắm trống), tương tự kép CPU Haswell Xeon E5-2687Wv3 (đối với loạt thử nghiệm này, nhưng các Broadwell khác hoạt động tương tự), Broadwell-E i7s và Skylake-X i9s (để so sánh).
Người ta hy vọng rằng bộ xử lý Skylake Xeon có bộ nhớ nhanh hơn sẽ hoạt động nhanh hơn Haswell khi có các chức năng memcpy khác nhau và thậm chí cấp phát bộ nhớ (không được đề cập trong các thử nghiệm bên dưới, như chúng tôi đã tìm thấy cách khắc phục), nhưng thay vào đó là cả hai CPU được cài đặt , Skylake Xeons hoạt động với tốc độ gần bằng một nửa so với Haswell Xeons, và thậm chí còn ít hơn khi so sánh với i7-6800k. Điều kỳ lạ hơn nữa là khi sử dụng Windows VirtualAllocExNuma để gán nút NUMA để cấp phát bộ nhớ, trong khi các chức năng sao chép bộ nhớ đơn giản sẽ hoạt động kém hơn trên nút từ xa so với nút cục bộ, các chức năng sao chép bộ nhớ sử dụng các thanh ghi SSE, MMX và AVX thực hiện nhiều nhanh hơn trên nút NUMA từ xa so với nút cục bộ (cái gì?). Như đã nói ở trên, với Skylake Xeons,
Tôi không chắc đây có phải là lỗi trên bo mạch chủ hoặc CPU không, hoặc với UPI vs QPI, hoặc không có lỗi nào ở trên, nhưng dường như không có sự kết hợp nào giữa các cài đặt BIOS. Việc vô hiệu hóa NUMA (không bao gồm trong kết quả kiểm tra) trong bios sẽ cải thiện hiệu suất của tất cả các chức năng sao chép bằng các thanh ghi SSE, MMX và AVX, nhưng tất cả các chức năng sao chép bộ nhớ đơn giản khác cũng chịu tổn thất lớn.
Đối với chương trình thử nghiệm của chúng tôi, chúng tôi đã thử nghiệm cả sử dụng các hàm lắp ráp nội tuyến và _mm
nội tại, chúng tôi đã sử dụng Windows 10 với Visual Studio 2017 cho tất cả mọi thứ trừ các hàm lắp ráp, như msvc ++ sẽ không biên dịch asm cho x64, chúng tôi đã sử dụng gcc từ mingw / msys để biên dịch một tệp obj bằng -c -O2
cờ, mà chúng tôi đã đưa vào trình liên kết msvc ++.
Nếu hệ thống đang sử dụng các nút NUMA, chúng tôi sẽ kiểm tra cả hai toán tử mới để phân bổ bộ nhớ với VirtualAllocExNuma cho mỗi nút NUMA và thực hiện trung bình tích lũy 100 bản sao bộ nhớ đệm cho mỗi chức năng sao chép bộ nhớ và chúng tôi xoay vòng phân bổ bộ nhớ mà chúng tôi đang sử dụng giữa mỗi bộ kiểm tra.
Tất cả 100 bộ đệm nguồn và 100 đích được căn chỉnh 64 byte (để tương thích với AVX512 bằng cách sử dụng các chức năng phát trực tuyến) và được khởi tạo một lần để tăng dữ liệu cho bộ đệm nguồn và 0xff cho bộ đệm đích.
Số lượng bản sao được tính trung bình trên mỗi máy với mỗi cấu hình khác nhau, vì nó nhanh hơn nhiều trên một số và chậm hơn nhiều trên các máy khác.
Kết quả như sau:
Haswell Xeon E5-2687Wv3 1 CPU (1 ổ cắm trống) trên Supermicro X10DAi với 32GB DDR4-2400 (10c / 20t, bộ nhớ cache L3 25 MB). Nhưng hãy nhớ rằng, điểm chuẩn xoay qua 100 cặp bộ đệm 16 MB, vì vậy chúng tôi có thể không nhận được các lần truy cập bộ đệm 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
Haswell Dual Xeon E5-2687Wv3 2 cpu trên Supermicro X10DAi với ram 64GB
---------------------------------------------------------------------------
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
Skylake Xeon Gold 6154 1 CPU (1 ổ cắm trống) trên Supermicro X11DPH-I với 48GB DDR4-2666 (18c / 36t, bộ nhớ cache L3 24,75 MB)
---------------------------------------------------------------------------
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
CPU Skylake Xeon Gold 6154 2 trên Supermicro X11DPH-I với 96GB DDR4-2666
---------------------------------------------------------------------------
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
Skylake-X i9-7940X trên ASUS ROG Rampage VI Extreme với 32GB DDR4-4266 (14c / 28t, bộ nhớ cache L3 19,25 MB) (được ép xung lên 3,8 GHz / 4,4 GHz turbo, DDR ở tốc độ 4040 MHz, Target AVX 3737 MHz, Target AVX 512 Tần số 3535 MHz, tần số bộ đệm đích 2424 MHz)
---------------------------------------------------------------------------
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
Broadwell i7-6800k trên ASUS X99 với 24 GB DDR4-2400 (6c / 12t, bộ nhớ cache L3 15 MB)
---------------------------------------------------------------------------
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
Các hàm lắp ráp được lấy từ fast_memcpy trong xine-libs, chủ yếu được sử dụng chỉ để so sánh với trình tối ưu hóa của msvc ++.
Mã nguồn cho bài kiểm tra có sẵn tại https://github.com/marcmicalizzi/memcpy_test (hơi lâu để đăng bài)
Có ai khác gặp phải vấn đề này hay có ai có cái nhìn sâu sắc về lý do tại sao điều này có thể xảy ra không?
Cập nhật 2018-05-15 13: 40EST
Vì vậy, theo đề xuất của Peter Cordes, tôi đã cập nhật thử nghiệm để so sánh tìm nạp trước với không tìm nạp trước và các cửa hàng NT so với các cửa hàng thông thường và điều chỉnh việc tìm nạp trước được thực hiện trong mỗi chức năng ( vì vậy tôi không có kinh nghiệm nào có ý nghĩa với việc viết tìm nạp trước, vì vậy nếu Tôi đang phạm phải bất kỳ sai lầm nào với điều này, xin vui lòng cho tôi biết và tôi sẽ điều chỉnh các bài kiểm tra cho phù hợp. Việc tìm nạp trước có ảnh hưởng, vì vậy ít nhất nó đang làm gì đó ). Những thay đổi này được phản ánh trong bản sửa đổi mới nhất từ liên kết GitHub mà tôi đã thực hiện trước đó cho bất kỳ ai đang tìm kiếm mã nguồn.
Tôi cũng đã thêm một memcpy SSE4.1, vì trước SSE4.1 tôi không thể tìm thấy bất kỳ chức năng SSE nào _mm_stream_load
(tôi đặc biệt sử dụng _mm_stream_load_si128
), vì vậy sse_memcpy
và sse2_memcpy
không thể sử dụng hoàn toàn các cửa hàng NT và avx_memcpy
chức năng này cũng sử dụng các chức năng AVX2 để tải luồng.
Tôi đã chọn không thực hiện thử nghiệm cho các cửa hàng thuần túy và các mẫu truy cập tải thuần túy, vì tôi không chắc liệu cửa hàng thuần túy có thể có ý nghĩa hay không, vì nếu không tải vào các thanh ghi mà nó truy cập, dữ liệu sẽ vô nghĩa và không thể kiểm chứng được.
Kết quả thú vị với thử nghiệm mới là trên thiết lập Ổ cắm kép Xeon Skylake và chỉ trên thiết lập đó, các chức năng lưu trữ thực sự nhanh hơn đáng kể so với các chức năng phát trực tuyến NT để sao chép bộ nhớ 16 MB. Cũng chỉ vào thiết lập đó là tốt (và chỉ với LLC prefetch kích hoạt trong BIOS), prefetchnta trong một số xét nghiệm (SSE, SSE4.1) vượt xa cả prefetcht0 và không prefetch.
Kết quả thô của bài kiểm tra mới này quá dài để thêm vào bài đăng, vì vậy chúng được đăng trên cùng một kho git như mã nguồn bên dưới results-2018-05-15
Tôi vẫn không hiểu tại sao để phát trực tuyến các cửa hàng NT, nút NUMA từ xa nhanh hơn trong cài đặt Skylake SMP, mặc dù việc sử dụng các cửa hàng thông thường vẫn nhanh hơn so với nút NUMA cục bộ
prefetchnta
và các cửa hàng NT! Đó là một sự thật quan trọng mà bạn đã bỏ qua câu hỏi của mình! Xem REP MOVSB nâng cao cho memcpy để biết thêm thảo luận về ERMSB rep movsb
so với các cửa hàng vector NT so với các cửa hàng vector thông thường. Loay hoay với điều đó sẽ hữu ích hơn MMX so với SSE. Có lẽ chỉ cần sử dụng AVX và / hoặc AVX512 và thử NT so với thông thường và / hoặc bỏ qua phần tìm nạp trước SW.
prefetchnta
bỏ qua L3 cũng như L2 (vì L3 không bao gồm), do đó, nó nhạy cảm hơn với khoảng cách tìm nạp trước (quá muộn và dữ liệu phải quay trở lại từ DRAM, không chỉ L3), vì vậy nó "dễ vỡ" hơn ( nhạy cảm để điều chỉnh khoảng cách phù hợp). Tuy nhiên, khoảng cách tìm nạp trước của bạn trông khá thấp, dưới 500 byte nếu tôi đọc chính xác mã asm. Thử nghiệm của SKX về SKX đã phát hiện ra rằng đó prefetchnta
có thể là một sự chậm chạp lớn đối với vị tướng đó ) và anh ta không khuyến nghị điều đó.