วิเคราะห์ด้วยการแสดงผล GPU ของโปรไฟล์

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

หน้านี้จะอธิบายถึงสิ่งที่เกิดขึ้นในแต่ละขั้นตอนของไปป์ไลน์โดยสรุป และอธิบายถึงปัญหาที่อาจทำให้เกิดจุดคอขวดในจุดนั้น ก่อนอ่านหน้านี้ คุณควรทำความคุ้นเคยกับข้อมูลที่แสดงในโปรไฟล์การแสดงผล GPU นอกจากนี้ คุณอาจต้องทบทวนวิธีการทำงานของไปป์ไลน์การแสดงผลเพื่อให้เข้าใจว่าแต่ละระยะทำงานร่วมกันอย่างไร

การนำเสนอด้วยภาพ

เครื่องมือการแสดงผล GPU โปรไฟล์จะแสดงขั้นตอนและเวลาที่เกี่ยวข้องในรูปแบบของกราฟ ซึ่งเป็นฮิสโตแกรมที่มีโค้ดสี รูปที่ 1 แสดงตัวอย่าง ของจอแสดงผลดังกล่าว

รูปที่ 1 กราฟการแสดงผล GPU ของโปรไฟล์

แต่ละส่วนของแท่งแนวตั้งแต่ละแท่งที่แสดงในกราฟการแสดงผล GPU ของโปรไฟล์แสดงถึงขั้นของไปป์ไลน์และถูกไฮไลต์โดยใช้สีที่เจาะจงในกราฟแท่ง รูปที่ 2 แสดงคีย์ความหมายของสีที่แสดงแต่ละสี

รูปที่ 2 คำอธิบายกราฟการแสดงผล GPU ของโปรไฟล์

เมื่อเข้าใจแล้วว่าแต่ละสีมีความหมายอย่างไร คุณสามารถกำหนดเป้าหมายเฉพาะด้านของแอปเพื่อพยายามเพิ่มประสิทธิภาพการแสดงผลได้

ขั้นตอนและความหมาย

ส่วนนี้อธิบายสิ่งที่เกิดขึ้นในแต่ละระยะที่ตรงกับสีในรูปที่ 2 รวมถึงสาเหตุที่ควรระวังจุดคอขวด

การจัดการอินพุต

ขั้นตอนการจัดการอินพุตของไปป์ไลน์จะวัดระยะเวลาที่แอปใช้ในการจัดการเหตุการณ์อินพุต เมตริกนี้ระบุระยะเวลาที่แอปใช้ในการเรียกใช้โค้ดที่เรียกเป็นผลมาจากการเรียกกลับเหตุการณ์อินพุต

เมื่อกลุ่มนี้มีขนาดใหญ่

ค่าที่สูงในพื้นที่นี้มักจะเป็นผลมาจากงานมากเกินไปหรือการทำงานที่ซับซ้อนเกินไปที่เกิดขึ้นภายใน Callback ของเหตุการณ์เครื่องมือจัดการอินพุต เนื่องจากระบบจะเรียกใช้การเรียกกลับเหล่านี้ในเธรดหลักเสมอ วิธีแก้ปัญหานี้จึงมุ่งเน้นที่การเพิ่มประสิทธิภาพงานโดยตรง หรือส่งงานไปยังเธรดอื่น

นอกจากนี้ โปรดทราบว่า RecyclerView การเลื่อนอาจเกิดขึ้นในระยะนี้ RecyclerView เลื่อนทันทีที่ใช้งานเหตุการณ์การสัมผัส ด้วยเหตุนี้ ระบบจึงอาจเพิ่มหรือป้อนข้อมูลยอดดูรายการใหม่ ด้วยเหตุนี้ จึงเป็นสิ่งสำคัญ ที่คุณจะต้องทำให้การดำเนินการนี้เร็วที่สุด เครื่องมือการทำโปรไฟล์ เช่น Traceview หรือ Systrace จะช่วยให้คุณตรวจสอบเพิ่มเติมได้

แอนิเมชัน

ช่วงภาพเคลื่อนไหวจะแสดงเวลาที่ใช้ในการประเมินภาพเคลื่อนไหวทั้งหมดที่อยู่ในเฟรมนั้น ผู้สร้างแอนิเมชันที่พบบ่อยที่สุดคือ ObjectAnimator, ViewPropertyAnimator และ ทรานซิชัน

เมื่อกลุ่มนี้มีขนาดใหญ่

