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

การเพิ่มประสิทธิภาพของ 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 ความคิดเห็น

 
GN⁺ 2024-12-06
ความเห็นบน Hacker News
  • ตัวอย่างลูปทำซ้ำ 1 พันล้านครั้งและใช้ลูปซ้อนกัน คาดว่าเบนช์มาร์กนี้จะใช้เวลาเกิน 99% ไปกับสองบรรทัดแรก

    • ด้วยการวิเคราะห์ความมีชีวิตขององค์ประกอบในอาร์เรย์ ก็สามารถตัดลูปชั้นนอกทั้งหมดออกได้ และแปลงโปรแกรมให้ง่ายขึ้นได้
    • สงสัยว่าคอมไพเลอร์จะทำการวิเคราะห์แบบนี้ได้หรือไม่
    • แม้ว่า u จะไม่เป็นที่รู้แน่ชัดในช่วงคอมไพล์ แต่ลูปชั้นในก็สามารถแทนที่ด้วยคำสั่งไม่กี่คำสั่งได้
  • มีการพูดถึง Ruby เวอร์ชันถัด ๆ ไป โดย Ruby 3.4.0 มีกำหนดออกช่วงคริสต์มาสนี้ และ Ruby 3.5.0 ในคริสต์มาสปีหน้า

    • สงสัยว่า JIT ขั้นต่ำของ Python จะส่งผลกับลูปแบบนี้อย่างไร
    • Python 3.13 ต้องถูกบิลด์โดยเปิดใช้งาน JIT และน่าจะน่าสนใจหากลองรันเบนช์มาร์กด้วยมัน
  • ยังมีความรักให้กับ Ruby อยู่เสมอ ขอบคุณ Matz

  • มี PR ปรับปรุงประสิทธิภาพของ Integer#succ เมื่อต้นปี 2024 ซึ่งทำให้เข้าใจว่าทำไมถึงใช้ Integer#succ

    • Integer#succ ถูกใช้ตอนเขียนเมธอดลูปใหม่ โดยในอินเทอร์พรีเตอร์ opt_succ (i = i.succ) ถูกประมวลผลได้เร็วกว่า putobject 1; opt_plus (i += 1)
    • ส่วนตัวใช้ #succ บ่อยเพราะอ่านง่าย และใช้มันสองครั้งในเมธอด #bytes ของไลบรารี UUID เพื่อคง "โหมด bit slicing" ไว้ขณะอ่านโค้ด
  • มีการแชร์ประสบการณ์เกี่ยวกับ TruffleRuby โดย TruffleRuby เร็วกว่า Node.js และเข้าใกล้ Bun หรือ Golang

    • ไม่แน่ใจว่าเบนช์มาร์กที่ให้มานั้นแสดงความเร็วของ TruffleRuby หลังการเปลี่ยนแปลงแล้วหรือไม่
    • อยากตรวจสอบเบนช์มาร์กและเพิ่มเป็นคอมมิตในรีโพซิทอรีหลัก
  • Ruby เร็วขึ้นมาก และ TruffleRuby ก็น่าประทับใจยิ่งกว่า

  • ไม่เคยรู้มาก่อนว่า YJIT เขียนด้วย Rust

  • Python เป็นภาษาที่ช้าที่สุดในเบนช์มาร์ก แต่ ณ เดือนตุลาคม 2024 ก็ยังเป็นภาษาที่ถูกใช้งานมากที่สุดบน Github

    • ดูเหมือนว่าความช้าของภาษาและความนิยมจะมีความสัมพันธ์กัน
  • มีรีโพซิทอรีเปรียบเทียบภาษารุ่นเก่าที่รวมภาษาไว้มากกว่านี้

  • ทำให้โซลูชัน Advent of Code เปลี่ยนไปมาก และดูคล้ายกันอย่างน่าประหลาด