41
1 תתתתתתתתתתתת תתתתתתתתתת

אופטימיזציות קומפיילרים

Embed Size (px)

DESCRIPTION

אופטימיזציות קומפיילרים. Delayed branch slots. אם ניזכר במכונת ה- MIPS pipeline (in-order) , הרי שהכרעת פקודות הסיעוף התבצעה בשלב ה- MEM , ולכל פקודת סיעוף כזו ישנם 3 מ"ש אחריה אשר בהם איננו יודעים בוודאות אילו פקודות עלינו להכניס. - PowerPoint PPT Presentation

Citation preview

Page 1: אופטימיזציות קומפיילרים

1

אופטימיזציות קומפיילרים

Page 2: אופטימיזציות קומפיילרים

2

Delayed branch slots

, MIPS pipeline (in-order)אם ניזכר במכונת ה-•הרי שהכרעת פקודות הסיעוף התבצעה בשלב

מ"ש 3, ולכל פקודת סיעוף כזו ישנם MEMה-אחריה אשר בהם איננו יודעים בוודאות אילו

פקודות עלינו להכניס.הפתרון של המכונה עבור בעיה זו הוא לנסות •

ולפעול branchלהמר מה תהיה תוצאת ה-בהתאם.

Page 3: אופטימיזציות קומפיילרים

3

הקומפיילר יכול להציע לנו פתרון אחר:•).slots תאים (3אחרי כל פקודת סיעוף לשים –לעבור על הקוד ולחפש פקודות שיבוצעו בכל מקרה ועצם –

מיקומם באחד התאים לא יפגע בנכונות התוכנית.nopתאים שיוותרו ריקים יוחלפו בפקודת –

במקרה כזה אין צורך בשום מנגנון חיזוי או טיפול מיוחד •.branchבפקודות

יש לו 1 או 2 תאים יהיה קשה לקומפיילר למלא אבל 3•סיכוי טוב יותר.

נקבל איפה שאין לעולם טעויות חיזוי, ואין תשלום •penalty-על פקודת ה branch-למעט ה) slots שלא

הצלחנו למלא).

Page 4: אופטימיזציות קומפיילרים

4

