การเพิ่มประสิทธิภาพของ Ruby: เขียน C ใหม่เป็น Ruby
การเปรียบเทียบประสิทธิภาพของ Ruby
- ในรีพอร์ตเปรียบเทียบภาษาเมื่อไม่นานมานี้ Ruby เร็วกว่า R และ Python แต่ถูกจัดว่าเป็นภาษาที่ช้าที่สุดเป็นอันดับสาม
- เบนช์มาร์กประกอบด้วยสองรายการคือ "Loops" และ "Fibonacci" โดยเน้นค่าใช้จ่ายส่วนเกินของลูปและเงื่อนไข การเรียกฟังก์ชัน และประสิทธิภาพของการเรียกซ้ำ
การเปรียบเทียบประสิทธิภาพระหว่าง Ruby และ Node.js
- บน M3 MacBook Pro, Ruby 3.3.6 ใช้เวลา 28 วินาทีในตัวอย่างลูป และ 12 วินาทีในตัวอย่างฟีโบนักชี
- Node.js ใช้เวลาประมาณ 1 วินาทีในทั้งสองตัวอย่าง
- บน M2 MacBook Air ประสิทธิภาพของ Ruby แย่ลงอีก
ความหมายของเบนช์มาร์ก
- เบนช์มาร์กเหล่านี้อาจไม่มีความหมายมากนักในทางปฏิบัติ
- Python ถูกประเมินว่าเป็นภาษาที่ช้าที่สุด แต่เป็นภาษาที่ถูกใช้งานมากที่สุดบน GitHub
- ภาษาโปรแกรมควรมีประสิทธิภาพ แต่ความมีประโยชน์และผลิตภาพของภาษาสำคัญกว่าประสิทธิภาพ
การใช้ YJIT
- เมื่อนำ YJIT มาใช้ ประสิทธิภาพของฟีโบนักชีดีขึ้นอย่างมาก
- ในตัวอย่างลูป การปรับปรุงประสิทธิภาพมีเพียงเล็กน้อย
การปรับแต่งโค้ด Ruby
Range#each เขียนด้วย C จึงไม่สามารถให้ YJIT ปรับแต่งได้
Integer#times ถูกแปลงจาก C เป็น Ruby ใน Ruby 3.3 ทำให้ YJIT ปรับแต่งได้
Array#each ถูกแปลงจาก C เป็น Ruby ใน Ruby 3.4
การปรับแต่ง Integer#times
Integer#succ ทำงานได้เร็วกว่า i += 1
- YJIT ปรับแต่ง
Integer#times จนช่วยเพิ่มประสิทธิภาพได้อย่างมาก
การปรับแต่ง Array#each
Array#each ถูกแปลงจาก C เป็น Ruby ใน Ruby 3.4 ทำให้ YJIT ปรับแต่งได้
- ใช้โมดูล
Primitive เพื่อประเมินโค้ด C ภายใน Ruby
รีพอซิทอรี Ruby Microbench
- มีการรันเบนช์มาร์กด้วย Ruby หลายเวอร์ชันและ YJIT
- Ruby 3.4 YJIT มีประสิทธิภาพดีขึ้นอย่างมาก
การปรับแต่ง range#each
- สามารถเพิ่มประสิทธิภาพได้ด้วยการอิมพลีเมนต์คลาส
Range เป็น Ruby ล้วน
ไลบรารีมาตรฐานของ YJIT
- ทีม YJIT กำลังแทนที่โค้ด C ด้วย Ruby เพื่อเพิ่มประสิทธิภาพ
- ใช้บล็อก
with_yjit เพื่อใช้ implementation แบบ Ruby เมื่อ YJIT ถูกเปิดใช้งาน
การตรวจสอบการปรับแต่งของ YJIT
- YJIT แปลงไบต์โค้ดของ Ruby VM เป็นภาษาเครื่องเพื่อปรับแต่งประสิทธิภาพ
- วิเคราะห์โค้ดภาษาเครื่องของ
Integer#succ เพื่อทำความเข้าใจกระบวนการปรับแต่งของ YJIT
1 ความคิดเห็น
ความเห็นบน Hacker News
ตัวอย่างลูปทำซ้ำ 1 พันล้านครั้งและใช้ลูปซ้อนกัน คาดว่าเบนช์มาร์กนี้จะใช้เวลาเกิน 99% ไปกับสองบรรทัดแรก
uจะไม่เป็นที่รู้แน่ชัดในช่วงคอมไพล์ แต่ลูปชั้นในก็สามารถแทนที่ด้วยคำสั่งไม่กี่คำสั่งได้มีการพูดถึง Ruby เวอร์ชันถัด ๆ ไป โดย Ruby 3.4.0 มีกำหนดออกช่วงคริสต์มาสนี้ และ Ruby 3.5.0 ในคริสต์มาสปีหน้า
ยังมีความรักให้กับ Ruby อยู่เสมอ ขอบคุณ Matz
มี PR ปรับปรุงประสิทธิภาพของ
Integer#succเมื่อต้นปี 2024 ซึ่งทำให้เข้าใจว่าทำไมถึงใช้Integer#succInteger#succถูกใช้ตอนเขียนเมธอดลูปใหม่ โดยในอินเทอร์พรีเตอร์opt_succ (i = i.succ)ถูกประมวลผลได้เร็วกว่าputobject 1; opt_plus (i += 1)#succบ่อยเพราะอ่านง่าย และใช้มันสองครั้งในเมธอด#bytesของไลบรารี UUID เพื่อคง "โหมด bit slicing" ไว้ขณะอ่านโค้ดมีการแชร์ประสบการณ์เกี่ยวกับ TruffleRuby โดย TruffleRuby เร็วกว่า Node.js และเข้าใกล้ Bun หรือ Golang
Ruby เร็วขึ้นมาก และ TruffleRuby ก็น่าประทับใจยิ่งกว่า
ไม่เคยรู้มาก่อนว่า YJIT เขียนด้วย Rust
Python เป็นภาษาที่ช้าที่สุดในเบนช์มาร์ก แต่ ณ เดือนตุลาคม 2024 ก็ยังเป็นภาษาที่ถูกใช้งานมากที่สุดบน Github
มีรีโพซิทอรีเปรียบเทียบภาษารุ่นเก่าที่รวมภาษาไว้มากกว่านี้
ทำให้โซลูชัน Advent of Code เปลี่ยนไปมาก และดูคล้ายกันอย่างน่าประหลาด