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

Preview:

DESCRIPTION

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

Citation preview

1

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

2

Delayed branch slots

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

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

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

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

3

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

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

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

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

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

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

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

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

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

מלפני הקפיצה

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

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

הסעיפים

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

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

8

דוגמא

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

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

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

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

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;

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

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

12

Loop unrolling

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

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

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

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

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

14

הסבר

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

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

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

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

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

16

?מה קיבלנו

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

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

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

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)

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)

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)

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] …

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

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

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

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] …

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

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

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

√ שמור

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]

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

הסיעוף

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)

24

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

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

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

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

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

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

25

26

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

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

לא סדרתי

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

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

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בבדיקה: הפרש פי •

28

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

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

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

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

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

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;

};

30

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

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

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

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

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

31

:הרעיון

X Y

= X

= +

Z*=

32

:הרעיוןX Y

= X

= +

Z*=

33

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

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

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

:הרעיוןX Y

= X

= +

Z*=

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;

};

35

Compiler prefetch

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

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

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

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

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

36

?prehetchingמתי לעשות

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

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

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

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

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

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:

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];

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]; }

40

הערות

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

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

קודם

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מה שעל פניו נראה כהחלפה טובה ,