דוגמאללא כל מנגנון טיפול בהוראות סיעוף (כלומר ) כפי שנלמד בכיתה (MIPSנתון מעבד

המעבד ממשיך להזרים קוד בכל מקרה). לשם שמירה על נכונות, נעזר המעבד . BRANCHעבור הוראות ) nopבקומפיילר ליצירת בועות (הוראות

וסדר אותו כך שמספר nopהוסף לקוד הוראות , nopלפניך קטע קוד ללא הוראות ה-הבועות יהיה קטן ככל האפשר.

על הקוד החדש לשמור על נכונות התוכנית. (ניתן, ואף רצוי, להשתמש בשיטת ה- delayed branch slots( הנח שאין קפיצות משום מקום אחר אל תוך קטע הקוד ,

הבא.

L2 ADDI R1, R22, 4ADDI R20, R20, 5SW R4, 50(R15)LW R2, 100(R20)ADD R3, R1, R2BEQ R1, R2, L1ADDI R10, R10, 1

L1 ADDI R7, R9, 2SUBI R8, R10, 1BEQ R7, R8, L2ADDI R1, R22, 4ADD R22, R22, R3ADDI R23, R0, 100

Page 5: אופטימיזציות קומפיילרים

5

פתרוןOptimized Code

ADDI R1, R22, 4L2 ADDI R20, R20, 5

SW R4, 50(R15)LW R2, 100(R20)BEQ R1, R2, L1ADD R3, R1, R2 ADDI R7, R9, 2NOPADDI R10, R10, 1

L1 SUBI R8, R10, 1BEQ R7, R8, L2ADDI R1, R22, 4ADDI R23, R0, 100NOPADD R22, R22, R3

Original code

L2 ADDI R1, R22, 4ADDI R20, R20, 5SW R4, 50(R15)LW R2, 100(R20)ADD R3, R1, R2BEQ R1, R2, L1

ADDI R10, R10, 1L1 ADDI R7, R9, 2

SUBI R8, R10, 1BEQ R7, R8, L2ADDI R1, R22, 4ADD R22, R22, R3

ADDI R23, R0, 100

ADD R3, R1, R2 ADDI R7, R9, 2NOP

ADDI R1, R22, 4ADDI R23, R0, 100NOP

Page 6: אופטימיזציות קומפיילרים

6

דרכים למלא תאי הסתעפותOptimized Code

ADDI R1, R22, 4L2 ADDI R20, R20, 5

SW R4, 50(R15)LW R2, 100(R20)BEQ R1, R2, L1ADD R3, R1, R2 ADDI R7, R9, 2NOPADDI R10, R10, 1

L1 SUBI R8, R10, 1BEQ R7, R8, L2ADDI R1, R22, 4ADDI R23, R0, 100NOPADD R22, R22, R3

Original code

L2 ADDI R1, R22, 4ADDI R20, R20, 5SW R4, 50(R15)LW R2, 100(R20)ADD R3, R1, R2BEQ R1, R2, L1

ADDI R10, R10, 1L1 ADDI R7, R9, 2

SUBI R8, R10, 1BEQ R7, R8, L2ADDI R1, R22, 4ADD R22, R22, R3

ADDI R23, R0, 100

ADD R3, R1, R2 ADDI R7, R9, 2NOP

ADDI R1, R22, 4ADDI R23, R0, 100NOP

מלפני הקפיצה

מההמשך המשותף

פקודה זהה בשני

הסעיפים

פקודה שלא מפרה נכונות

Page 7: אופטימיזציות קומפיילרים

7

Basic pipeline scheduling

לצורך הדוגמאות הבאות, נניח שאנו עובדים עם מעבד אחר • שלבים ללא כל מנגנון חיזוי, וכן 5 בן pipeline in-orderעם

(מספר מחזורי שעון שממתינים עד הפקודה latencyנניח הבאה) כדלקמן:

פק' מייצרת התוצאה פק' משתמשת בתוצאה

latencyבמ"ש

Branch 1

FP ALU op Another FP ALU op 3

FP ALU op Branch 1

FP ALU op Store double 2

Load double FP ALU op 1

Load double Store double 0

Page 8: אופטימיזציות קומפיילרים

8

דוגמא

נתבונן בקטע הקוד הבא:•

for (i=1000; i>0; i--)

x[i] = x[i] + s;

תוך הנחה ש:MIPSנתרגם לאסמבלי של •–1R) מאותחל לכתובת האלמנט האחרון במערך x[1000](–2F מכיל את הערך של s–2R מאותחל לכתובת של x[0]

Page 9: אופטימיזציות קומפיילרים

9

תרגום:R1 &x[1000]

F2 s

R2 &x[0]

Loop: LD F0,0(R1)

ADD F4,F0,F2

SD F4,0(R1)

ADDI R1,R1,#-8 (DW=8 bytes)

BNE R1,R2,Loop

for (i=1000; i>0; i--)x[i] = x[i] + s;

Page 10: אופטימיזציות קומפיילרים

10

נראה כיצד תיראה באמת התוכנית):stalls (כולל ה-

מ"שR1 &x[1000]F2 sR2 &x[0]

Loop: LD F0,0(R1) 1stall 2ADD F4,F0,F2 3stall 4stall 5SD F4,0(R1) 6ADDI R1,R1,# -8 7stall 8BNE R1,R2,Loop 9stall 10

פק' מייצרת התוצאה

פק' משתמשת בתוצאה

latency במ"ש

Branch 1

FP ALU op Another FP ALU op 3

FP ALU op Branch 1

FP ALU op Store double 2

Load double FP ALU op 1

Load double Store double 0

Page 11: אופטימיזציות קומפיילרים

11

אבל אם נתזמן ...אחרת

Loop: LD F0,0(R1)ADDI R1,R1,#-8ADD F4,F0,F2 stallBNE R1,R2,LoopSD F4,8(R1) פק' הסיעוף מבוצע תמיד לאחר //

10 מ"ש במקום 6נקבל כל איטרציה ב-•

R1 &x[1000]F2 sR2 &x[0]

Loop: LD F0,0(R1)stallADD F4,F0,F2stallstallSD F4,0(R1)ADDI R1,R1,# -8stallBNE R1,R2,Loopstall

פק' מייצרת התוצאה

פק' משתמשת בתוצאה

latency במ"ש

Branch 1

FP ALU op Another FP ALU op 3

FP ALU op Branch 1

FP ALU op Store double 2

Load double FP ALU op 1

Load double Store double 0

Page 12: אופטימיזציות קומפיילרים

12

Loop unrolling

באמת מהווים את 6 מ"ש מתוך ה-3נשים לב שרק •).ADD וה-LD, SDזמן העבודה של האיטרציה (

המ"ש הם עדכון המונה, פקודת הסיעוף 3שאר • שנכפה עלינו.stallוה-

אם נפרוש את הלולאה כך שהיא תתבצע פחות •פעמים ובכל פעם תבצע כמה איטרציות אולי נוכל

לצמצם מספר זה.

Page 13: אופטימיזציות קומפיילרים

13

איטרציות4למשל אם נפרוש

R1 &x[1000]F2 sR2 &x[0]

Loop: LD F0,0(R1)ADD F4,F0,F2SD F4,0(R1)LD F6,-8(R1)ADD F8,F6,F2SD F8,-8(R1)LD F10,-16(R1)ADD F12,F10,F2SD F12,-16(R1)LD F14,-24(R1)ADD F16,F14,F2SD F16,-24(R1)ADDI R1,R1,# -32BNE R1,R2,Loop

)stalls( ללא התייחסות ל-

פק' מייצרת התוצאה

פק' משתמשת בתוצאה

latency במ"ש

Branch 1

FP ALU op Another FP ALU op 3

FP ALU op Branch 1

FP ALU op Store double 2

Load double FP ALU op 1

Load double Store double 0

Page 14: אופטימיזציות קומפיילרים

14

הסבר

ואת הקטנות המונה הפנימיות.branchהסרנו את הוראות ה-•

במידה ומספר האיטרציות לא מתחלק בצורה יפה, נחזיק גם •לולאה של איטרציות בודדות ואת השארית נריץ שם.

LD עבור כל stalls:1עדיין נקבל •ADD עבור כל 2ADDI עבור ה- 1branch עבור ה-1

מ"ש לאיטרציה (ישנה)7 פקודות לכן נקבל 14 יש stallsחוץ מה- ••)see next slide(

Page 15: אופטימיזציות קומפיילרים

15

נבצע אופטימיזציות

Loop: LD F0,0(R1)LD F6,-8(R1)LD F10,-16(R1)LD F14,-24(R1)ADD F4,F0,F2ADD F8,F6,F2ADD F12,F10,F2ADD F16,F14,F2SD F4,0(R1)SD F8,-8(R1)ADDI R1,R1,# -32stallstallSD F12,16(R1) (16-32=-

16)BNE R1,R2,LoopSD F16,8(R1)(8-32=-24)

Loop:LD F0,0(R1)StallADD F4,F0,F2Stall*2SD F4,0(R1)LD F6,-8(R1)StallADD F8,F6,F2Stall*2SD F8,-8(R1)LD F10,-

16(R1)StallADD

F12,F10,F2Stall*2SD F12,-

16(R1)LD F14,-

24(R1)StallADD

F16,F14,F2Stall*2SD F16,-

24(R1)ADDI R1,R1,# -

32StallBNE

R1,R2,LoopStall

פק' מייצרת התוצאה

פק' משתמשת בתוצאה

latency במ"ש

Branch 1

FP ALU op Another FP ALU op 3

FP ALU op Branch 1

FP ALU op Store double 2

Load double FP ALU op 1

Load double Store double 0

Page 16: אופטימיזציות קומפיילרים

16

?מה קיבלנו

כך שכל stallsקיבלנו אפוא קוד עם פחות • מ"ש.16איטרציה מתבצעת בו ב-

!!!4זה אומר שכל איטרציה ישנה מתבצעת ב-•

החסרון: צריכת האוגרים•

Page 17: אופטימיזציות קומפיילרים

17

Software pipelining

של תלויותstallsשיטה אחרת להיפטר מ-• פעמים:3ראשית נפרוש את גוף הלולאה •

Iteration i: LD F0,16(R1)

ADD F4,F0,F2

SD F4,16(R1)

Iteration i+1: LD F0,8(R1)

ADD F4,F0,F2

SD F4,8(R1)

Iteration i+2: LD F0,0(R1)

ADD F4,F0,F2

SD F4,0(R1)

Page 18: אופטימיזציות קומפיילרים

18

כעת נסמן תלויות:•

Iteration i: LD F0,16(R1)

ADD F4,F0,F2

SD F4,16(R1)

Iteration i+1: LD F0,8(R1)

ADD F4,F0,F2

SD F4,8(R1)

Iteration i+2: LD F0,0(R1)

ADD F4,F0,F2

SD F4,0(R1)

Page 19: אופטימיזציות קומפיילרים

19

נבחר פקודות שאינן תלויות, אחת מכל איטרציה ישנה:•

Iteration i: LD F0,16(R1)

ADD F4,F0,F2

SD F4,16(R1)

Iteration i+1: LD F0,8(R1)

ADD F4,F0,F2

SD F4,8(R1)

Iteration i+2: LD F0,0(R1)

ADD F4,F0,F2

SD F4,0(R1)

Page 20: אופטימיזציות קומפיילרים

20

ונקבע איטרציה להיות:•

Loop: SD F4,16(R1) ; stores into x[i]ADD F4,F0,F2 ; adds to x[i-1]LD F0,0(R1) ; loads x[i-2]ADDI R1,R1,# -8BNE R1,R2, Loop

... X[i-3] X[i-2] X[i-1] X[i] X[i+1] …

קרא קרא קרא √ קרא√ קרא√

חבר חבר חבר חבר √ חבר √

שמור שמור שמור שמור √ שמור

Page 21: אופטימיזציות קומפיילרים

21

ונקבע איטרציה להיות:•

Loop: SD F4,16(R1) ; stores into x[i]ADD F4,F0,F2 ; adds to x[i-1]LD F0,0(R1) ; loads x[i-2]ADDI R1,R1,# -8BNE R1,R2, Loop

... X[i-3] X[i-2] X[i-1] X[i] X[i+1] …

קרא קרא √ קרא √ קרא√ קרא√

חבר חבר חבר √ חבר √ חבר √

שמור שמור שמור √ שמור

√ שמור

Page 22: אופטימיזציות קומפיילרים

22

):stalls (ע"מ לחסוך schedulingואחרי •

Loop: SD F4,16(R1) ; stores into x[i]ADDI R1,R1,# -8ADD F4,F0,F2 ; adds to x[i-1]BNE R1,R2, LoopLD F0,8(R1) ; loads x[i-2]

מבוצע תמיד לאחר

הסיעוף

Page 23: אופטימיזציות קומפיילרים

23

כדי לשמר נכונות epilog ו-prologיש לתכנן •ונקבל:

R1 &x[998] F2 s R2 &x[0] LD F0,16(R1) ADD F4,F0,F2 LD F0,8(R1)

Loop: SD F4,16(R1) ADDI R1,R1,# -8 ADD F4,F0,F2 BNE R1,R2, Loop LD F0,8(R1) SD F4,16(R1) ADD F4,F0,F2 SD F4,8(R1)

מבוצע תמיד לאחר הסיעוף

X[997] X[998] X[999] X[1000]

קרא קרא קרא √ קרא√

חבר חבר חבר חבר √

שמור שמור שמור שמור

SD F4,16(R1) ADD F4,F0,F2 SD F4,8(R1)

R1 &x[998] F2 s R2 &x[0] LD F0,16(R1) ADD F4,F0,F2 LD F0,8(R1)

Page 24: אופטימיזציות קומפיילרים

24

השוואת השיטות

מ"ש אם נתעלם מהזנבות5האיטרציה לוקחת •

היא loop unrollingעל פני software pipelineהיתרון הגדול של •העובדה שאנו לא מנפחים את הקוד

מאפשר למכונות רחבות (יותר loop unrollingלעומת זאת, •) לנצל טוב יותר את רוחבן (ללא פקודות pipelineשלבים ב-

סיעוף תכופות שקוטעות את הרצף)

במקרים רבים, שילוב של שתי השיטות נותן את הביצועים •הטובים ביותר, שכן הן תוקפות את הבעיה מכיוונים שונים.

Page 25: אופטימיזציות קומפיילרים

25

Page 26: אופטימיזציות קומפיילרים

26

של המטמון ע"י קומפיילרhit rateשיפור ה-

ניתן hit rateדוגמא הכי פשוטה לאפשרות של קומפיילר לשפר •לראות בלולאות מקוננות אשר סדר הגישות בהן לזיכרון הוא

לא סדרתי

אם המטמון אינו גדול דיו לאחסן את כל הנתונים עלול להיות •דפדוף רב של שורות

לעיתים החלפת סדר הלולאות עשוי לפתור את הבעיה•

Page 27: אופטימיזציות קומפיילרים

27

דוגמא

• Beforefor (j=0; j<100; j++)

for (i=0; i<5000; i++)x[i][j]=2*x[i][j];

• Afterfor (i=0; i<5000; i++)

for (j=0; j<100; j++)x[i][j]=2*x[i][j];

Core2 Xeon על 10בבדיקה: הפרש פי •

Page 28: אופטימיזציות קומפיילרים

28

blockingישנם מקרים של לולאות מקוננות בהם החלפת סדר הלולאות •

אינה פותרת את הבעיה

פתרון משוכלל יותר מנסה במקום לעבור על כל •השורות/עמודות, לחלק את המטריצה לבלוקים

גודל הבלוקים אינו עולה על גודל המטמון ובכך בתוך הבלוק •ניתן לעבוד בחופשיות

מנסים לרכז את כל הפעילויות שרלוונטיות לאותו בלוק •וכשמסיימים עוברים לבלוק הבא.

Page 29: אופטימיזציות קומפיילרים

29

N*Nלדוגמא – כפל מטריצות X = Y*Z

for (i=0; i<N; i++)

for (j=0; j<N; j++)

{

r=0;

for (k=0; k<N; k++)

r = r + y[i][k] * z[k][j];

x[i][j]=r;

};

Page 30: אופטימיזציות קומפיילרים

30

ובגודל Nברור שמספר ההחטאות במטמון תלוי ב-•המטמון

2N3+N2במקרה הגרוע ביותר, עלולים להגיע ל- • פעולותN3החטאות מתוך

, כך B על Bנחלק את המטריצות לבלוקים של •שהבלוקים המטופלים בכל עת יהיו קטנים דיו

שורות 2באופן כללי סדר גודל של גודל מטמון עבור בלוק + – אמור להיות אופטימאליC ו-Aשל הבלוקים ממטריצות

•B-מכונה כ blocking factor מאתחלת לאפסים.Xנניח שהמטריצה •

Page 31: אופטימיזציות קומפיילרים

31

:הרעיון

X Y

= X

= +

Z*=

Page 32: אופטימיזציות קומפיילרים

32

:הרעיוןX Y

= X

= +

Z*=

Page 33: אופטימיזציות קומפיילרים

33

בדוגמה הנחנו:

1 .N הוא כפולה שלמה של B

B*B. יש מקום במטמון לארבעה "בלוקי טבלה" של 2

:הרעיוןX Y

= X

= +

Z*=

Page 34: אופטימיזציות קומפיילרים

34

After

for (jj=0; jj<N; jj+B)

for (kk=0; kk<N; kk+B)

for (i=0; i<N; i++)

for (j=jj; j<min(jj+B,N); j++)

{

r=0;

for (k=kk; k<min(kk+B,N); k++)

r = r + y[i][k] * z[k][j];

x[i][j]+=r;

};

Page 35: אופטימיזציות קומפיילרים

35

Compiler prefetch

הכוונה היא להכין מידע מהזיכרון מבעוד מועד•

לרגיסטרים או למטמון, prefetchingניתן להפריד ל-•) לכאלה faultingוכן בין כאלה שיוצרים פסיקות (

שבמקרה של פסיקה (גישה לכתובות אסורות למשל) nop (nonfaulting)פשוט הופכות ל-

prefetching רגילה כעל loadאפשר לחשוב על פקודת •...faultingלרגיסטר מסוג

nonfaultingרוב המעבדים כיום תומכים ב-•prefetching .למטמון

Page 36: אופטימיזציות קומפיילרים

36

?prehetchingמתי לעשות

דבר ראשון צריך שהמערכת לא תיעצר בעקבות •הפעולה

כלומר שעצם הבאת הבלוק למטמון לא תמנע מאיתנו –להמשיך לעבוד עם המטמון.

עולה זמן, ולכן רצוי לשים prefetchהוספת פקודות •אותם במקומות שיש סבירות גבוהה להחטאה במטמון

מיותרים רבים ועם זאת נצליח prefetchאם לא נעשה •לחסוך עם אלו שכן שמנו החטאות במטמון, הרי

שנשיג שיפור בביצועים.

Page 37: אופטימיזציות קומפיילרים

37

דוגמא

וגודל way-2, בשיטת 8KBנניח מערכת עם מטמון נתונים בגודל • בתים16שורה של

•a -ו b בתים. 8 הם מערכים של איברים בני –a עמודות, 100 שורות ו-3 הוא בן –b שורות ושתי עמודות.101 בן

נניח גם שהמטמון ריק• cacheעבור קטע הקוד הבא, אילו גישות סביר שיגרמו ל-•

misses?

for (i=0; i<3; i++)

for (j=0; j<100; j++)

a[i][j]=b[j][0]+b[j+1][0];

100

3A: …

101

2

B:

Page 38: אופטימיזציות קומפיילרים

38

תשובה

הן לפי הסדר בו יושב המערך בזיכרון ולכן נקבל aהגישות ל-•-ים האי זוגיים) סה"כ jהחטאה רק עם כל מעבר בלוק (כלומר ב-

3)*100/2=(150

אינן נהנות מלוקליות. לעומת זאת הגישה חוזרת bהגישות ל-• החטאות 101 ונותנת לנו סה"כ iעל עצמה בכל איטרציה של

.a השונים). כל זאת בהנחה שאין התנגשויות עם j(לערכי

100

3A: … …10

1

2

B:

for (i=0; i<3; i++) for (j=0; j<100; j++) a[i][j]=b[j][0]+b[j+1][0];

Page 39: אופטימיזציות קומפיילרים

39

prefetchכעת נוסיף פקודות

for (j=0; j<100; j++) { // i==0

prefetch(b[j+7][0]); /* b(j,0) for 7 iterations later */

prefetch(a[0][j+7]); /* a(0,j) for 7 iterations later */

a[0][j]=b[j][0]+b[j+1][0];

}

for (i=1; i<3; i++)

for (j=0; j<100; j++) {

prefetch(a[i][j+7]); /* a(i,j) for +7 iterations */

a[i][j]=b[j][0]+b[j+1][0]; }

Page 40: אופטימיזציות קומפיילרים

40

הערות

נשים לב שבסוף הלולאה אנו חורגים מגבולות •). זה בסדר prefetchהמערך (בפקודות ה-nonfaultingבתנאי שהפקודות הן

כה גדול כך miss penaltyההנחה היא שה- • איטרציות prefetching 7שיש להתחיל את ה-

קודם

Page 41: אופטימיזציות קומפיילרים

41

ביצועים a[i][99] עד a[i][7] עבור prefetchingהקוד מבצע לנו •

.b[100][0] עד b[7][0]וכן מ-

החטאות נקבל עבור:• בלולאה הראשונה.b[0][0] - b[6][0] החטאות של 7– בלולאה הראשונה.a[0][0] – a[0][6]) עבור 7/2 החטאות (4– בלולאה השנייה.a[1][0] – a[1][6]) עבור 7/2 החטאות (4–

. כך שהמחיר עבור prefetch החטאות ללא 15סה"כ • הוראות 400 הוא cache misses 236התחמקות מ-

prefetchמה שעל פניו נראה כהחלפה טובה ,