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

ลิลลี ทอมป์สัน
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 ของ GPU หรือไม่ ในแต่ละเฟรม คุณจะได้แสดงผลบางส่วนบน GPU และตรรกะบางอย่างบน CPU เพื่อให้ทราบว่าสิ่งใดที่ทำให้เกมทำงานช้าลง คุณจะต้องดูความสมดุลระหว่างการทำงานในทรัพยากรทั้งสอง

ขั้นแรก ให้ค้นหาบรรทัดในมุมมองการติดตามที่ชื่อว่า 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 ms เป็น 2320 ms ซึ่งหมายความว่าแต่ละเฟรมจะใช้เวลาประมาณ 50 ms (อัตราเฟรม 20 Hz) คุณจะเห็นชิ้นส่วนกล่องสีแทนฟังก์ชันแสดงผลข้างกล่องอัปเดต แต่เฟรมจะทำหน้าที่อัปเดตเองทั้งหมด

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

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

#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 มีดังนี้