คลิกที่นี่

Download Report

Transcript คลิกที่นี่

Register Spilling
การล้ นจากรี จิสเตอร์
Spilling (การล้นจากรี จิสเตอร์)
• เกิดอะไรขึ ้นถ้ าทุกๆ node มี neighbor มากกว่า k
• ตัวอย่างเช่นถ้ าเราต้ องการทา 3-coloring ของ RIG ด้ านล่างนี ้
Spilling (การล้นจากรี จิสเตอร์)
• ถ้ าเราลบ node หนึง่ ออกไปตามขั ้นตอน heuristics เราจะไป
ต่อไปได้ ดงั แสดงด้ วยรูป RIG ใหม่ต้านล่าง
• ในกรณีนี ้เราจะทาการเลือก node ที่จะ spill
– ตัวแปรที่ถกู spill ไปจะไป “lives” ในหน่วยความจาหลักแทน
– ให้ วา่ เราเลือก f ที่จะต้ องถูก spill ไปที่หน่วยความจาหลัก
Spilling (การล้นจากรี จิสเตอร์)
• หลังจากที่เรา spill f แล้ ว เราสามารถกลับไปใช้ heuristic ได้
เหมือนเดิม (ดูจากภาพ RIG ด้ านล่าง)
Spilling (การล้นจากรี จิสเตอร์)
• ในท้ ายที่สดุ เราก็จะต้ องให้ คา่ สีกบั f โดยความคาดหวังของเราก็
คือจาก neighbor ทัง้ 4 ของ f นัน้ บางทีอาจจะมีสีที่ใช้ แตกต่าง
กัน น้ อยกว่า 3 สีก็เป็ นได้
Spilling
• ในกรณีนี ้ไม่เป็ นเช่นที่เราคาดหวัง
– เราจะต้ องทาการจองตาแหน่งในหน่วยความจาหลักให้ กบั f
• ส่วนใหญ่ใช้ พื ้นที่บน stack และจัดให้ อยูใ่ น AR
• เรี ยกตาแหน่งนี ้ว่า fa
• ในกรณีที่มีการใช้ f ให้ เพิ่มคาสัง่ load เพื่อนาข้ อมูลเข้ าเข้ ามาที่ f
f := load fa
• ในกรณีที่มีการ assign ค่าให้ f (การ write ไปที่ f) ให้ ใส่คาสัง่ store
ต่อไปนี ้
store f, fa
ตัวอย่าง Spilling
• โค๊ ดใหม่หลังจากการ spill ตัวแปร f
ค่า Liveness เดิม
คานวณ Liveness ใหม่
คานวณ Liveness ใหม่
• ข้ อมูล liveness ที่คานวณได้ ใหม่มีความใกล้ เคียงกับ liveness เดิม
มาก (สาหรับ CFG ที่ไม่มีการ spill)
• f จะ live ในช่วงต่อไปนี ้
– ระหว่าง f := load fa และคาสัง่ ที่อยูถ่ ดั ไป
– ระหว่าง f := load fa และคาสัง่ ที่อยูก่ ่อนหน้ านี ้
• การทา spilling ลดช่วงชีวิต (live range) ของ f
– เพราะฉะนันท
้ าให้ interference (การทับหรื อรบกวนกันของตัวแปร) ลดลง
– ซึง่ ทาให้ node ของ f ใน RIG มี neighbor ที่น้อยลง
คานวณ RIG ใหม่หลังจาก Spilling
• Edge หลังจากที่ node ที่ทาการ spill จะถูกกาจัดออกจาก RIG เดิม
• ตัวแปร f live range ยังทับซ้ อนกับ live range ของ c และ d
• ได้ RIG ใหม่ที่สามารถใช้ เพียง 3 สีในการให้ สี RIG นี ้ได้ (3-colorable)
การตัดสิ นใจเกี่ยวกับ Spilling
• ในบางครัง้ เราอาจจะต้ อง spill มากกว่าหนึ่งครัง้ ก่อนที่จะทา coloring
จากจานวนสีที่กาหนดให้ อย่างจากัดได้
• เราสามารถเลือกที่จะ spill ตัวแปรตัวใดก็ได้ อัลกอริ ทมึ ที่กล่าวมายังคง
ทางานได้ ถกู ต้ อง
• แต่การเลือกที่ดีจะช่วยเพิ่มประสิทธิภาพของโค๊ ด assembly ที่ผลิลิตได้
– มี heuristics ที่ใช้ ในการเลือกต่อไปนี ้:
• Spill ตัวแปรที่ทาให้ เกิด interference มากที่สดุ (นัน่ คือมี neighbor มากที่สดุ )
• Spill ตัวแปรที่ใช้ งานน้ อย
• หลีกเลี่ยงการ spill ใน inner loop
ประเด็นหลักเกี่ยวกับ Register Allocation
• คอมไพเลอร์ ในปั จจุบนั ทา optimization อันนี ้ทังนั
้ น้
– เพราะสมรรถนะที่แตกต่างกันมากระหว่าง CPU กับ memory การคานวณที่
เกี่ยวข้ องกับตัวแปรที่อยูใ่ นรี จิสเตอร์ จะทาได้ เร็วกว่าตัวแปรที่อยู่ใน memory
มาก
– การผลิลิตโค๊ ดในสไตล์ stack machine จะมีสมรรถนะต่ามากเพราะมีการ
โต้ ตอบกับ memory มาก
• การทา register allocation สาหรับ CISC จะยุง่ ยากมากกว่า
RISC
– รี จิสเตอร์ แต่ละตัวมีสิ่งที่พิเศษเฉพาะตัว อาจจะไม่สามารถนามาใส่ตวั แปรบางชนิด
ในทุกๆกรณีได้
ลาดับชั้นของระบบหน่วยความจา
(Memory Hierarchy)
การจัดการหน่วยความจาลาดับชั้น
• ภาพของหน่วยความจาที่โปรแกรมเมอร์ เห็นคือที่เก็บข้ อมูลที่มีตาแหน่งติดกันและมี
ความจุเป็ นอนันต์และมีประสิทธิภาพสูง (Virtual Memory)
• CPU OS และคอมไพเลอร์ จะทาหน้ าที่จดั การลาดับชันของหน่
้
วยความจาเพื่อให้
ภาพในอุดมคตินนกั
ั ้ บโปรแกรมเมอร์
– ในโลกความเป็ นจริ งลาดับชันของหน่
้
วยความจามีความจากัดทางด้ านความจุและ
สมรรถนะ
– CPU OS และ คอมไพเลอร์ จะต้ อง “ซ่อน” ข้ อจากัดนี ้และ “หลอก” โปรแกรมเมอร์ ให้
มองเห็นแต่ในโลกเสมือน
• CPU จัดการในส่วนที่เกี่ยวข้ องกับ main memory และ cache
• คอมไพเลอร์ จดั การในส่วนการบริ หารรี จิสเตอร์ และการติดต่อกับ main
memory
• OS จัดการในส่วนที่เกี่ยวข้ องกับ main memory และ disc
Cache
• คอมไพเลอร์ เก่งเรื่ องการจัดการรี จิสเตอร์
• ถ้ าเราต้ องการให้ คอมไพเลอร์ ช่วย CPU ในการจัดการ cache
– ทาได้ ระดับหนึง่ แต่คอมไพเลอร์ ไม่เก่งมาก
– หลายๆอย่างโปรแกรมเมอร์ ต้องออกมาจากโลกเสมือนเพื่อช่วยคอมไพเลอร์
– เป็ นหนึง่ ในแนวทางการวิจยั ทางด้ านคอมไพเลอร์ ในปั จจุบนั
การ Optimize การใช้ Cache
• พิจารณา loop ด้ านล่างนี ้
for(j := 1; j < 10; j++)
for(i=1; i<10000000; i++)
a[i] *= b[i]
• Loop นี ้มีประสิทธิภาพต่าเพราะมีการใช้ งาน cache อย่างไม่มี
ประสิทธิภาพ
• ทุกๆการอ้ างถึงค่าใน a[i] หรื อ b[i] เป็ นการ miss ทังหมด
้
(ให้ วา่
cache block มีขนาดเท่ากับหนึง่ element ของ a และ b)
การ Optimize การใช้ Cache
• พิจารณาการเขียนโปรแกรมใหม่จากสไลด์ที่แล้ วดังนี ้:
for(i=1; i<10000000; i++)
for(j := 1; j < 10; j++)
a[i] *= b[i]
– ให้ ผลิลลัพธ์เหมือนกันแต่สมรรถนะของโปรแกรมนี ้สูงขึ ้นมาก
– การใช้ ประโยชน์จาก cache ทาได้ สงู สุด
– สมรรถนะที่เพิ่มขึ ้นอาจจะมากกว่า 10 เท่า
• Optimization ในลักษณะนี ้ (เรี ยกว่า loop interchange)
คอมไพเลอร์ สามารถทาได้
– อาจจะต้ องทาในระดับ high-level IR