יצירת פרופיל למשחק WebGL שלך באמצעות הדגל about:tracing

לילי תומפסון
לילי תומפסון

אם אי אפשר למדוד את הביצועים, לא ניתן לשפר אותו.

לורד קלווין

כדי שמשחקי ה-HTML5 שלכם יפעלו מהר יותר, עליכם לזהות תחילה צווארי בקבוק בביצועים, אבל זה יכול להיות קשה. הערכת הנתונים של פריימים לשנייה (FPS) היא התחלה טובה, אבל כדי לראות את התמונה המלאה, צריך להבין את הניואנסים בפעילויות של Chrome.

הכלי about:מעקב מספק את התובנות שעוזרות לך להימנע מפתרונות עקיפים מהירים המיועדים לשיפור הביצועים, אך למעשה מדובר בניחושים עם כוונה טובה. תוכלו לחסוך הרבה זמן ואנרגיה, לקבל תמונה ברורה יותר לגבי הפעולות ש-Chrome עושה עם כל פריים ולהשתמש במידע הזה כדי לבצע אופטימיזציה של המשחק.

שלום על:מעקב

הכלי'מידע על:מעקב' של Chrome מספק לך חלון זמנים לכל הפעילויות של Chrome בפרק זמן מסוים, ברמת פירוט כה גבוהה, עד שנראה שבהתחלה הוא מבלבל. רבות מהפונקציות ב-Chrome מיושמות במטרה לזהות את התוצאות מהקופסה, כך שמבלי לבצע אף כיבוש ידני, עדיין תוכלו להשתמש ב-about:ttracking כדי לעקוב אחר הביצועים שלכם. (ראו סעיף מאוחר יותר על אינסטרומנטציה ידנית של ה-JS)

כדי לראות את תצוגת המעקב, הקלד "about:tracing" בסרגל הכתובות של Chrome.

סרגל הכתובות ב-Chrome
מקלידים 'about:tracing' בסרגל הכתובות של Chrome

מכלי המעקב, אפשר להתחיל להקליט, להריץ את המשחק למשך כמה שניות ואז לצפות בנתוני המעקב. דוגמה לנתונים:

תוצאת מעקב פשוטה
תוצאת מעקב פשוטה

כן, זה מבלבל, בסדר. בואו נראה איך קוראים את זה.

כל שורה מייצגת תהליך שיוצר פרופיל, הציר השמאלי מציין זמן וכל תיבה צבעונית היא קריאה לפונקציה מתואמת. יש שורות לסוגים שונים של משאבים. הרכיבים המעניינים ביותר ליצירת פרופילים של משחקים הם CrGpuMain, שמראה מה עושה יחידת העיבוד הגרפי (GPU) ו-CrRendererMain. כל מעקב מכיל שורות CrRendererMain עבור כל כרטיסייה פתוחה במהלך תקופת המעקב (כולל הכרטיסייה about:ttracking)

בזמן קריאת נתוני מעקב, המשימה הראשונה היא לקבוע איזו שורה CrRendererMain מתאימה למשחק שלך.

תוצאת מעקב פשוטה מודגשת
תוצאת מעקב פשוטה מודגשת

בדוגמה הזו שני המועמדים הם: 2216 ו-6516. לצערנו אין כרגע דרך מלוטשת לבחירת האפליקציה שלך, מלבד חיפוש הקו שמבצע עדכונים תקופתיים רבים (או אם הגדרת ידנית קוד בנקודות מעקב, כדי לחפש את הקו שמכיל את נתוני המעקב שלך). בדוגמה הזו, נראה ש-6516 מפעיל לולאה ראשית מתדירות העדכונים. אם תסגרו את כל שאר הכרטיסיות לפני התחלת המעקב, יהיה לכם קל יותר למצוא את CrRendererMain הנכון. עם זאת, יכול להיות שעדיין יהיו שורות CrRendererMain עבור תהליכים אחרים, שהם לא המשחק שלך.

אנחנו מחפשים את המסגרת

אחרי שמוצאים את השורה הנכונה בכלי המעקב של המשחק, השלב הבא הוא למצוא את הלולאה הראשית. הלולאה הראשית נראית כמו דפוס חוזר בנתוני המעקב. ניתן לנווט בנתוני המעקב באמצעות המקשים W, A, S ו-D: A ו-D כדי לנוע שמאלה או ימינה (קדימה ואחורה בזמן) ו-W ו-S כדי להגדיל או להקטין את התצוגה של הנתונים. הלולאה הראשית צפויה להיות תבנית שחוזרת על עצמה כל 16 אלפיות השנייה, אם המשחק פועל ב-60Hz.

נראה כמו שלוש פריימים של ביצוע
נראה כמו שלושה פריימים של ביצוע

אחרי שתאתרו את פעימות הלב של המשחק, תוכלו להתעמק ולראות מה בדיוק הקוד עושה בכל פריים. כדי להגדיל את התצוגה, אפשר להשתמש באותיות W, A, S ו-D כדי לקרוא את הטקסט שבתיבות הפונקציות.

עמוק בתוך מסגרת ביצוע
מבט מעמיק על מסגרת ביצוע

אוסף התיבות מציג סדרה של קריאות פונקציה, כאשר כל קריאה מיוצגת על ידי תיבה צבעונית. כל פונקציה נקראה על ידי התיבה שמעליה, כך שבמקרה זה ניתן לראות את הערך MessageLoop::RunTask שנקרא RenderWidget::OnSwapBuffersComplete, אשר בתורו נקרא RenderWidget::DoDeferredUpdate, וכן הלאה. קריאת הנתונים האלה תאפשר לכם לקבל תצוגה מלאה של מה שנקרא, וכמה זמן נמשכה כל הפעלה.

