เราได้ทดสอบเซิร์ฟเวอร์โดยใช้ซีพียู 2x Xeon Gold 6154 กับมาเธอร์บอร์ด Supermicro X11DPH-I และ RAM 96GB และพบปัญหาด้านประสิทธิภาพรอบ ๆ หน่วยความจำที่แปลกประหลาดมากเมื่อเปรียบเทียบกับการทำงานกับซีพียูเพียง 1 ตัว (ซ็อกเก็ตเดียว) CPU Haswell Xeon E5-2687Wv3 (สำหรับชุดการทดสอบนี้ แต่ Broadwells อื่น ๆ ทำงานในลักษณะเดียวกัน), Broadwell-E i7s และ Skylake-X i9s (สำหรับการเปรียบเทียบ)
คาดว่าโปรเซสเซอร์ Skylake Xeon ที่มีหน่วยความจำเร็วกว่าจะทำงานได้เร็วกว่า Haswell เมื่อพูดถึงฟังก์ชั่น memcpy และการจัดสรรหน่วยความจำ (ไม่ครอบคลุมในการทดสอบด้านล่างเนื่องจากเราพบวิธีแก้ปัญหา) แต่แทนที่จะติดตั้งทั้ง CPU Skylake Xeons ทำงานได้เกือบครึ่งหนึ่งของความเร็วขณะที่ Haswell Xeons และแม้แต่น้อยกว่าเมื่อเทียบกับ i7-6800k สิ่งที่แม้แต่คนแปลกหน้าคือเมื่อใช้ Windows VirtualAllocExNuma เพื่อกำหนดโหนด NUMA สำหรับการจัดสรรหน่วยความจำในขณะที่ฟังก์ชั่นการคัดลอกหน่วยความจำธรรมดาคาดว่าจะทำงานได้แย่ลงบนโหนดระยะไกลเทียบกับโหนดโลคัล เร็วขึ้นในโหนด NUMA ระยะไกลกว่าในโหนดท้องถิ่น (อะไร?) ดังที่กล่าวไว้ข้างต้นกับ Skylake Xeons
ฉันไม่แน่ใจว่านี่เป็นข้อผิดพลาดบนมาเธอร์บอร์ดหรือซีพียูหรือด้วย UPI กับ QPI หรือไม่ได้กล่าวถึงข้างต้น แต่ไม่มีการรวมกันของการตั้งค่าไบออส การปิดใช้งาน NUMA (ไม่รวมอยู่ในผลการทดสอบ) ในไบออสนั้นช่วยปรับปรุงประสิทธิภาพของฟังก์ชั่นการทำสำเนาทั้งหมดโดยใช้การลงทะเบียน SSE, MMX และ AVX แต่ฟังก์ชั่นการคัดลอกหน่วยความจำธรรมดาอื่น ๆ ทั้งหมดก็ประสบปัญหาเช่นกัน
สำหรับโปรแกรมทดสอบของเราเราทดสอบทั้งโดยใช้ฟังก์ชั่นการประกอบแบบอินไลน์และ_mm
ภายในเราใช้ Windows 10 กับ Visual Studio 2017 สำหรับทุกอย่างยกเว้นฟังก์ชั่นการชุมนุมซึ่งเป็น msvc ++ จะไม่รวบรวม asm สำหรับ x64 เราใช้ gcc จาก mingw / msys รวบรวมไฟล์ obj โดยใช้-c -O2
ค่าสถานะซึ่งเรารวมอยู่ในตัวเชื่อมโยง msvc ++
หากระบบใช้โหนด NUMA เราจะทดสอบทั้งตัวดำเนินการใหม่สำหรับการจัดสรรหน่วยความจำด้วย VirtualAllocExNuma สำหรับแต่ละโหนด NUMA และทำการคัดลอกบัฟเฟอร์หน่วยความจำเฉลี่ยเฉลี่ย 100 เมกะไบต์แต่ละหน่วยความจำ 16MB สำหรับแต่ละฟังก์ชั่นการคัดลอกหน่วยความจำ ระหว่างการทดสอบแต่ละชุด
100 ต้นทางและ 100 ปลายทางบัฟเฟอร์มีการจัดตำแหน่ง 64 ไบต์ (สำหรับความเข้ากันได้สูงถึง AVX512 โดยใช้ฟังก์ชั่นการสตรีม) และกำหนดค่าเริ่มต้นหนึ่งครั้งเพื่อเพิ่มข้อมูลสำหรับบัฟเฟอร์ต้นทางและ 0xff สำหรับบัฟเฟอร์ปลายทาง
จำนวนสำเนาที่ถูกเฉลี่ยในแต่ละเครื่องที่มีการกำหนดค่าแต่ละอย่างแตกต่างกันเพราะมันเร็วกว่าในบางส่วนและช้ากว่ามากสำหรับคนอื่น ๆ
ผลลัพธ์มีดังนี้:
Haswell Xeon E5-2687Wv3 1 CPU (1 ซ็อกเก็ตว่างเปล่า) บน Supermicro X10DAi พร้อม 32GB DDR4-2400 (10c / 20t, L3 แคช 25 MB) แต่โปรดจำไว้ว่าเบนช์มาร์กทำการหมุนผ่านบัฟเฟอร์ขนาด 16MB จำนวน 100 คู่ดังนั้นเราอาจจะไม่ได้รับแคช 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 บน Supermicro X10DAi พร้อม 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 อัน) บน Supermicro X11DPH-I พร้อม 48GB DDR4-2666 (18c / 36t, แคช 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
Skylake Xeon Gold 6154 2 CPU บน Supermicro X11DPH-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บน ASUS ROG Rampage VI Extreme พร้อม 32GB DDR4-4266 ( 14c / 28t, L3 cache 19.25 MB 19 MB) (โอเวอร์คล็อกที่เทอร์โบ 3.8GHz / 4.4GHz, DDR ที่ 4040MHz, เป้าหมาย 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
Broadwell i7-6800kบน ASUS X99 พร้อม 24GB DDR4-2400 (6c / 12t, แคช 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
ฟังก์ชันแอสเซมบลีมาจาก fast_memcpy ใน xine-libs ส่วนใหญ่ใช้เพื่อเปรียบเทียบกับเครื่องมือเพิ่มประสิทธิภาพของ msvc ++
ซอร์สโค้ดสำหรับการทดสอบมีให้ที่https://github.com/marcmicalizzi/memcpy_test (ใช้เวลานานพอสมควรในการโพสต์)
มีคนอื่นวิ่งเข้าไปในนี้หรือไม่มีใครเข้าใจว่าทำไมสิ่งนี้อาจเกิดขึ้น?
อัปเดต 2018-05-15 13: 40EST
ดังนั้นตามคำแนะนำของ Peter Cordes ฉันได้อัปเดตการทดสอบเพื่อเปรียบเทียบ prefetched vs not prefetched และ NT stores เปรียบเทียบกับร้านค้าทั่วไปและปรับการดึงข้อมูลล่วงหน้าที่ทำในแต่ละฟังก์ชัน ( ฉันไม่มีประสบการณ์ที่มีความหมายกับการเขียน prefetching ดังนั้นถ้า ฉันทำผิดพลาดกับเรื่องนี้โปรดแจ้งให้เราทราบและฉันจะปรับการทดสอบตามความเหมาะสม prefetching มีผลกระทบดังนั้นอย่างน้อยที่สุดมันก็ทำอะไรบางอย่าง ) การเปลี่ยนแปลงเหล่านี้สะท้อนให้เห็นในการแก้ไขล่าสุดจากลิงค์ GitHub ที่ฉันทำไว้ก่อนหน้านี้สำหรับทุกคนที่กำลังมองหาซอร์สโค้ด
ฉันยังเพิ่ม SSE4.1 memcpy ตั้งแต่ก่อน SSE4.1 ฉันไม่พบฟังก์ชัน SSE ใด ๆ_mm_stream_load
(ฉันใช้เฉพาะ_mm_stream_load_si128
) ดังนั้นsse_memcpy
และsse2_memcpy
ไม่สามารถใช้ร้านค้า NT ได้อย่างสมบูรณ์และavx_memcpy
ฟังก์ชั่นนี้ใช้ฟังก์ชัน AVX2 สำหรับการโหลดกระแส
ฉันเลือกที่จะไม่ทำการทดสอบร้านค้าแท้และรูปแบบการเข้าถึงของแท้เนื่องจากฉันไม่แน่ใจว่าร้านค้าแท้อาจมีความหมายได้หรือไม่หากไม่มีการลงทะเบียนเพื่อเข้าถึงร้านค้านั้นข้อมูลจะไร้ความหมายและไม่สามารถพิสูจน์ได้
ผลลัพธ์ที่น่าสนใจจากการทดสอบใหม่คือการติดตั้ง Xeon Skylake Dual Socket และเฉพาะการตั้งค่านั้นฟังก์ชั่นการจัดเก็บนั้นเร็วกว่าฟังก์ชั่นการสตรีม NT อย่างมีนัยสำคัญสำหรับการคัดลอกหน่วยความจำ 16MB เช่นเดียวเท่านั้นกับการตั้งค่าที่ดี (และเฉพาะกับ LLC prefetch เปิดใช้งานใน BIOS) prefetchnta ในบางการทดสอบ (SSE, SSE4.1) มีประสิทธิภาพดีกว่าทั้ง prefetcht0 และไม่มี prefetch
ผลลัพธ์ดิบของการทดสอบใหม่นี้ยาวเกินกว่าจะเพิ่มไปยังโพสต์ดังนั้นจึงโพสต์ในที่เก็บ git เดียวกับซอร์สโค้ดภายใต้ results-2018-05-15
ฉันยังไม่เข้าใจว่าทำไมการสตรีมร้านค้า NT โหนด NUMA ระยะไกลจึงเร็วขึ้นภายใต้การตั้งค่า Skylake SMP แม้ว่าการใช้ร้านค้าทั่วไปก็ยังเร็วกว่าโหนด NUMA ท้องถิ่น
prefetchnta
และร้านค้า NT! นั่นเป็นความจริงที่สำคัญอย่างยิ่งที่คุณทิ้งคำถามไว้! ดูREP MOVSB ขั้นสูงสำหรับ memcpyสำหรับการสนทนาเพิ่มเติมของ ERMSB rep movsb
กับร้านค้าเวกเตอร์ NT กับร้านค้าเวกเตอร์ทั่วไป ล้อเล่นกับสิ่งนั้นจะมีประโยชน์มากกว่า MMX กับ SSE อาจเป็นเพียงแค่ใช้ AVX และ / หรือ AVX512 แล้วลองใช้ NT กับแบบปกติและ / หรือออกจาก prefetch SW ล่วงหน้า
prefetchnta
ข้าม L3 และ L2 (เนื่องจาก L3 ไม่รวม) ดังนั้นจึงมีความไวต่อระยะการดึง prefetch (สายเกินไปและข้อมูลต้องมาจาก DRAM อีกครั้งไม่ใช่แค่ L3) ดังนั้นจึงเป็น "เปราะ" มากกว่า ( ความไวต่อการปรับระยะทางที่เหมาะสม) ระยะการดึงข้อมูลล่วงหน้าของคุณดูค่อนข้างต่ำ แต่อยู่ต่ำกว่า 500 ไบต์ถ้าฉันอ่าน asm อย่างถูกต้อง @ การทดสอบของ Mysticial ใน SKX พบว่าprefetchnta
อาจเป็นการชะลอตัวครั้งใหญ่ใน uarch นั้น ) และเขาไม่แนะนำ