1 אופטימיזציות קומפיילרים. 2 delayed branch slots אם ניזכר במכונת...

Post on 22-Dec-2015

230 Views

Category:

Documents

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

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

2

Delayed branch slots

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

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

פקודות עלינו להכניס.

הפתרון של המכונה עבור בעיה זו הוא לנסות • ולפעול branchלהמר מה תהיה תוצאת ה-

בהתאם.

3

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

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

.nopתאים שיוותרו ריקים יוחלפו בפקודת –

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

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

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

שלא הצלחנו למלא).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

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 7 stall 8BNE R1,R2,Loop 9 stall 10

11

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

Loop: LD F0,0(R1)ADDI R1,R1,#-8ADD F4,F0,F2 stallBNE R1,R2,LoopSD F4,8(R1)

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

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

פק' הסיעוף

12

Loop unrolling

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

).ADDוה-

המ"ש הם עדכון המונה, פקודת הסיעוף 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( ללא התייחסות ל-

14

הסבר ואת הקטנות branchהסרנו את הוראות ה-•

המונה הפנימיות.במידה ומספר האיטרציות לא מתחלק בצורה •

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

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

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

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,# -32stallstall

SD F12,16(R1) (16-32=-16)BNE R1,R2,Loop

SD F16,8(R1) (8-32=-24)

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

הסיעוף

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 על פני software pipelineהיתרון הגדול של •

unrolling.היא העובדה שאנו לא מנפחים את הקוד מאפשר למכונות רחבות 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

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;

};

32

:הרעיוןX Y

= X

= +

Z*=

33

:הרעיוןX Y

= X

= +

Z*=

34

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

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

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

:הרעיוןX Y

= X

= +

Z*=

35

Compiler prefetch

הכוונה היא להכין מידע מהזיכרון מבעוד מועד.• לרגיסטרים או prefetchingניתן להפריד ל-•

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

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

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

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

36

?prehetchingמתי לעשות

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

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

להחטאה במטמון. מיותרים רבים ועם זאת prefetchאם לא נעשה •

נצליח לחסוך עם אלו שכן שמנו החטאות במטמון, הרי שנשיג שיפור בביצועים.

37

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

way בתים.16 וגודל שורה של •a -ו b בתים. 8 הם מערכים של איברים בני a 3 הוא בן

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

?cache missesל-

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

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

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

38

תשובה

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

-ים האי זוגיים) סה"כ jבלוק (כלומר ב-3)*100/2=(150.

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

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

a.

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

top related