เมื่อเร็ว ๆ นี้ ข้อเสนอสำหรับเคอร์เนลลินุกซ์ได้รับการเผยแพร่โดยเสนอให้รวมชุดของแพตช์ที่มี a การใช้งานฟังก์ชัน memchr() ที่เหมาะสมที่สุด ใช้เพื่อค้นหาอักขระในอาร์เรย์
ฟังก์ชัน memchr() จะสแกนนำหน้า n ไบต์ของพื้นที่หน่วยความจำที่ชี้ไปที่ s สำหรับอินสแตนซ์แรกของ c ทั้ง c และไบต์ในพื้นที่หน่วยความจำที่ชี้โดย s จะถูกตีความว่าเป็นอักขระที่ไม่ได้ลงนาม
ข้อเสนอ สัญญาว่า เร็วขึ้น เพื่อค้นหาตัวละครภายในบล็อกแห่งความทรงจำ ในการทดสอบของนักพัฒนาซอฟต์แวร์ การปรับใช้ใหม่สามารถทำได้เร็วขึ้นเกือบสี่เท่าในการค้นหาจำนวนมาก
ต่างจากรุ่นก่อนซึ่งใช้การเปรียบเทียบแบบไบต์ต่อไบต์การดำเนินการที่เสนอจะถูกสร้างขึ้นโดยพิจารณาจากการใช้รีจิสเตอร์ CPU 64 บิตและ 32 บิตอย่างเต็มรูปแบบ แทนที่จะใช้ไบต์ การเปรียบเทียบทำได้โดยใช้คำเครื่อง ซึ่งช่วยให้เปรียบเทียบได้อย่างน้อย 4 ไบต์ในแต่ละครั้ง
ชุดของแพตช์นี้ปรับให้เหมาะสม "memcr()" และเพิ่มมาโครสำหรับ
"memchr_inv()" เพื่อให้ทั้งสองฟังก์ชันใช้สร้างบิตมาสก์ได้การใช้งานดั้งเดิมของ "memcr()" ขึ้นอยู่กับการเปรียบเทียบไบต์
ซึ่งไม่ได้ใช้รีจิสเตอร์ 64 หรือ 32 บิตใน CPU อย่างเต็มที่ เราใช้ a
เปรียบเทียบโดยคำเพื่อให้สามารถเปรียบเทียบได้อย่างน้อย 4 ไบต์
สภาพอากาศ. memchr() ที่ปรับให้เหมาะสมนั้นเร็วกว่าต้นฉบับเกือบ 4 เท่า
สำหรับโซ่ยาว ใน Linux Kernel เราพบว่าความยาวของสตริง
ค้นหาโดย "memchr()" สูงสุด 512 ไบต์ใน drivers/misc/lkdtm/heap.c
เมื่อค้นหาสตริงขนาดใหญ่ เวอร์ชั่นใหม่กลับเร็วกว่ารุ่นเก่าประมาณ 4 เท่า (เช่น สำหรับสตริงที่มีอักขระ 1000 ตัว) สำหรับเครือข่ายขนาดเล็ก ประสิทธิภาพของการใช้งานใหม่นั้นไม่สำคัญเท่า แต่ก็ยังสูงกว่ารุ่นเดิม
สิ่งที่น่าสนใจเกี่ยวกับข้อเสนอใหม่นี้คือการปรับปรุงห่วงโซ่ขนาดใหญ่ ซึ่งปรับปรุงเวลาได้อย่างมาก เป็นมูลค่าการกล่าวขวัญว่าในเคอร์เนลลินุกซ์ ขนาดของสตริงที่ประมวลผลใน memchr() ถึง 512 ไบต์ ในการทดสอบของเรา ประสิทธิภาพจะเพิ่มขึ้นสำหรับสตริง 512 ไบต์ ในสถานการณ์ที่อักขระค้นหา อยู่ที่ส่วนท้ายของสตริง คือ 20%
เป็นมูลค่าการกล่าวขวัญว่าเวอร์ชันดั้งเดิมของ memchr() ถูกนำไปใช้กับเทคนิคการเปรียบเทียบแบบไบต์ ซึ่งไม่ได้ใช้รีจิสเตอร์บนซีพียู 64 บิตหรือ 32 บิตอย่างเต็มที่
เราใช้การเปรียบเทียบทั้งคำเพื่อให้สามารถเปรียบเทียบอักขระได้ 8 ตัวพร้อมกันบน CPU รหัสนี้อิงตามการใช้งานของ David Light
เราสร้างไฟล์สองไฟล์เพื่อวัดประสิทธิภาพของไฟล์แรก ซึ่งประกอบด้วยอักขระที่อยู่ข้างหน้าอักขระปลายทางโดยเฉลี่ย 10 ตัว ไฟล์ที่สองมีอย่างน้อย 1000 อักขระก่อน ตัวละครเป้าหมาย
การใช้งาน "memcr()" ของเรานั้นเล็กน้อย ดีกว่าในการทดสอบครั้งแรกและเร็วกว่าต้นฉบับเกือบ 4 เท่า การดำเนินการในการทดสอบครั้งที่สอง
การทดสอบเคอร์เนล 5.18 ด้วยตัวแปร "memchr()" ใหม่สำหรับสถาปัตยกรรม 32 บิตและ 64 บิต ไม่ได้เปิดเผยปัญหาใดๆ
จะเกิดอะไรขึ้นถ้า p ไม่ใช่ 8 (หรือ 4 บนเป้าหมาย 32 บิต) จัดตำแหน่งไบต์? เป้าหมายทั้งหมดไม่สนับสนุนการโหลดที่ไม่สอดคล้อง (มีประสิทธิภาพ) ใช่ไหม
ฉันคิดว่ามันใช้งานได้ถ้า p ไม่เรียงกันเป็น 8 หรือ 4 ไบต์ สมมติว่าสตริงมีขนาด 10 ไบต์ for loop ที่นี่จะมองหา 8 ไบต์แรก หากอักขระปลายทางอยู่ใน 2 ไบต์สุดท้าย ตัวที่สองสำหรับลูปจะพบ มันยังทำงานในลักษณะนี้บนเครื่อง 32 บิต
ยังไม่ได้รับการประเมินประสิทธิภาพโดยรวม ของระบบย่อยเคอร์เนลเมื่อใช้ตัวแปร "memchr()" ที่ปรับให้เหมาะสม และไม่มีการพูดคุยกันว่าจะแทนที่การใช้งานหรือไม่ (การเรียกใช้ฟังก์ชัน memchr() เกิดขึ้น 129 ครั้งในโค้ดเคอร์เนล รวมถึงไดรเวอร์และระบบไฟล์)
ในที่สุด หากคุณสนใจที่จะทราบข้อมูลเพิ่มเติม คุณสามารถตรวจสอบรายละเอียด ในลิงค์ต่อไปนี้.