เครื่องมือ การแสดงผล GPU ตามโปรไฟล์จะระบุเวลาที่สัมพันธ์กันของแต่ละขั้นตอนใน ไปป์ไลน์การแสดงผลเพื่อแสดงผลเฟรมก่อนหน้า ความรู้นี้ จะช่วยให้คุณระบุคอขวดในไปป์ไลน์ได้ เพื่อให้คุณ เพิ่มประสิทธิภาพเพื่อปรับปรุงประสิทธิภาพการแสดงผลของแอปได้
หน้านี้จะอธิบายโดยย่อถึงสิ่งที่เกิดขึ้นในแต่ละขั้นตอนของไปป์ไลน์และ กล่าวถึงปัญหาที่อาจทำให้เกิดคอขวด ก่อนอ่านหน้านี้ คุณควรทำความคุ้นเคยกับข้อมูลที่แสดงในความเร็วในการแสดงผลของ GPU ในโปรไฟล์ นอกจากนี้ คุณอาจต้องดู วิธีการทำงานของไปป์ไลน์การแสดงผลเพื่อทำความเข้าใจว่าแต่ละขั้นตอนเชื่อมโยงกันอย่างไร
การแสดงภาพ
เครื่องมือการแสดงผล GPU ตามโปรไฟล์จะแสดงขั้นตอนและเวลาที่เกี่ยวข้องใน รูปแบบของกราฟ ซึ่งเป็นฮิสโทแกรมที่ใช้รหัสสี รูปที่ 1 แสดงตัวอย่าง การแสดงผลดังกล่าว
แต่ละส่วนของแถบแนวตั้งแต่ละแถบที่แสดงในกราฟการแสดงผล GPU ของโปรไฟล์ แสดงถึงขั้นตอนของไปป์ไลน์และจะไฮไลต์โดยใช้สีที่เฉพาะเจาะจง ในกราฟแท่ง รูปที่ 2 แสดงคำอธิบายความหมายของแต่ละสีที่แสดง
เมื่อเข้าใจความหมายของแต่ละสีแล้ว คุณจะกำหนดเป้าหมายไปยังแง่มุมที่เฉพาะเจาะจงของ แอปเพื่อพยายามเพิ่มประสิทธิภาพการแสดงผลได้
ขั้นตอนและความหมาย
ส่วนนี้จะอธิบายสิ่งที่เกิดขึ้นในแต่ละขั้นตอน รวมถึงสาเหตุที่ทำให้เกิดคอขวดที่ควรระวัง
การจัดการอินพุต
ขั้นตอนการจัดการอินพุตของไปป์ไลน์จะวัดระยะเวลาที่แอปใช้ในการจัดการเหตุการณ์อินพุต เมตริกนี้ระบุระยะเวลาที่แอป ใช้ในการเรียกใช้โค้ดที่เรียกใช้เป็นผลจากการเรียกกลับของเหตุการณ์อินพุต
เมื่อกลุ่มนี้มีขนาดใหญ่
ค่าสูงในส่วนนี้มักเกิดจากงานมากเกินไปหรืองานที่ซับซ้อนเกินไป ซึ่งเกิดขึ้นภายในแฮนเดิลอินพุตของฟังก์ชันเรียกกลับของเหตุการณ์ เนื่องจาก Callback เหล่านี้เกิดขึ้นในเทรดหลักเสมอ วิธีแก้ปัญหานี้จึงมุ่งเน้นไปที่การเพิ่มประสิทธิภาพงานโดยตรงหรือการส่งต่องานไปยังเทรดอื่น
การเลื่อนดูLazyColumn
หรือ LazyRow
อาจเกิดขึ้นในระยะนี้ด้วย เมื่อการแตะของผู้ใช้มีคุณสมบัติเป็นเลื่อน lazy
list จะใช้เหตุการณ์การแตะเพื่อจัดวางและแสดงรายการแบบไดนามิก หากแอปของคุณ
ทำงานที่กำหนดเองเพื่อตอบสนองต่อการเปลี่ยนแปลงตำแหน่งการเลื่อน
คุณควรทำให้การดำเนินการนี้เร็วที่สุดเท่าที่จะเป็นไปได้เพื่อป้องกันไม่ให้เฟรม
หลุด เครื่องมือสร้างโปรไฟล์ เช่น เครื่องมือสร้างโปรไฟล์ CPU ใน Android Studio หรือ Perfetto จะช่วยให้คุณตรวจสอบเพิ่มเติมได้ ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมของการติดตามระบบ
ภาพเคลื่อนไหว
ระยะภาพเคลื่อนไหวจะแสดงระยะเวลาที่ใช้ในการประเมินสถานะภาพเคลื่อนไหวทั้งหมด
ที่ทำงานในเฟรมนั้น API ภาพเคลื่อนไหวที่ใช้กันโดยทั่วไปใน Compose มีดังนี้
animate*AsState
Transition
และ Animatable
นอกจากนี้ Recomposer ยังทำงานในระหว่างขั้นตอนนี้เพื่อประมวลผลการเปลี่ยนแปลงสถานะของ Snapshot
และอัปเดตการจัดองค์ประกอบ ซึ่งหมายความว่าค่าใช้จ่ายในการจัดองค์ประกอบใหม่มักจะปรากฏ
โดยตรงในขั้นตอนการสร้างภาพเคลื่อนไหว
สำหรับ UI ของ Jetpack Compose ให้รวมไลบรารี การติดตามรันไทม์ของ Compose เพื่อดูการติดตามการคอมโพสแบบละเอียดควบคู่ไปกับเหตุการณ์ของระบบ
เมื่อกลุ่มนี้มีขนาดใหญ่
โดยปกติแล้วค่าสูงในส่วนนี้เกิดจากงานที่ดำเนินการเนื่องจาก
การเปลี่ยนแปลงสถานะที่เกิดจากภาพเคลื่อนไหว ตัวอย่างเช่น ภาพเคลื่อนไหวแบบดีด ซึ่งเลื่อน LazyColumn
หรือ LazyRow จะทำให้เกิดการเรียบเรียง การวัด และการจัดสรรรายการใหม่ในรายการอย่างรวดเร็ว
Measure
Android จะดำเนินการ3 เฟสในโหนดเลย์เอาต์ ในแผนผัง UI เพื่อวาด Composable บนหน้าจอ
ก่อนอื่น ระบบจะวัดโหนดเลย์เอาต์ Composable ทุกรายการมีข้อจำกัดและตัวแก้ไขที่เฉพาะเจาะจงซึ่งอธิบายขีดจำกัดขนาดของออบเจ็กต์บนหน้าจอ Composable บางรายการอาจมีขนาดที่เฉพาะเจาะจงและคงที่ ส่วนรายการอื่นๆ อาจมีขนาด ที่ปรับตามข้อจำกัดที่ส่งต่อมาจากคอนเทนเนอร์เลย์เอาต์หลัก
จากนั้นระบบจะวางโหนดเลย์เอาต์ เมื่อ Compose คำนวณขนาดของ โหนดลูกในระหว่างเฟสการวัดแล้ว ก็จะดำเนินการต่อในเฟสการจัดวางได้ ซึ่งจะกำหนดขนาดและตำแหน่งของโหนดเลย์เอาต์บนหน้าจอ
ระบบจะใช้เลย์เอาต์แบบผ่านเดียวนี้เสมอเพื่อประสิทธิภาพ เมื่อเลย์เอาต์ที่ประกอบได้ไม่ถูกต้อง Compose จะวัดโหนดนั้นๆ และเผยแพร่การอัปเดตเลย์เอาต์ไปยังลำดับชั้นระดับบนสุดเท่านั้น หาก องค์ประกอบย่อยเปลี่ยนขนาดหรือข้อจำกัด
เมื่อกลุ่มนี้มีขนาดใหญ่
ส่วนขนาดใหญ่ในพื้นที่นี้หมายความว่าแอปใช้เวลามากเกินไปในระยะเลย์เอาต์ ซึ่งประกอบด้วยการกำหนดตำแหน่งและขนาดของโหนดเลย์เอาต์ การดำเนินการเหล่านี้ รวมถึงการดำเนินการตัวแก้ไขการวัดและการจัดวางสำหรับ Composable ซึ่งอาจ ทำให้การเตรียมเฟรมล่าช้าหากแผนผังเลย์เอาต์มีความซับซ้อนมากเกินไป ในกรณีเหล่านี้ การแก้ไขประสิทธิภาพเกี่ยวข้องกับการเปรียบเทียบแอป Compose และทำตามแนวทางปฏิบัติแนะนำด้านประสิทธิภาพ
ใช้เครื่องมือสร้างโปรไฟล์ CPU ใน Android Studio หรือ Perfetto เพื่อตรวจสอบการส่งเลย์เอาต์และระบุจุดคอขวด ดูข้อมูลเพิ่มเติมได้ที่ ภาพรวมของการติดตามระบบ
วาด
ขั้นตอนการวาดจะแปลการดำเนินการแสดงผล เช่น การวาด พื้นหลัง รูปร่าง หรือข้อความ ให้เป็นลำดับของคำสั่งการวาดแบบเนทีฟ ระบบจะบันทึกคำสั่งเหล่านี้ลงในรายการแสดงผลสำหรับการดำเนินการของ GPU
แถบวาดจะบันทึกระยะเวลาที่ใช้ในการบันทึกคำสั่งให้เสร็จสมบูรณ์ ลงในรายการแสดงผลสำหรับโหนดเลย์เอาต์ทั้งหมดที่ต้องอัปเดตบน หน้าจอสำหรับเฟรมนี้ เวลาที่วัดได้ยังใช้กับตรรกะการวาดที่กำหนดเอง ที่คุณอาจมีภายในตัวแก้ไขการวาดหรือ Canvas ที่ใช้ร่วมกันได้ด้วย
เมื่อกลุ่มนี้มีขนาดใหญ่
พูดง่ายๆ ก็คือ คุณสามารถเข้าใจเมตริกนี้ได้ว่าแสดงระยะเวลาที่ใช้ในการเรียกใช้คำสั่งการวาดทั้งหมดสำหรับโหนดเลย์เอาต์แต่ละรายการที่ใช้ไม่ได้
การวัดนี้รวมถึงเวลาที่ใช้ในการส่งคำสั่งเหล่านี้ไปยังโหนดย่อย
และ Vector Drawable ด้วยเหตุนี้ เมื่อเห็นว่าแถบนี้เพิ่มขึ้นอย่างรวดเร็ว สาเหตุอาจเป็นเพราะ Composable จำนวนมากกลายเป็นไม่ถูกต้องในทันที
การลบล้างทำให้ต้องเรียกใช้คำสั่งการวาดซ้ำและสร้างรายการแสดงผลของโหนดเลย์เอาต์ใหม่
หรืออาจใช้เวลานานเนื่องจากมี Composable หรือ Canvas ที่กำหนดเองเพียงไม่กี่รายการ
ซึ่งมีตรรกะที่ซับซ้อนอย่างยิ่งในการ
DrawScope
ใช้งาน
นอกจากนี้ Compose มักจะจัดการการวัดและการส่งเลย์เอาต์ภายในใน สิ่งที่แพลตฟอร์มถือว่าเป็นเฟสการวาด ดังนั้น แถบ Draw ที่สูงขึ้นอาจเกิดจากการดำเนินการวัด/เลย์เอาต์ภายในที่มีค่าใช้จ่ายสูงหรือมากเกินไป แทนที่จะเป็นคำสั่งวาดเพียงอย่างเดียว หากไม่แน่ใจ ให้บันทึกการติดตาม Perfetto เพื่อดูว่าค่าใช้จ่ายเพิ่มเติมเกิดจากกิจวัตรการวาดภาพหรือการวัดและการส่งผ่านเลย์เอาต์ของ Compose
อัปโหลด
เมตริกการอัปโหลดแสดงเวลาที่ใช้ในการโอนออบเจ็กต์บิตแมปจากหน่วยความจำ CPU ไปยังหน่วยความจำ GPU ในระหว่างเฟรมปัจจุบัน
CPU และ GPU เป็นโปรเซสเซอร์ที่แตกต่างกัน จึงมีพื้นที่ RAM ที่แตกต่างกัน ซึ่งใช้เฉพาะสำหรับการประมวลผล เมื่อวาดบิตแมปใน Android ระบบจะ โอนบิตแมปไปยังหน่วยความจำ GPU ก่อนที่ GPU จะแสดงผลบิตแมปลงใน หน้าจอได้ จากนั้น GPU จะแคชบิตแมปเพื่อให้ระบบไม่ต้อง โอนข้อมูลอีก เว้นแต่จะมีการนำเท็กซ์เจอร์ออกจากแคชเท็กซ์เจอร์ของ GPU
หมายเหตุ: ในอุปกรณ์ Lollipop ขั้นตอนนี้จะเป็นสีม่วง
เมื่อกลุ่มนี้มีขนาดใหญ่
ทรัพยากรทั้งหมดสำหรับเฟรมต้องอยู่ในหน่วยความจำ GPU ก่อนจึงจะ ใช้ในการวาดเฟรมได้ ซึ่งหมายความว่าค่าสูงสำหรับเมตริกนี้อาจหมายถึง การโหลดทรัพยากรขนาดเล็กจำนวนมากหรือทรัพยากรขนาดใหญ่มาก จำนวนเล็กน้อย กรณีที่พบบ่อยคือเมื่อแอปแสดงบิตแมปเดียวที่มีขนาด ใกล้เคียงกับขนาดของหน้าจอ อีกกรณีหนึ่งคือเมื่อแอปแสดงภาพปกจำนวนมาก
หากต้องการย่อแถบนี้ คุณสามารถใช้เทคนิคต่างๆ เช่น
- ตรวจสอบว่าความละเอียดของบิตแมปไม่ใหญ่กว่าขนาดที่จะแสดงมากนัก เช่น หลีกเลี่ยงการแสดงรูปภาพขนาด 1024x1024 เป็นรูปภาพขนาด 48x48
- ใช้ประโยชน์จากไลบรารีที่ทันสมัย เช่น Coil เพื่ออัปโหลดบิตแมปล่วงหน้าแบบไม่พร้อมกันก่อนระยะการซิงค์ถัดไป
ส่งคำสั่ง
กลุ่มคำสั่งปัญหาแสดงถึงเวลาที่ใช้ในการออกคำสั่งทั้งหมดที่จำเป็นสำหรับการวาดรายการที่แสดงบนหน้าจอ
ระบบจะส่ง คำสั่งที่จำเป็นไปยัง GPU เพื่อให้วาดรายการที่แสดงไปยังหน้าจอ โดยปกติแล้ว การดำเนินการนี้จะทำผ่าน API ของ OpenGL ES
กระบวนการนี้ใช้เวลาสักครู่ เนื่องจากระบบจะทำการเปลี่ยนรูปแบบขั้นสุดท้าย และตัดแต่ละคำสั่งก่อนที่จะส่งคำสั่งไปยัง GPU จากนั้น GPU จะมีค่าใช้จ่ายเพิ่มเติม ซึ่งจะคำนวณคำสั่งสุดท้าย คำสั่งเหล่านี้รวมถึงการเปลี่ยนรูปแบบขั้นสุดท้ายและการตัดเพิ่มเติม
เมื่อกลุ่มนี้มีขนาดใหญ่
เวลาที่ใช้ในขั้นตอนนี้เป็นการวัดความซับซ้อนและ ปริมาณของรายการที่แสดงที่ระบบแสดงในเฟรมที่กำหนดโดยตรง ตัวอย่างเช่น การดำเนินการวาดหลายรายการ โดยเฉพาะในกรณีที่ มีต้นทุนเล็กๆ น้อยๆ ในการวาดแต่ละองค์ประกอบ อาจทำให้เวลานี้เพิ่มขึ้น เช่น
for (i in 0 until 1000) { canvas.drawPoint() }
มีค่าใช้จ่ายในการออกมากกว่า
canvas.drawPoints(thousandPointArray)
การออกคำสั่งและการวาดรายการที่แสดงจริงไม่ได้มีความสัมพันธ์แบบ 1:1 เสมอไป เมตริกการวาดจะแสดงเวลาที่ใช้ในการบันทึกคำสั่งที่ออกไปยังรายการที่แสดง ซึ่งแตกต่างจากแถบคำสั่งปัญหา ที่บันทึกเวลาที่ใช้ในการส่งคำสั่งวาดไปยัง GPU
ความแตกต่างนี้เกิดขึ้นเนื่องจากระบบจะแคชรายการที่แสดงทุกครั้งที่ทำได้ ด้วยเหตุนี้ จึงมีบางกรณีที่การ เลื่อน แปลง หรือภาพเคลื่อนไหวต้องให้ระบบส่งรายการที่แสดงผล อีกครั้ง แต่ไม่จำเป็นต้องสร้างใหม่จริงๆ ซึ่งก็คือการบันทึกคำสั่งวาดภาพ ใหม่ตั้งแต่ต้น ด้วยเหตุนี้ คุณจึงอาจเห็นแถบคำสั่งออกปัญหาที่สูง โดยไม่เห็นแถบคำสั่งวาดที่สูง
สลับบัฟเฟอร์
เมื่อ Android ส่งรายการที่แสดงไปยัง GPU เสร็จแล้ว ระบบจะออกคำสั่งสุดท้ายเพื่อบอกไดรเวอร์กราฟิกว่า เฟรมปัจจุบันเสร็จแล้ว ในขั้นตอนนี้ ไดรเวอร์จะแสดง รูปภาพที่อัปเดตแล้วบนหน้าจอได้
เมื่อกลุ่มนี้มีขนาดใหญ่
คุณควรทราบว่า GPU จะทำงานควบคู่ไปกับ CPU ระบบ Android จะออกคำสั่งวาดไปยัง GPU แล้วไปยัง งานถัดไป GPU จะอ่านคำสั่งวาดเหล่านั้นจากคิวและประมวลผล คำสั่ง
ในกรณีที่ CPU ออกคำสั่งได้เร็วกว่าที่ GPU จะประมวลผลได้ คิวการสื่อสารระหว่างโปรเซสเซอร์อาจเต็ม เมื่อเกิดกรณีนี้ขึ้น CPU จะบล็อกและรอจนกว่าจะมีพื้นที่ใน คิวเพื่อวางคำสั่งถัดไป สถานะคิวเต็มนี้มักเกิดขึ้นในระหว่าง ขั้นตอนการสลับบัฟเฟอร์ เนื่องจากในขั้นตอนนี้ ระบบจะส่งคำสั่ง ทั้งหมดของเฟรม
กุญแจสำคัญในการลดปัญหานี้คือการลดความซับซ้อนของงานที่เกิดขึ้น ใน GPU ในลักษณะเดียวกับที่คุณจะทำในเฟสคำสั่งปัญหา
เบ็ดเตล็ด
นอกเหนือจากเวลาที่ระบบการแสดงผลใช้ในการทำงานแล้ว ยังมีชุดงานเพิ่มเติมที่เกิดขึ้นในเทรดหลักและไม่เกี่ยวข้องกับการแสดงผล เวลาที่ใช้ในการทำงานนี้จะรายงานเป็น เวลาอื่นๆ เวลาอื่นๆ โดยทั่วไปหมายถึงงานที่อาจเกิดขึ้นในเทรด UI ระหว่างเฟรมการแสดงผล 2 เฟรมติดต่อกัน
เมื่อกลุ่มนี้มีขนาดใหญ่
หากค่านี้สูง แสดงว่าแอปของคุณอาจมี Callback, Intent หรือ งานอื่นๆ ที่ควรเกิดขึ้นในเธรดอื่น เครื่องมือต่างๆ เช่น CPU Profiler ใน Android Studio หรือ Perfetto จะช่วยให้มองเห็นงานที่กำลังทำงานอยู่ ในเทรดหลัก ข้อมูลนี้จะช่วยให้คุณกำหนดเป้าหมายการปรับปรุงประสิทธิภาพได้ ดูข้อมูลเพิ่มเติมได้ที่ ภาพรวมของการติดตามระบบ