การทำโปรไฟล์เกม WebGL ด้วย Flag "เกี่ยวกับ:การติดตาม"

Lilli Thompson
Lilli Thompson

หากวัดผลไม่ได้ คุณก็ปรับปรุงไม่ได้

ลอร์ดเคลวิน

หากต้องการให้เกม HTML5 ทำงานได้เร็วขึ้น คุณต้องระบุจุดคอขวดด้านประสิทธิภาพก่อน แต่ก็อาจทำได้ยาก การประเมินข้อมูลเฟรมต่อวินาที (FPS) เป็นจุดเริ่มต้น แต่หากต้องการดูภาพรวม คุณต้องเข้าใจความแตกต่างของกิจกรรมใน Chrome

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

สวัสดีเกี่ยวกับ:การติดตาม

เครื่องมือ about:tracing ของ Chrome จะทำให้คุณเห็นภาพรวมของกิจกรรมทั้งหมดของ Chrome ในช่วงเวลาหนึ่ง ซึ่งมีรายละเอียดมากมายจนคุณอาจรู้สึกว่ายุ่งยากในตอนแรก ฟังก์ชันหลายอย่างใน Chrome มีเครื่องมือในการติดตามตั้งแต่แกะกล่อง ดังนั้นแม้ไม่มีการติดตั้งใช้งานด้วยตนเอง คุณยังสามารถใช้ about:tracing เพื่อติดตามประสิทธิภาพได้ (ดูส่วนภายหลังเกี่ยวกับการใช้เครื่องมือ JS ด้วยตนเอง)

หากต้องการดูมุมมองการติดตาม ให้พิมพ์ "about:tracing" ลงในแถบอเนกประสงค์ (แถบที่อยู่) ของ Chrome

วันที่ แถบอเนกประสงค์ของ Chrome
พิมพ์ "about:tracing" ลงในแถบอเนกประสงค์ของ Chrome

คุณจะเริ่มบันทึกจากเครื่องมือติดตาม เล่นเกมเป็นเวลา 2-3 วินาที แล้วดูข้อมูลการติดตามได้ นี่คือตัวอย่างของลักษณะของข้อมูล

วันที่ ผลลัพธ์การติดตามอย่างง่าย
ผลลัพธ์การติดตามอย่างง่าย

ใช่แล้ว มันชวนสับสน มาพูดถึงวิธีการอ่านกัน

แต่ละแถวจะแสดงกระบวนการที่ได้รับการสร้างโปรไฟล์ แกนด้านซ้ายขวาจะระบุเวลา และกล่องสีแต่ละกล่องคือการเรียกฟังก์ชันที่มีการวัดคุม โดยจะมีแถวสำหรับทรัพยากรหลายประเภท โดยตัวแปรที่น่าสนใจที่สุดสำหรับการทำโปรไฟล์เกมคือ CrGpuMain ซึ่งแสดงสิ่งที่หน่วยประมวลผลกราฟิก (GPU) กำลังทำอยู่ และ CrRendererMain การติดตามแต่ละรายการจะมีบรรทัด CrRendererMain สำหรับแต่ละแท็บที่เปิดอยู่ระหว่างระยะเวลาการติดตาม (รวมถึงแท็บ about:tracing)

เมื่ออ่านข้อมูลการติดตาม งานแรกของคุณคือการระบุแถว CrRendererMain แถวไหนที่สอดคล้องกับเกมของคุณ

วันที่ ผลลัพธ์การติดตามอย่างง่ายที่ไฮไลต์
ไฮไลต์ผลลัพธ์การติดตามอย่างง่าย

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

กำลังค้นหากรอบแว่น

