Thursday, August 25, 2016

ทำไงให้ GHC เร็วขึ้น

งานที่ผมทำอยู่ (ยังไม่เสร็จ) code ของ app จริง ๆ ตอนนี้แค่ 3 พันกว่าบรรทัด แต่มีใช้ template haskell กับ quasiquotation หลายที่ + lens นิดหน่อย  compile ทั้ง project ล่อไป 1 นาที ถ้าไปแก้ module ที่ module อื่นมายุ่งแล้ว compile ใหม่ ก็รอไปครึ่งนาที ไม่รู้มันช้าเอง เครื่องห่วย หรือผมเขียนอะไร noob ๆ ทำให้ compiler มันงงก็ไม่รู้

แต่จะนั่งขุดรายละเอียด GHC หาทางเอาใจ compiler ก็คงไม่ไหว.. เลยลอง google แล้วก็เจอคนเขียนเรื่องนี้ไว้พอดี เค้าลองปรับ options ต่าง ๆ  ของ GHC แล้วเอามาเทียบกันให้เราดู ว่าทำอะไรแล้วมันเร็วขึ้นแค่ไหน https://rybczak.net/2016/03/26/how-to-reduce-compilation-times-of-haskell-projects/

สำหรับใครขี้เกียจอ่าน ขอคำตอบแบบ stackoverflow:
  • ปิด optimizer (-O0) นอกจากเรื่อง correctness แล้ว GHC ยังใช้เวลาไม่น้อยไป optimize code อย่างหนักหน่วง เพื่อให้ code เราให้ทำงานได้เร็ว แต่เวลาเรา develop เราไม่ได้ต้องการเร็วอะไรขนาดนั้น ขอแค่เช็คว่า type ถูกมั้ย test พอได้ก็พอ ดังนั้นก็ปิด optimizer มันซะ
  • เพิ่ม heap (+RTS -A128m -n2m -RTS) เพราะ GHC เสียเวลาไปกับ garbage collection (GC) ตอน compile เยอะมาก ประมาณ 25 วิ จาก 65 ถ้าเพิ่ม heap ให้เยอะ ๆ GC ก็จะวิ่งน้อยลง เป็นการแลก memory กับ time
  • parallel compilation (-j) ใส่แล้ว GHC จะหาเองว่า module ไหนไม่มี dependency ก็จะ compile พร้อม ๆ กันไปเลย

ผลคือเร็วขึ้น เยอะมาก จาก 65 วิ เหลือแค่ 23 วิ... สบายละ

ปล: ใครคิดว่าเขียน haskell แล้ววงจร code feedback มันจะช้า จะขาดตอน ใจเย็น ๆ อย่าตื่นตูม แค่ลง intero (http://commercialhaskell.github.io/intero/) ตอนนี้มีแต่เป็น emacs plugin คุณก็จะได้ editor ที่ขีดเส้นตัวแดง ๆ ตรงที่ code ผิด เราเอา cursor ไปแหย่ก็รู้ทันทีว่าต้องแก้เพราะอะไร โดยไม่ต้อง compile ใหม่แม้แต่ตัวเดียว โค้ดทั่วไปรอประมาณครึ่งวิ โค้ดหนืด ๆ อย่าง template haskell รอไม่เกิน 3 วิ  หรือจะลอง test บาง function ก็มี repl ให้ใช้ใน emacs  ที่ intero มันเร็วเพราะหลังบ้านมันใช้ GHCi ในการ interpret code เรา ก็เลยเร็วเหมือนภาษา dynamic แต่เป๊ะ เหมือนวิ่งผ่าน compiler