1 คะแนน โดย GN⁺ 2024-08-27 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

vmsplice เร็ว_เกินไป_

  • บางโปรแกรมใช้ system call ชื่อ vmsplice เพื่อย้ายข้อมูลผ่าน pipe ให้เร็วขึ้น
  • พบว่าเมื่อไม่ใช้ vmsplice แล้ว Linux pipe ช้ากว่าที่คาดไว้
  • กำลังเขียนโปรแกรมสำหรับเข้ารหัส/ถอดรหัส Morse code อย่างรวดเร็ว และใช้ pipe สำหรับงานนี้

การเขียนข้อมูลในสภาพแวดล้อมอุดมคติ

  • โปรแกรมด้านล่างคัดลอกข้อมูลโดยไม่ต้องมี system call
  • ทำงานได้ที่ความเร็ว 167 GB/s โดยใช้ AVX-512
  • เมื่อปิดใช้งาน AVX-512 และทดสอบด้วย AVX2 และ SSE2 ก็ยังได้ความเร็วเท่าเดิมที่ 167 GB/s
  • ตราบใดที่มีการใช้ vectorization ก็สามารถทำความเร็ว 167 GB/s ได้

การเขียนข้อมูลลง pipe จริง

  • เขียนโปรแกรมที่ส่งข้อมูลลง pipe และวัดผล ได้ความเร็ว 17 GB/s
  • ช้ากว่าการเขียนลงบัฟเฟอร์ถึง 10 เท่า
  • ผลการทำ profiling พบว่าเวลาส่วนใหญ่ถูกใช้ไปกับการเรียก write
  • ใช้เวลาอย่างมากในการจัดสรร memory page ในฟังก์ชัน pipe_write
  • ตัวการคัดลอกข้อมูลเองใช้เวลา CPU เพียง 20% แต่ก็ยังช้ากว่า __memset_avx512_unaligned_erms อยู่สองเท่า

ความช่วยเหลือจาก vmsplice

  • vmsplice ย้ายบัฟเฟอร์จาก user space ไปยัง kernel โดยไม่คัดลอกข้อมูล
  • เมื่อใช้ vmsplice สามารถทำความเร็วได้ 210 GB/s
  • vmsplice ช่วยเลี่ยงส่วนที่มีต้นทุนสูงของ system call write

สรุปท้ายบท

  • การเขียนลง pipe ช้ากว่าการเขียนลงหน่วยความจำดิบอยู่ 10 เท่า
  • สาเหตุคือค่าใช้จ่ายในการล็อกบัฟเฟอร์และค่าใช้จ่ายในการบันทึกและกู้คืน SIMD context
  • splice และ vmsplice ช่วยหลีกเลี่ยงค่าใช้จ่ายเหล่านี้และย้ายข้อมูลได้อย่างมีประสิทธิภาพ

สรุปโดย GN⁺

  • บทความนี้อธิบายวิธีรีดประสิทธิภาพสูงสุดของ Linux pipe ด้วย vmsplice
  • vmsplice ย้ายข้อมูลได้โดยตรงโดยไม่ต้องคัดลอกเข้า kernel space จึงช่วยเพิ่มประสิทธิภาพอย่างมาก
  • มีประโยชน์สำหรับโปรแกรมประมวลผลข้อมูลความเร็วสูง เช่น การเข้ารหัส/ถอดรหัส Morse code
  • โครงการอื่นที่มีความสามารถคล้ายกัน ได้แก่ splice และ sendfile

1 ความคิดเห็น

 
GN⁺ 2024-08-27
ความเห็นจาก Hacker News
  • เหตุผลที่ JMP ไม่ถูกแทนที่ด้วย RET เป็นเพราะตัวเลือก CONFIG_RETHUNK

    • สามารถดูผลลัพธ์ที่ RET ถูกแทนที่ด้วย JMP __x86_return_thunk ได้จากดิสแอสเซมบลีของ objdump
    • ลิงก์ที่เกี่ยวข้อง: ลิงก์1, ลิงก์2
  • คำสั่ง NOP ที่ต้นและท้ายของฟังก์ชันมีไว้เพื่อให้ ftrace สามารถแทรกคำสั่งสำหรับการติดตามได้

    • มาจากแมโคร ASM_CLAC และ ASM_STAC
    • หากตรวจพบ X86_FEATURE_SMAP ก็จะถูกเติมเป็นคำสั่ง CLAC และ STAC ตอนรันไทม์
    • ลิงก์ที่เกี่ยวข้อง: ลิงก์3, ลิงก์4, ลิงก์5
  • โปรเจกต์ข้างเคียงของผู้ใช้รายหนึ่งเสนอ system call ที่ให้ ring buffer สำหรับ file descriptor

    • หากทั้งสองฝั่งของ pipe รองรับ ring buffer ก็จะสามารถแมป ring buffer เดียวกันได้ ทำให้ทำ zero-copy IO ได้โดยไม่ต้องเรียกเคอร์เนล
    • กำลังมองหาผู้ร่วมพัฒนา
    • ลิงก์ที่เกี่ยวข้อง: ลิงก์6
  • การเรียก Linux pipe ว่า "ช้า" ก็เหมือนการเรียก Toyota Corolla ว่า "ช้า"

    • สำหรับกรณีส่วนใหญ่ มันเร็วพออยู่แล้ว
    • ถ้าไม่ใช่กรณีสุดขั้ว ก็ไม่จำเป็นต้องมองหาสิ่งที่เร็วกว่านี้
  • บน CPU สมัยใหม่ rep movsb เร็วพอๆ กับเวอร์ชันที่ทำเวกเตอร์ไรซ์แล้วซึ่งเร็วที่สุด

    • ชื่อฟังก์ชันในเคอร์เนล "copy_user_enhanced_fast_string" ก็สื่อถึงเรื่องนี้
    • ฟีเจอร์ของ CPU อย่าง ERMS และ FSRM ทำให้สิ่งนี้เป็นไปได้
  • AVX512 ใช้พลังงานสูงและทำให้เกิดการสเกลความถี่ของ CPU

  • กำลังเจอกับ "hug of death" จาก Hacker News อีกครั้ง

    • สถานการณ์ดีขึ้นเพราะมีหน้า WordPress ที่แคชไว้ แต่ก็ยังใช้เวลาหลายวินาที
  • น่าสนใจหากได้เห็นเวอร์ชันที่ใช้ io_uring

    • สามารถหลีกเลี่ยงการคัดลอกและลดโอเวอร์เฮดของ system call ได้ โดยใช้เคอร์เนลและบัฟเฟอร์ที่แชร์กันล่วงหน้า
  • การบอกว่าการโหลดบล็อกใช้เวลาประมาณ 20 วินาทีเป็นคำกล่าวที่กล้ามาก

  • IPC แทบทุกรูปแบบนั้น "ช้า"

    • นี่คือการตัดสินใจยอมจ่ายต้นทุนด้านประสิทธิภาพเพื่อความปลอดภัย
  • เดิมทีไม่เข้าใจว่าทำไม splice ถึงช้านัก

    • มีการชี้เหตุผลว่าทำไมมันช้ากว่า vmsplice แต่ก็ยังไม่ชัดเจนว่าทำไม
    • น่าจะมีเหตุผลบางอย่างที่ทำให้ไม่สามารถนำไปเขียนใหม่ด้วย vmsplice ได้