ค่าสูงในพื้นที่นี้มักเป็นผลมาจากงานที่ดำเนินการเนื่องจากการเปลี่ยนแปลงพร็อพเพอร์ตี้บางอย่างของภาพเคลื่อนไหว ตัวอย่างเช่น ภาพเคลื่อนไหวแบบขว้าง ซึ่งจะเลื่อน ListView หรือ RecyclerView ก็ทําให้อัตราเงินเฟ้อและประชากรเพิ่มขึ้นอย่างมาก

การวัด/เลย์เอาต์

เพื่อให้ Android วาดรายการในมุมมองบนหน้าจอได้ การดำเนินการนั้นจะดำเนินการ 2 อย่างในเลย์เอาต์และมุมมองในลำดับชั้นการแสดงผล

ขั้นแรก ระบบจะวัดรายการการดู มุมมองและเลย์เอาต์ทุกรายการมีข้อมูลที่เฉพาะเจาะจงซึ่งอธิบายขนาดของวัตถุบนหน้าจอ มุมมองบางรายการอาจมีขนาดที่เจาะจง ในขณะที่มุมมองอื่นๆ มีขนาดที่ปรับตามขนาดของคอนเทนเนอร์เลย์เอาต์หลัก

ขั้นที่สอง ระบบจัดวางรายการมุมมอง เมื่อระบบคำนวณขนาดของมุมมองสำหรับเด็กแล้ว ก็จะดำเนินการต่อด้วยเลย์เอาต์ การปรับขนาด และการวางตำแหน่งมุมมองบนหน้าจอ

ระบบจะวัดและจัดเลย์เอาต์ไม่เพียงแต่สำหรับมุมมองที่จะวาดเท่านั้น แต่ยังสำหรับลำดับชั้นระดับบนของมุมมองเหล่านั้นไปจนถึงมุมมองรูทด้วย

เมื่อกลุ่มนี้มีขนาดใหญ่

หากแอปใช้เวลานานมากต่อเฟรมในส่วนนี้ สาเหตุมักเกิดจากปริมาณมุมมองจำนวนมากที่ต้องจัดวาง หรือปัญหาต่างๆ เช่น การเรียกเก็บภาษีซ้ำในตำแหน่งที่ไม่ถูกต้องในลําดับชั้น ไม่ว่าในกรณีใด การจัดการประสิทธิภาพก็เกี่ยวข้องกับการปรับปรุงประสิทธิภาพของลําดับชั้นมุมมอง

รหัสที่คุณเพิ่มลงใน onLayout(boolean, int, int, int, int) หรือ onMeasure(int, int) อาจทำให้เกิดปัญหาด้านประสิทธิภาพได้เช่นกัน Traceview และ Systrace ช่วยให้คุณตรวจสอบกองคิวการเรียกเพื่อระบุปัญหาที่โค้ดอาจพบได้

วาด

ระยะวาดจะแปลการดำเนินการแสดงผลของมุมมอง เช่น การวาดพื้นหลังหรือการวาดข้อความ เป็นลำดับคำสั่งวาดแบบดั้งเดิม ระบบจะบันทึกคําสั่งเหล่านี้ไว้ในรายการที่แสดง

แถบวาดจะบันทึกระยะเวลาที่ใช้ในการบันทึกคําสั่งลงในรายการการแสดงผลสําหรับมุมมองทั้งหมดที่ต้องอัปเดตบนหน้าจอในเฟรมนี้ เวลาที่วัดจะใช้กับโค้ดทั้งหมดที่คุณเพิ่มลงในออบเจ็กต์ UI ในแอป ตัวอย่างของโค้ดดังกล่าวอาจเป็น onDraw(), dispatchDraw() และ draw ()methods ต่างๆ ที่เป็นของคลาสย่อยของคลาส Drawable

เมื่อกลุ่มนี้มีขนาดใหญ่

กล่าวอย่างง่ายคือ เมตริกนี้แสดงระยะเวลาที่ใช้เรียกใช้ onDraw() ทั้งหมดสําหรับมุมมองที่ลบล้างแล้วแต่ละรายการ การวัดนี้รวมเวลาที่ใช้ส่งคําสั่งวาดไปยังองค์ประกอบย่อยและสิ่งที่วาดได้ซึ่งอาจปรากฏอยู่ด้วย ด้วยเหตุนี้ เมื่อคุณเห็นแท่งกราฟพุ่งสูงขึ้น สาเหตุก็อาจเป็นเพราะการดูจำนวนมากกลายเป็นโมฆะกะทันหัน การระบุว่าไม่ถูกต้องทำให้จำเป็นต้องสร้างรายการยอดดูใหม่ หรือเวลาที่ยาวนานอาจเป็นผลมาจากมุมมองที่กำหนดเอง 2-3 รายการที่มีตรรกะที่ซับซ้อนมากในเมธอด onDraw()