אבל כאן זה נעשה נדבק קצת. המידע שנחשף על ידי about:ttracking הוא הקריאות לפונקציה הגולמית מקוד המקור של 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). כדי להבין מה מאט את המשחק, תצטרכו לראות עד כמה העבודה מאוזנת בין שני המשאבים.

תחילה, מאתרים את השורה בתצוגת המעקב שנקראת 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)

מה אפשר ללמוד מהמעקב הזה? ניתן לראות שקצב הפריימים של התמונה נע בין כ-2,270 אלפיות השנייה ל-2,320 אלפיות השנייה, כלומר כל פריים נמשך כ-50 אלפיות השנייה (קצב פריימים של 20Hz). אפשר לראות קטעים של תיבות צבעוניות שמייצגות את פונקציית העיבוד ליד תיבת העדכון, אבל המסגרת נשלטת לחלוטין על ידי העדכון עצמו.

בניגוד למה שקורה במעבד (CPU), ניתן לראות שה-GPU עדיין לא פעיל ברוב התמונות. כדי לבצע אופטימיזציה של הקוד, אפשר לחפש פעולות שאפשר לבצע בקוד של תוכנת הצללה (shader) ולהעביר אותן ל-GPU ולנצל את המשאבים בצורה הטובה ביותר.

מה קורה כשהקוד של תוכנת ההצללה (shader) עצמו איטי וה-GPU עמוס מדי? מה קורה אם נסיר את העבודה המיותרת מהמעבד (CPU) ובמקום זאת נוסיף קצת עבודה בקוד של שרת ההצללה במקטע. הנה תוכנת הצללה בקטעים יקרים שלא לצורך:

#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 איטי

שוב, חשוב לציין את משך הזמן של מסגרת. במקרה הזה, הדפוס החוזר עובר מ-2,750 אלפיות השנייה ל-2,950 אלפיות השנייה, משך של 200 אלפיות השנייה (קצב פריימים של כ-5Hz). הקו CrRendererMain כמעט ריק. המשמעות היא שהמעבד לא פעיל רוב הזמן, כאשר ה-GPU עמוס. זה סימן לכך שהצללות כבדות מדי.

אם לא יכולת להבין בדיוק מה גורם לקצב הפריימים הנמוך, ניתן לראות את העדכון של ה-5 הרץ ולהתפתות להיכנס לקוד המשחק ולהתחיל לנסות לבצע אופטימיזציה או להסיר את הלוגיקה של המשחק. במקרה הזה, לגמרי לא כדאי לעשות זאת, כי הלוגיקה ב-Game Loop היא לא מה שגוזל זמן. למעשה, המעקב הזה מצביע על כך ששימוש נוסף במעבד (CPU) בכל פריים יהיה 'חינם', כי המעבד (CPU) נמצא במצב לא פעיל, כך שזמן עבודה רב יותר לא ישפיע על משך העבודה.

דוגמאות אמיתיות

עכשיו נראה איך נראים נתוני מעקב ממשחק אמיתי. אחד הדברים המגניבים במשחקים שנוצרו באמצעות טכנולוגיות אינטרנט פתוחות הוא האפשרות לראות מה קורה במוצרים האהובים עליכם. אם תרצו לנסות כלים ליצירת פרופילים, תוכלו לבחור את כותרת ה-WebGL המועדפת עליכם בחנות האינטרנט של Chrome ולהציג אותה בפרופיל about:tracy. זהו עקבות לדוגמה שנלקחו ממשחק WebGL Skid Racer המעולה.

מעקב אחרי משחק אמיתי
מעקב אחר משחק אמיתי

נראה שכל פריים נמשך כ-20 אלפיות השנייה, כלומר קצב הפריימים הוא בערך 50 FPS. אפשר לראות שהעבודה מאוזנת בין המעבד (CPU) לבין ה-GPU, אבל ה-GPU הוא המשאב בעל הביקוש הגבוה ביותר. אם תרצו לראות איך נראית פרופיל דוגמאות אמיתיות של משחקי WebGL, נסו לשחק עם כמה מהכותרים בחנות האינטרנט של Chrome שנבנו באמצעות WebGL, כולל:

סיכום

אם אתם רוצים שהמשחק יפעל במהירות של 60Hz, כל הפעולות בכל פריים צריכות להתאים ל-16 אלפיות השנייה של המעבד (CPU) ול-16 אלפיות השנייה של ה-GPU. יש לכם שני משאבים שאפשר להשתמש בהם במקביל, ותוכלו להחליף ביניהם את העבודה כדי למקסם את הביצועים. תצוגת about:ttracking של Chrome היא כלי רב-ערך לקבלת תובנות לגבי מה שהקוד שלך עושה בפועל, והיא תעזור לך להאריך את זמן הפיתוח על ידי טיפול בבעיות הנכונות.

מה השלב הבא?

מלבד GPU, תוכלו גם לעקוב אחרי חלקים אחרים של זמן הריצה של Chrome. Chrome Canary, גרסת השלב המוקדם של Chrome, מיושם כדי לעקוב אחר IO, IndexedDB ועוד כמה פעילויות. כדאי לקרוא את המאמר הזה ב-Chromium כדי להבין יותר לעומק את המצב הנוכחי של מעקב אחר אירועים.

אם אתם מפתחים של משחקי אינטרנט, מומלץ לצפות בסרטון שבהמשך. זוהי מצגת מאת צוות התמיכה למפתחי משחקים של Google ב-GDC 2012 בנושא אופטימיזציה של הביצועים במשחקי Chrome: