1 אופטימיזציה של קוד ASU פרק 10
2 2 מה זה אופטימיזציה? שיפור ביצועי התוכנית. בניגוד למה שמשתמע מהשם, בדרך-כלל לא מגיעים לאופטימום.
3 3 אופצימיזציה של...? האופטימיזציה הנפוצה ביותר: אופטימיזציה של זמן ריצה. אפשרויות נוספות: אופטימיזציה של גודל הקוד. אופטימיזציה של צריכת זיכרון. אופטימיזציה של צריכת חשמל.
4 4 אופטימיזציה של זמן ריצה ניתן לקצר זמן ריצה של תוכנית בדרכים רבות מאוד לעיתים, קוד מהיר יותר הוא דווקא קוד ארוך יותר אופטימיזציה טובה דורשת היכרות עמוקה עם: המעבד עליו רצה התוכנית מערכת ההפעלה אופי ריצת התוכנית (מידע שלא תמיד זמין!) דוגמא: מיקום סמוך של פרוצדורות עם coupling גבוה
5 5 ייצוג החישוב של בלוק בסיסי בעזרת DAG עלים – משתנים (שונים) או קבועים (שונים) צמתים פנימיים מסומנים על ידי האופרטורים המתאימים לצמתים נצמיד שמות משתנים על פי התקדמות החישוב t 1 := 4 * i t 2 := a [ t 1 ] t 3 := 4 * i t 4 := b [ t 3 ] t 5 := t 2 * t 4 t 6 := prod + t 5 prod := t 6 t 7 := i + 1 i := t 7 if i <= 20 goto (1) (1) 1i0i0 4ba 20t 7, i+t1, t3t1, t3 * (1)<=t4t4 [ ]t2t2 t5t5 *prod 0 t 6, prod+
6 6 בנית ה- DAG מטפלים בכל משפט בבלוק x := y + z מוצאים איפה נמצא הערך הנוכחי של y ו- z בונים צומת חדש המסומן +ומחברים אותו לשני הבנים (אם לא קיים כזה); מסמנים אותו ב- x אם x (לאx 0 ) כבר מסומן, יש לבטל את הסימון הקודם אין יוצרים צומת חדש עבור משפטי השמה פשוטים x := y
7 7 ייצוג בלוקים בסיסיים כ- DAGs עלים – משתנים (שונים) או קבועים (שונים) צמתים פנימיים מסומנים על ידי האופרטורים המתאימים לצמתים נצמיד שמות משתנים על פי התקדמות החישוב t 1 := 4 * i t 2 := a [ t 1 ] t 3 := 4 * i t 4 := b [ t 3 ] t 5 := t 2 * t 4 t 6 := prod + t 5 prod := t 6 t 7 := i + 1 i := t 7 if i <= 20 goto (1) (1) 1i0i0 4ba 20t 7, i+t1, t3t1, t3 * (1)<=t4t4 [ ]t2t2 t5t5 *prod 0 t 6, prod+ t1t1 prod := prod + t 5 i := i + 1
8 8 שימושים של DAGs כייצוג של בלוקים בסיסיים זיהוי אוטומטי של ביטויים משותפים זיהוי המשתנים בהם נעשה שימוש בבלוק זיהוי הפקודות בהן חושבו ערכים בעלי שימוש בסוף הבלוק ייצור קוד יעיל (בפרט – אין צורך בהשמות) זיהוי המשתנים החיים סדר חישוב קביל – באמצעות מיון טופולוגי
9 9 side effects הקושי – aliasing הפתרון – השמה לאיבר של מערך מבטלת את האפשרות להשתמש בצמתים המכילים התייחסות אליו הערה – בעיה דומה נגרמת על ידי מצביעים הערה – בעיה דומה נגרמת על ידי פרוצדורות נושא ה- aliasing הוא מכשול מרכזי לאופטימיזציה של תוכניות x := a [ i ] a [ j ] := y z := x x := a [ i ] a [ j ] := y z := a [ i ]
10 שיטות אופטימיזציה בשקפים הבאים נסקור כמה שיטות אופטימיזציה שונות. הדגש כאן הוא על אופטימיזציה של ביצועים. חלק מהשיטות כלליות ומתאימות לכל מעבד כעקרון, כל מה שחוסך ביצוע חישובים – תמיד עוזר. חלק מהשיטות רלוונטיות רק למעבדים מסוימים. למשל, החלפת כפל בחיבור: במעבדים רבים חישובי חיבור הם מהירים יותר. חלק מהשיטות תראינה לא משמעותיות בפני עצמן – אבל השילוב של כמה מהן יחדיו הופך אפקטיבי מאוד.
11 ביטול ביטויים משותפים ראינו כיצד ניתן לאתר ביטויים משותפים ב-basic block נתון ולחסוך חישובים חוזרים. על-ידי ביצוע DFA ניתן למצוא גם ביטויים כאלה החוצים את גבולות הבלוק היחיד.
12 Copy propagation אם בנקודה נתונה יש השמה, a:=b, ננסה בהמשך להשתמש ב-b בכל מקום בו יש שימוש ב-a. תוצאה אפשרית: a הופך להיות חסר שימוש (משתנה מת) וניתן לחסוך את ההשמה.
13 Code motion מזהים חישוב המתבצע באופן חוזר בתוך לולאה. מוודאים שהמקורות המשמשים לחישוב אינם משתנים בתוך הלולאה. מוציאים את החישוב אל מחוץ ללולאה. while (x – 3 < y) { // … instructions that do not change x } ↓ t 1 = x – 3; while (t 1 < y) { // … instructions that do not change x or t 1 }
14 Induction variables and Strength Reduction זיהוי משתני המונה של לולאה, וזיהוי הקשר שלהם למשתנים אחרים. הסרת תלות במשתני המונה, במידת האפשר. (1) i = 0; (2) t 1 = i * 4; (3) t 2 = a[t 1 ] (4) if (t 2 > 100) goto (19) (5) … … (17) i = i + 1 (18) goto (2) (19) … מדוע קוד מסוג זה (כולל ההכפלה ב-4) הוא מאוד נפוץ? → t 1 = t כמובן שיש לאתחל את t 1 מחוץ ללולאה אבל זה לא רק SR! הסרנו את התלות של t 1 ב-i כלומר, שורות (1) ו- (17) כעת מיותרות! חיבור מהיר יותר מכפל במעבדים רבים (strength reduction)
15 שיטה בסיסית: peephole optimization בוחנים את הקוד ב"חלון" צר. מתבוננים ב"חלון קטן" לתוך הקוד ומנסים לשפר את קטע הקוד בתוך החלון על פי רוב מפעילים את השיטה בצורה איטרטיבית מאתרים פקודות שברור שניתן לבטל, בשל רצף הפקודות שמיד לפניהן או אחריהן. יש גם פקודות שניתן לבטל בפני עצמן, ללא תלות בסביבה. למשל: x := x * 1 a := a + 0
16 peephole optimizations פישוט של חישובים אלגבריים: x := x ^ 2 → x := x * x x := x * 8 → x := x << 3 ארגון מחדש של קוד : (1) if x := 1 goto (3) (2) goto (19) (3) … ↓ (1) if x 1 goto (19) (2) …
17 peephole optimizations ביטול שורות מיותרות: (1) a := x (2) x := a (3) a := someFunction(a); (4) x := someOtherFunction(a, x); (5) if a > x goto (2) מבצעים peephole רק בגבולות basic block. זהירות!
18 Data Flow Analysis שיטות אופטימיזציה רבות מסתמכות על data flow analysis (או DFA). למעשה, חישוב ה-live variables שראינו (בתוך basic block) הוא מקרה פשוט של DFA. חישובי DFA על גרף (למשל, של basic blocks) מאפשרים למצוא את המקור האפשרי לערכים (או טיפוסים) עבור כל משתנה בכל נקודה בתוכנית. DFA משמש לא רק לאופטימיזציות, אלא גם להוכחות נכוֹנוּת של תוכניות, ועוד.
19 DFA – האלגוריתם הכללי המבנה הכללי של כל אלגוריתם DFA הוא: N 1 …N n – the program nodes (could be variables, basic blocks, etc.) for i in {1…n}: initialize N i bool change = true; while (change) { change = false; for i in {1…n}: M = new value for N i if (M N i ) then change = true; N i = M }
20 DFA – דוגמה לאלגוריתם ספציפי שימושים ספציפיים במבנה של DFA נבדלים זה מזה באתחול של N ובאופן החישוב של N בכל שלב. למשל: חישוב המקורות האפשריים לערך של משתנה. כל N i:A הוא קבוצה, המייצגת את כל המקורות האפשריים של משתנה A בשורה i. (יש N i נפרד עבור כל משתנה). אתחול: אם בשורה i יש השמה של קבוע, חישוב, או פונקציה למשתנה A, (כלומר, כל השמה שאינה העתקה, A=B) אזי: N i:A = {i} אחרת, N i:A = צעד: אם בשורה i לא מעדכנים את A, אזי N i:A = N x:A N y:A N z:A … כאשר x, y, z וכו' הן כל השורות שיש מעבר ישיר מהן אל שורה i. אם בשורה i יש העתקה, A=B, אזי N i:A = N i:B.
21 חישוב מקורות - דוגמה (1) if (b == 4) goto (4) (2) a = 5 (3) goto 5 (4) a = 3 (5) if (a > 4) goto 4 (6) c = a n i:a n i:c {2} {4} n i:a n i:c {2} {4} {2,4} {2,4} n i:a n i:c {2} {4} {2,4} {2,4}
22 שימושים אחרים ל-DFA ערכים קבועים אפשריים למשתנה בנקודה נתונה זיהוי שימוש במשתנה שלא אותחל int i; if (…) i = 3; x = i; ← error: i might not have been initialized ב- OOP: זיהוי downcast בלתי-אפשרי ועוד...