ארכיטקטורת GPU מוסברת בפשטות - מה יש בתוך הקופסה הזאת¶
אנשים משתמשים במילה GPU כאילו זה בלוק מונוליטי אחד גדול שסתם "מהיר". בפועל, GPU הוא מבנה היררכי מסודר להפליא, כמעט כמו עיר שלמה עם מבנה ארגוני ברור. ברגע שמבינים את המבנה הזה, גם קוד CUDA וגם דיבורים על ביצועים מתחילים להיות הגיוניים בהרבה.
תחשבו על זה כמו מפעל ענק¶
הדרך הכי טובה להבין ארכיטקטורת GPU היא אנלוגיה למפעל תעשייתי גדול. יש למפעל כמה מבנים, לכל מבנה כמה קווי ייצור, ולכל קו ייצור עובדים עם כלים שונים. ב-GPU זה בדיוק אותו הגיון, רק שהשמות טכניים ומוזרים.
GPC ו-TPC - המבנים והמחלקות¶
בראש הפירמידה נמצא ה-GPC, ראשי תיבות של Graphics Processing Cluster. תחשבו עליו כמו על מבנה שלם במפעל, עם המנוף העצמאי שלו ותשתית משלו. בתוך כל GPC יושבים כמה TPC, יחידות עיבוד קטנות יותר, שהן בעצם המחלקות בתוך המבנה. GPU חדש ומודרני יכול להכיל מספר GPC, וכל אחד מהם מכיל כמה TPC. זו רמת הארגון הכי גבוהה, וברוב היום יום של כתיבת קוד לא באמת נוגעים בה ישירות, אבל היא זו שקובעת כמה כוח עיבוד כולל יש לכרטיס.
ה-SM - קו הייצור עצמו¶
הרכיב האמיתי שחשוב להכיר הוא ה-SM, ראשי תיבות של Streaming Multiprocessor. זהו קו הייצור עצמו, היחידה שבפועל מבצעת את החישובים. כל SM מכיל בתוכו את כל מה שצריך כדי להריץ עבודה - ליבות עיבוד, יחידת תזמון, קבצי רגיסטרים, וזיכרון מהיר משלו.
בתוך כל SM יושבות ליבות ה-CUDA cores, שהן הפועלים הפשוטים שמבצעים את החישובים המתמטיים הבסיסיים - חיבור, כפל, פעולות על מספרים עשרוניים ושלמים. לצידן יש SFU, יחידות פונקציה מיוחדות שמתמחות בפעולות מורכבות יותר כמו סינוס וקוסינוס, ו-LSU, יחידות טעינה ואחסון שאחראיות על תנועת נתונים מהזיכרון ואליו.
בשנים האחרונות נוספו לכל SM גם Tensor Cores, ליבות מיוחדות שתוכננו במיוחד לביצוע כפל מטריצות במהירות מטורפת, בדיוק סוג הפעולה שרשתות נוירונים עמוסות בה. אלה הרכיבים שהפכו את NVIDIA לשחקנית מרכזית כל כך בעולם הבינה המלאכותית.
ה-Warp Scheduler - מנהל העבודה¶
בתוך כל SM יושב גם ה-Warp Scheduler, שהוא בעצם מנהל המשמרת. הוא מחליט אילו קבוצות של threads, שנקראות warp ומכילות 32 threads בכל פעם, מקבלות לרוץ בכל רגע נתון על הליבות הפנויות. הרעיון המבריק כאן הוא שבזמן ש-warp אחד מחכה לנתונים מהזיכרון, שהוא לרוב תהליך איטי, המתזמן פשוט מעביר את הליבות ל-warp אחר שמוכן לרוץ. כך ה-SM נשאר עמוס כמעט כל הזמן, במקום לשבת ולחכות.
איך זה מתקשר לכתיבת קוד¶
כשאתם כותבים קוד CUDA, אתם למעשה לא כותבים ישירות "תריצו על SM מספר 3". אתם מגדירים grid של blocks, ואת ה-blocks האלה ה-GPU מפזר בעצמו על פני ה-SM הפנויים. כמה blocks יכולים לרוץ בו זמנית על SM אחד תלוי במשאבים שהם צורכים - רגיסטרים וזיכרון משותף - וזה בדיוק המקום שבו נכנס הנושא של occupancy, מדד ליעילות השימוש במשאבי ה-SM.
למה חשוב להכיר את זה בכלל¶
ההבנה הזו לא אקדמית בלבד. ברגע שאתם יודעים שה-SM הוא היחידה שבאמת מריצה עבודה, ושמשאבים כמו רגיסטרים וזיכרון משותף מוגבלים בתוכו, כל החלטת אופטימיזציה הופכת ברורה בהרבה. למה קוד מסוים איטי? כי הוא לא מנצל מספיק warp כדי להסתיר עיכובי זיכרון. למה הוספת עוד threads לא תמיד עוזרת? כי אולי כל ה-SM כבר עמוסים ואין עוד מקום.
זה בדיוק ההיגיון שאנחנו בונים לעומק בקורס תכנות GPU, מתחילים מארכיטקטורת החומרה בדיוק כמו שתיארתי כאן, וממשיכים עד לרמה שבה אתם קוראים דוחות פרופיילינג ומבינים בדיוק למה קרנל מסוים לא מנצל את החומרה במלואה.
לסיכום¶
GPU הוא לא קופסה קסומה, הוא מבנה היררכי הגיוני - GPC למעלה, SM באמצע כמנוע העבודה האמיתי, וליבות CUDA, Tensor Cores ו-warp scheduler בפנים. ברגע שהמפה הזו נכנסת לראש, גם כתיבת קוד וגם קריאת ביצועים הופכות למשחק הרבה יותר ברור.
בואו תמשיכו לצלול פנימה עם קהילה שכבר שם.