เมื่อพบแถวที่ถูกต้องในเครื่องมือการติดตามของเกมแล้ว ขั้นตอนถัดไปคือหาลูปหลัก ลูปหลักจะดูเหมือนรูปแบบที่เกิดซ้ำในข้อมูลการติดตาม คุณสามารถไปยังส่วนต่างๆ ของข้อมูลการติดตามโดยใช้ปุ่ม W, A, S, D: A และ D เพื่อเลื่อนไปทางซ้ายหรือขวา (กลับไปกลับมา) และ W และ S เพื่อซูมเข้าและออกข้อมูล คุณคาดว่าลูปหลักของคุณจะเป็นรูปแบบที่เกิดซ้ำทุกๆ 16 มิลลิวินาทีหากเกมของคุณทำงานที่อัตรา 60 Hz

วันที่ ดูเหมือนว่ามีเฟรมการดำเนินการ 3 เฟรม
ดูเหมือนมีเฟรมการดำเนินการ 3 เฟรม

เมื่อพบจังหวะการเต้นของหัวใจของเกมแล้ว คุณสามารถตรวจสอบได้ว่าโค้ดของคุณกำลังทำอะไรในแต่ละเฟรม ใช้ W, A, S, D เพื่อซูมเข้าจนกว่าคุณจะอ่านข้อความในช่องฟังก์ชันได้

วันที่ เจาะลึกถึงเฟรมการดำเนินการ
เจาะลึกในเฟรมการดำเนินการ

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

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

การเพิ่มแท็กการติดตาม

โชคดีที่เรามีวิธีเพิ่มการติดตั้งใช้งานด้วยตนเองลงในโค้ดเพื่อสร้างข้อมูลการติดตาม ซึ่งก็คือ console.time และ console.timeEnd

console.time("update");
update();
console.timeEnd("update");
console.time("render");
update();
console.timeEnd("render");

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

วันที่ แท็กที่เพิ่มด้วยตนเอง
แท็กที่เพิ่มด้วยตนเอง

การใช้วิธีนี้ช่วยให้คุณสร้างข้อมูลการติดตามที่มนุษย์อ่านได้เพื่อติดตามฮอตสปอตในโค้ด

GPU หรือ CPU

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

ขั้นแรก ให้หาบรรทัดบนมุมมองการติดตามที่ชื่อ CrGPUMain ซึ่งระบุว่า GPU ไม่ว่างในขณะนั้นหรือไม่

การติดตาม GPU และ CPU

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

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

console.time("update");
doExtraWork();
update(Math.min(50, now - time));
console.timeEnd("update");

console.time("render");
render();
console.timeEnd("render");

ตอนนี้คุณจะเห็นการติดตามที่มีลักษณะเช่นนี้

การติดตาม GPU และ CPU

การติดตามนี้บอกอะไรเราบ้าง เราจะเห็นว่าเฟรมที่แสดงในภาพเปลี่ยนจาก 2270 มิลลิวินาที ไปเป็น 2320 มิลลิวินาที ซึ่งหมายความว่าแต่ละเฟรมจะใช้เวลาประมาณ 50 มิลลิวินาที (อัตราเฟรม 20 Hz) คุณจะเห็นชิ้นส่วนต่างๆ ของกล่องสีที่แสดงถึงฟังก์ชันการแสดงผลข้างกล่องอัปเดต แต่เฟรมนั้นเด่นด้วยตัวอัปเดตเองทั้งหมด

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

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

#ifdef GL_ES
precision highp float;
#endif
void main(void) {
  for(int i=0; i<9999; i++) {
    gl_FragColor = vec4(1.0, 0, 0, 1.0);
  }
}

ร่องรอยของโค้ดที่ใช้ตัวปรับแสงเงานั้นมีลักษณะอย่างไร

วันที่ การติดตาม GPU และ CPU เมื่อใช้โค้ด GPU ที่ช้า
การติดตาม GPU และ CPU เมื่อใช้โค้ด GPU ที่ช้า

