יום שישי

Memory Barrier

הפוסט הזה הוא חלק מההקדמה לפוסט "short". האחרון מציג דוגמא לטיפול ב-IO.
מה זה Memory Barrier? מדובר בקבוצה של פונקציות שנועדו להבטיח סדר ביצוע פעולות כתיבת\קריאת זיכרון.
למה צריך את זה? מיד נראה מצבים שבהם סדר הכתיבות\קריאות לא ודאי. הוא לא ודאי כי הקומפיילר\CPU עשויים להחליט על שינוי סדר הפעולות כדי לשפר יעילות ביצוע.
שני סוגי המצבים הבעיתיים האופייניים הם:
-שינוי סדר פעולות בטיפול ב-I/O
-שינוי סדר פעולות במערכת Multiprocessing.

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

דוגמא לבעיה  ב-IO:
הדוגמא מציגה קריאה מ-IO.
המטרה: קריאה לתוך משתנה a,  מהכתובת 0x2000 שנמצאת במרחב הזיכרון אליו ממופה ה-IO.
הקריאה מרכיב הIO  הזה היא indirect, כך שהיא מתבצעת בשני שלבים:
1. הכנסת הכתובת ממנה נרצה לקרוא לתוך רגיסטר שממופה לכתובת 0x5 במרחב הIO/
2. שליפת ה-data שבכתובת שנקראה מתוך רגיסטר שממופה לכתובת 0x6 במרחב ה-IO.


הנה קטע התוכנית:

#define ADDRESS 0x5
#define DATA        0x6
*(ADDRESS) = 0x2000;
a = *(DATA)



מה הבעיה?
ה-CPU עלול לבצע את השורה השניה - a = *DATA, לפני הראשונה - ADDRESS= 0x2000*. ברור שהתוצאה שתתקבל אינה טובה.
נציג בהמשך סט של פונקציות מסוג barrier שיפתור את הבעיה.
פתרון לדוגמא:



#define ADDRESS 0x5
#define DATA        0x6
*(ADDRESS) = 0x2000;
barrier function here;
a = *(DATA)

ה-barrier שחוצץ בין שתי השורות מבטיח את סדר הביצוע.





דוגמא לבעיה בסביבת Multiprocessing

הנה דוגמא מתוך וויקיפדיה:

Processor #1:
 while (f == 0);
 // Memory fence required here
 print x;
Processor #2:
 x = 42;
 // Memory fence required here
 f = 1;


איזה ערך של x ידפיס Processor #1? אם השורה השניה ב-Processor #2 תתבצע לפני השורה הראשונה, הערך שיודפס לא יהיה 42.
היה אפשר להבטיח את סדר הביצוע ע"י הוספת barrier באופן הבא:


x = 42;
barrier function here;
f = 1;

נציג כעת את משפחת הפונקציות שממשת את פונקצית ה-barrier:



1. קבוצת הפונקציות הבאה מונעת היפוך סדר של הגישות לזיכרון, מוגדרות ב - asm/system.h:
void rmb(void);
void wmb(void);
void mb(void);
void read_barrier_depends(void);






rmb - מונעת היפוך סדר בין פעולות read בלבד/
wmb - מונעת היפוך סדר בין פעולות write בלבד/
mb - מונעת היפוך סדר בכל מקרה. במידת האפשר עדיף להשתמש בחציצת rmb או wmb בלבד כי הפגיעה בביצועים קטנה יותר. נציין שבארכיטקטורת 86 wmb לא עושה כלום  כי אין שינוי סדר בכתיבות לזיכרון חיצוני, כך שגם אין לה שום פגיעה בביצועים.
read_barrier_depends - חוצצת בין פעולות read בלבד, בדומה ל-rmb, אך היא מונעת היפוך סדר רק בפעולות בהן הקריאה בשורה השניה תלויה ב-data שנקראה בשורה הראשונה.

2. קבוצת הפונקציות הבאה מונעת היפוך סדר של הגישות לזיכרון רק במקרה שהקוד מקומפל עבור מערכת עם SMP- Symmetric Multiprocessing. מוגדרות ב - asm/system.h. במקרה שאין SMP, הפונקציות יפעלו כפונקצית ()barrier שתוסבר בסעיף הבא:
void smp_rmb(void);
void smp_wmb(void);
void smp_mb(void);
void smp_read_barrier_depends(void);






3. הפונקציה ()barrier לא מטפלת בשמירה על סדר הגישות לזיכרון עצמו (ל"חומרה"), אלא רק מונעת אופטימיזציות תוכנה של הקומפיילר. היא דואגת להשלמת העתקת כל הערכים שה-CPU שומר ברגיסטר כדי לשפר ביצועים, לתוך מקומם בזיכרון.






void barrier(void)










אין תגובות:

הוסף רשומת תגובה