שיעור 27: כפל מטריצות עם tiling ב-shared memory
כפל מטריצות C = A * B מחשב כל איבר C[row][col] כסכום של מכפלות לאורך ממד K: C[row][col] = סכום על k של A[row][k] * B[k][col]. בגרסה הנאיבית, כל thread שאחראי על איבר אחד של C קורא שורה שלמה מ-A ועמודה שלמה מ-B ישירות מהזיכרון הגלובלי (global memory) — האיטי ביותר. הבעיה: אותם איברים של A ושל B נקראי
דמיין שאתה מרכיב מנה ושוב ושוב רץ למחסן הרחוק להביא בדיוק את אותם מצרכים. במקום זה, אתה מביא ארגז שלם פעם אחת למטבח (המדף הקרוב), וכל הטבחים מושכים ממנו במהירות. ה-tiling הוא בדיוק זה: מביאים אריח נתונים פעם אחת ל-shared memory הקרוב, ושם משתמשים בו שוב ושוב.
- כפל מטריצות עם tiling
- אלגוריתם כפל מטריצות שטוען אריחים של A ו-B ל-shared memory, מסנכרן, וצובר משם — חוסך קריאות מהזיכרון הגלובלי.
- אריח (tile)
- תת-בלוק בגודל TILE x TILE של המטריצה, שנטען בבת אחת ל-shared memory ומשמש את כל ה-threads ב-block.
- ניצול חוזר ב-shared
- כל איבר שנטען ל-shared memory נקרא על-ידי TILE threads שונים, כך שקריאה גלובלית אחת משרתת מכפלות רבות.
- ממד K
- הממד המשותף בכפל: A הוא M x K ו-B הוא K x N. הסכום על k רץ לאורך K ומחושב אריח-אריח.