ย้ำอีกครั้ง ให้บันทึกระยะเวลาของเฟรม รูปแบบการทำซ้ำจะเริ่มจากประมาณ 2750 มิลลิวินาที เป็น 2950 มิลลิวินาที เป็นระยะเวลา 200 มิลลิวินาที (อัตราเฟรมประมาณ 5 Hz) บรรทัด CrRendererMain แทบจะว่างเปล่า ซึ่งหมายความว่า CPU ไม่มีการใช้งานเกือบตลอดเวลา ขณะที่ GPU ทำงานหนักเกินไป นี่เป็นสัญญาณว่าตัวให้เฉดสีของคุณหนักเกินไป

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

ตัวอย่างจริง

คราวนี้มาดูกันว่าข้อมูลการติดตามจากเกมจริงมีลักษณะอย่างไร หนึ่งในสิ่งที่เจ๋งที่สุดเกี่ยวกับเกมที่สร้างด้วยเทคโนโลยีเว็บแบบเปิดคือ คุณสามารถดูสิ่งที่เกิดขึ้นในผลิตภัณฑ์โปรดของคุณได้ หากคุณต้องการทดสอบเครื่องมือการทำโปรไฟล์ คุณสามารถเลือกชื่อ WebGL ที่คุณชื่นชอบจาก Chrome เว็บสโตร์และสร้างโปรไฟล์ด้วย about:tracing ได้ นี่คือตัวอย่างการติดตามจากเกม Skid Racer ที่ยอดเยี่ยมของ WebGL

วันที่ ตามรอยเกมจริง
การตามหาเกมจริง

ดูเหมือนว่าแต่ละเฟรมจะใช้เวลาประมาณ 20 มิลลิวินาที ซึ่งหมายความว่าอัตราเฟรมจะอยู่ที่ประมาณ 50 FPS คุณจะเห็นว่าการทำงานมีความสมดุลระหว่าง CPU และ GPU แต่ GPU เป็นทรัพยากรที่มีความต้องการมากที่สุด หากคุณต้องการดูว่าโปรไฟล์ตัวอย่างจริงของเกม WebGL เป็นอย่างไร ให้ลองเล่นกับชื่อบางส่วนของ Chrome เว็บสโตร์ที่สร้างด้วย WebGL ได้แก่

บทสรุป

หากต้องการให้เกมทำงานที่อัตรา 60 Hz การดำเนินการทั้งหมดจะต้องมีขนาดไม่เกิน CPU 16 มิลลิวินาที และเวลา GPU 16 มิลลิวินาทีสำหรับทุกเฟรม คุณมีทรัพยากร 2 อย่างที่ใช้ควบคู่กันไป และสามารถสลับงานเพื่อเพิ่มประสิทธิภาพสูงสุดได้ มุมมอง "เกี่ยวกับ:การติดตาม" ของ Chrome เป็นเครื่องมือที่มีประโยชน์มากในการดูข้อมูลเชิงลึกว่าโค้ดของคุณกำลังทำอะไรอยู่ และจะช่วยให้คุณประหยัดเวลาในการพัฒนาซอฟต์แวร์ได้สูงสุดโดยการจัดการปัญหาที่เหมาะสม

ขั้นตอนถัดไปคือ

นอกจาก GPU คุณยังติดตามส่วนอื่นๆ ของรันไทม์ของ Chrome ได้ด้วย Chrome Canary เป็น Chrome เวอร์ชันเริ่มต้น ซึ่งมีเครื่องมือในการติดตาม IO, IndexedDB และกิจกรรมอื่นๆ อีกมากมาย คุณควรอ่านบทความ Chromium นี้เพื่อทำความเข้าใจสถานะปัจจุบันของเหตุการณ์การติดตาม

หากคุณเป็นนักพัฒนาเกมบนเว็บ ให้ลองดูวิดีโอด้านล่างนี้ เอกสารนี้เป็นการนำเสนอจากทีมประสานงานนักพัฒนาซอฟต์แวร์เกมของ Google ที่ GDC 2012 เกี่ยวกับการเพิ่มประสิทธิภาพสำหรับเกมของ Chrome ดังต่อไปนี้