לדלג לתוכן

מודל Roofline מוסבר בפשטות - איך יודעים על מה בכלל לעבוד

אחת הטעויות הכי נפוצות באופטימיזציית קוד GPU היא לנחש. מישהו רואה שקוד איטי, מחליט "בטח יש יותר מדי threads", מנסה לשנות את זה, לא עוזר, מנסה משהו אחר. שעות של ניחושים. מודל ה-Roofline נולד בדיוק כדי לפתור את הבעיה הזו - הוא נותן לכם תשובה מספרית וברורה לשאלה הכי חשובה באופטימיזציה - מה בכלל מגביל אתכם.

הבעיה שהמודל פותר

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

איך בונים את הגרף

תארו לעצמכם גרף עם ציר X וציר Y. ציר ה-Y הוא ביצועים בפועל, כמה פעולות נקודה צפה אתם מבצעים בשנייה, נמדד ב-FLOPS. ציר ה-X הוא מדד שנקרא arithmetic intensity, שהוא בעצם היחס בין כמות החישוב שאתם מבצעים לכמות הנתונים שאתם צריכים להביא מהזיכרון בשביל לבצע אותו - כלומר, כמה פעולות חישוב אתם "סוחטים" מכל בית שהבאתם מהזיכרון.

עכשיו מציירים על הגרף הזה שני קווים שיוצרים צורה של גג משופע, ומכאן השם. קו אחד אופקי, בגובה השיא התיאורטי של כוח החישוב של ה-GPU שלכם. קו שני אלכסוני, שמייצג את רוחב הפס המקסימלי של הזיכרון, כלומר כמה נתונים ה-GPU יכול להעביר בשנייה. שני הקווים האלה נפגשים בנקודה שנקראת ridge point.

מה הגרף בעצם אומר לכם

עכשיו לוקחים את הקרנל שלכם, מחשבים את ה-arithmetic intensity שלו, ומסמנים אותו על הגרף. אם הנקודה שלכם נופלת מתחת לקו האלכסוני, כלומר משמאל ל-ridge point, אתם memory-bound - הצוואר בקבוק שלכם הוא רוחב פס הזיכרון, ואין שום טעם לייעל את החישוב עצמו כי ה-GPU ממילא מחכה לנתונים. אם הנקודה שלכם נמצאת מימין ל-ridge point, אתם compute-bound - יש לכם מספיק נתונים ביחס לחישוב, וה-GPU עסוק לגמרי בחישוב עצמו, אז אופטימיזציה של תזוזת זיכרון לא תעזור.

זה בדיוק הכוח של המודל - הוא הופך שאלה מעורפלת ל"למה זה איטי" לתשובה קונקרטית - "אתם memory-bound, תתמקדו בקוואלסינג של גישות זיכרון ובשימוש בזיכרון משותף" או "אתם compute-bound, תתמקדו בהפחתת פעולות מיותרות ובשימוש טוב יותר ב-Tensor Cores".

דוגמה שממחישה את זה

חיבור שני וקטורים גדולים הוא הדוגמה הקלאסית ל-memory-bound - על כל שתי קריאות מהזיכרון אתם מבצעים חיבור בודד, פעולה אחת בלבד. לעומת זאת, כפל מטריצות גדולות הוא compute-bound מטבעו, כי כל איבר בזיכרון משמש לחישוב הרבה תוצאות שונות. זו הסיבה שספריות כמו cuBLAS משקיעות כל כך הרבה מאמץ בלנצל מחדש נתונים שכבר נמצאים בזיכרון המהיר, ולא לגשת שוב ושוב לזיכרון הראשי האיטי.

למה זה חשוב יותר ממה שחושבים

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

זה בדיוק הסוג של כלי חשיבה שאנחנו בונים לעומק בפרק על תיאוריית הביצועים בקורס תכנות GPU, יחד עם דוגמאות מספריות אמיתיות וכלי פרופיילינג שמראים לכם איפה בדיוק אתם עומדים על הגרף.

לסיכום

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

בואו תלמדו לזהות את זה בעצמכם, יחד עם קהילה שכבר עוברת את זה.

הצטרפו לקהילה בדיסקורד