ซิงค์/อัปโหลด

เมตริกการซิงค์และอัปโหลดแสดงเวลาที่ใช้ในการโอนออบเจ็กต์บิตแมปจากหน่วยความจำ CPU ไปยังหน่วยความจำ GPU ระหว่างเฟรมปัจจุบัน

เนื่องจากโปรเซสเซอร์ต่างกัน CPU และ GPU จะมีพื้นที่ RAM เฉพาะสำหรับการประมวลผล เมื่อคุณวาดบิตแมปบน Android ระบบจะโอนบิตแมปไปยังหน่วยความจำ GPU ก่อนที่ GPU จะสามารถแสดงผลบนหน้าจอได้ จากนั้น GPU จะแคชบิตแมปเพื่อให้ระบบไม่ต้องโอนข้อมูลอีกครั้ง เว้นแต่ว่าจะมีการนำพื้นผิวออกจากแคชพื้นผิวของ GPU

หมายเหตุ: บนอุปกรณ์ Lollipop ระยะนี้จะเป็นสีม่วง

เมื่อกลุ่มนี้มีขนาดใหญ่

ทรัพยากรทั้งหมดของเฟรมต้องอยู่ในหน่วยความจำ GPU ก่อนจึงจะใช้วาดเฟรมได้ ซึ่งหมายความว่าค่าที่สูงสำหรับเมตริกนี้อาจหมายถึงการโหลดทรัพยากรจำนวนมากหรือทรัพยากรที่มีขนาดใหญ่มากจำนวนน้อย กรณีที่พบบ่อยคือเมื่อแอปแสดงบิตแมปเดียวที่ใกล้เคียงกับขนาดของหน้าจอ อีกกรณีหนึ่งคือเมื่อแอปแสดงภาพปกจํานวนมาก

หากต้องการย่อแท่งแผนภูมิดังกล่าว คุณสามารถใช้เทคนิคต่างๆ เช่น

  • โดยตรวจสอบว่าความละเอียดของบิตแมปไม่ได้ใหญ่กว่าขนาดที่จะแสดง ตัวอย่างเช่น แอปของคุณควรหลีกเลี่ยงการแสดงรูปภาพขนาด 1024x1024 เป็นรูปภาพขนาด 48x48
  • ใช้ประโยชน์จาก prepareToDraw() เพื่ออัปโหลดบิตแมปล่วงหน้าแบบไม่พร้อมกันก่อนขั้นตอนการซิงค์ถัดไป

ออกคำสั่ง

ส่วนคำสั่งปัญหาแสดงระยะเวลาที่ใช้ในการออกคำสั่งทั้งหมดที่จำเป็นสำหรับการวาดรายการที่แสดงไปยังหน้าจอ

ระบบจะส่งคําสั่งที่จําเป็นไปยัง GPU เพื่อให้วาดรายการที่แสดงบนหน้าจอ ซึ่งโดยปกติแล้วจะดำเนินการนี้ผ่าน API OpenGL ES

กระบวนการนี้ใช้เวลาสักระยะหนึ่ง เนื่องจากระบบทำการเปลี่ยนรูปแบบขั้นสุดท้ายและตัดข้อความสำหรับแต่ละคำสั่งก่อนที่จะส่งคำสั่งไปยัง GPU จากนั้นจะมีค่าใช้จ่ายเพิ่มเติมในด้าน GPU ซึ่งจะคํานวณคําสั่งสุดท้าย คำสั่งเหล่านี้รวมถึงการเปลี่ยนรูปแบบสุดท้ายและการคลิปเพิ่มเติม

เมื่อกลุ่มนี้มีขนาดใหญ่

เวลาที่ใช้ในขั้นตอนนี้จะเป็นการวัดความซับซ้อนและจำนวนรายการที่แสดงที่ระบบแสดงผลในเฟรมหนึ่งๆ ได้โดยตรง ตัวอย่างเช่น การมีการดำเนินการดึงข้อมูลจำนวนมาก โดยเฉพาะอย่างยิ่งในกรณีที่มีค่าใช้จ่ายแฝงเล็กๆ น้อยๆ สำหรับการวาดพื้นฐานแต่ละครั้ง อาจทำให้สูงเกินเวลาได้ เช่น

Kotlin

for (i in 0 until 1000) {
    canvas.drawPoint()
}

Java

for (int i = 0; i < 1000; i++) {
    canvas.drawPoint()
}

มีค่าใช้จ่ายในการออกสูงกว่ามาก

Kotlin

canvas.drawPoints(thousandPointArray)

Java

canvas.drawPoints(thousandPointArray);

การออกคำสั่งกับการวาดรายการแสดงไม่ได้สัมพันธ์กันแบบ 1:1 เสมอไป เมตริก Draw จะแสดงเวลาที่ใช้ในการบันทึกคำสั่งที่ออกลงในรายการที่แสดง ซึ่งแตกต่างจากคำสั่งปัญหาที่บันทึกระยะเวลาในการส่งคำสั่งวาดไปยัง GPU

ความแตกต่างนี้เกิดขึ้นเนื่องจากระบบแคชรายการที่แสดง เมื่อเป็นไปได้ ด้วยเหตุนี้ จึงมีบางกรณีที่การเลื่อน การเปลี่ยนรูปแบบ หรือภาพเคลื่อนไหวทำให้ระบบต้องส่งรายการที่แสดงอีกครั้ง แต่ไม่จำเป็นต้องสร้างใหม่ทั้งหมด นั่นคือไม่ต้องบันทึกคำสั่งวาดภาพใหม่ตั้งแต่ต้น คุณจึงเห็นแถบ "ออกคำสั่ง" สูงโดยที่ไม่เห็นแถบวาดคำสั่งสูง

ประมวลผล/สลับบัฟเฟอร์

เมื่อ Android ส่งรายการการแสดงผลทั้งหมดไปยัง GPU แล้ว ระบบจะออกคำสั่งสุดท้ายเพื่อแจ้งให้ไดรเวอร์กราฟิกทราบว่าแสดงเฟรมปัจจุบันเสร็จแล้ว เมื่อถึงจุดนี้ โปรแกรมควบคุมจึงแสดงภาพเวอร์ชันอัปเดตบนหน้าจอได้

เมื่อกลุ่มนี้มีขนาดใหญ่

โปรดเข้าใจว่า GPU ทำงานควบคู่กับ CPU ปัญหาเกี่ยวกับระบบ Android จะวาดคำสั่งไปยัง GPU แล้วย้ายไปยังงานถัดไป GPU จะอ่านคำสั่งดึงเหล่านั้นจากคิวและประมวลผลคำสั่งเหล่านั้น

ในกรณีที่ปัญหาของ CPU มีคำสั่งเร็วกว่าที่ GPU ใช้ไป คิวการสื่อสารระหว่างตัวประมวลผลอาจเต็มได้ เมื่อเกิดกรณีนี้ขึ้น CPU จะบล็อกและรอจนกว่าจะมีพื้นที่ในคิวเพื่อวางคำสั่งถัดไป สถานะคิวเต็มนี้เกิดขึ้นบ่อยครั้งในช่วงสลับบัฟเฟอร์ เพราะ ณ เวลานั้น มีการส่งคำสั่งของทั้งเฟรม

หัวใจสำคัญในการบรรเทาปัญหานี้คือลดความซับซ้อนของงานที่ดำเนินการใน GPU ในลักษณะเดียวกับที่คุณจะทำในขั้นตอน "ออกคำสั่ง"

เบ็ดเตล็ด

นอกจากเวลาที่ระบบใช้ทำงานแล้ว ยังมีงานอีกชุดหนึ่งที่เกิดขึ้นในเทรดหลักและไม่เกี่ยวข้องกับการแสดงผล ระบบจะรายงานเวลาที่ใช้ในการทำงานนี้ว่าเป็นเวลาอื่นๆ โดยทั่วไปแล้ว เวลาอื่นๆ จะแสดงถึงงานที่อาจเกิดขึ้นในเธรด UI ระหว่างเฟรมการแสดงผล 2 เฟรมติดต่อกัน

เมื่อกลุ่มนี้มีขนาดใหญ่

หากค่านี้สูง แสดงว่าแอปของคุณอาจมีคอลแบ็ก อินเทนต์ หรืองานอื่นๆ ที่ควรเกิดขึ้นในเธรดอื่น เครื่องมือต่างๆ เช่น การติดตามเมธอดหรือ Systrace จะช่วยให้คุณเห็นภาพงานที่กำลังทำงานอยู่ในเธรดหลัก ข้อมูลนี้จะช่วยให้คุณมุ่งปรับปรุงประสิทธิภาพได้