במאמר הזה מוסבר איך לזהות ולפתור בעיות שקשורות לנעילות של אוטובוס CPU במערכות הפעלה אורחות של Linux. המאמר כולל הסבר על התסמינים של נעילות אוטובוס של מעבד, איך לאבחן את הבעיות האלה באמצעות הודעות ביומן של ליבת מערכת ההפעלה, איך לאתר את הקוד הפגום ואיך להחיל אמצעי מניעה או תיקונים.
סקירה כללית
נעילת אפיק CPU מתרחשת כשמעבד צריך לאשר אות חומרה LOCK# כדי לקבל גישה בלעדית לאפיק הזיכרון של המערכת. הבעיה הזו מתרחשת בדרך כלל באחד מהמקרים הבאים:
- הוראה אטומית פועלת על זיכרון לא מיושר שחוצה גבול של שורת מטמון (נעילה מפוצלת).
- הוראה אטומית פועלת בזיכרון שמסומן כ-
uncacheable(UC), כמוMemory-Mapped I/O(MMIO).
המעבד (CPU) קובע נעילת אוטובוס גלובלית, ולכן כל המעבדים והמכשירים האחרים במערכת ההפעלה של האורח צריכים לחכות עד שפעולת הזיכרון תסתיים. שיעור גבוה של נעילות אוטובוס עלול לפגוע באופן משמעותי בביצועי ה-CPU.
מעבדים ישנים יותר לא עקבו אחרי נעילות של אפיקי נתונים, אבל מעבדי x86 מודרניים, כמו Intel Sapphire Rapids ואילך, או AMD Zen 5 ואילך, כוללים תכונת חומרה שמזהה נעילות של אפיקי נתונים של מעבד. כשפקודה מפעילה נעילה של אפיק CPU, המעבד מנפיק חריגת ניפוי באגים (#DB) מיד אחרי שהפקודה מסתיימת.
החל מגרסת ליבת Linux 5.13 ב-Intel ו-6.13 ב-AMD, ליבת Linux מיירטת את חריגת #DB הזו ומיישמת אמצעי להפחתת הסיכון, בדרך כלל על ידי הגבלת קצב התהליך הפגום. על ידי הכרחת התהליך לישון, ליבת המערכת מונעת מאפליקציה יחידה להעמיס על אפיק הזיכרון, וכך שומרת על ביצועי המערכת עבור שאר מופע ה-Compute, על חשבון ביצועי האפליקציה הפגומה.
תסמינים
אם תהליך במערכת האורחת של Linux מפעיל נעילות של אוטובוס המעבד, יכול להיות שתיתקלו בתסמינים הבאים:
- ביצועי אפליקציה פחות טובים: נעילות של אוטובוס המעבד עלולות לגרום לחביון לא צפוי באפליקציות.
- עליות פתאומיות בעומס על המערכת: יכול להיות שהיענות המערכת הכוללת תרד.
- קריסות לא צפויות של אפליקציות: אם מגדירים את ליבת המערכת לטפל בפיצול או בנעילות של אפיק הנתונים באופן קפדני (
split_lock_detect=fatal), יכול להיות שהאפליקציה הפגומה תקרוס עם שגיאהSIGBUS.
זיהוי נעילות של אוטובוס המעבד
כדי לזהות אם מופעלים נעילות של אפיק ה-CPU במופע החישוב, מבצעים אחת מהפעולות הבאות:
- אם הפעלתם רישום ביומן של פלט היציאה הטורית עבור מכונת החישוב, בדקו את פלט היציאה הטורית כדי לראות את העקבות של נעילת אפיק ה-CPU.
- בודקים את היומנים של מערכת ההפעלה של מופע המחשוב (
/var/log/messages) כדי למצוא מעקב של נעילת אוטובוס CPU.
דוגמה למעקב אחר נעילת אפיק נתונים של מעבד
x86/split lock detection: #DB: <process_name>/<pid> took a bus_lock trap at
address: 0x<address>
כדי לזהות נעילות של אוטובוס CPU בעתיד:
- הפעלת רישום ביומן של פלט היציאה הטורית
יצירת מדיניות התראות שמבוססת על יומן עבור היומן הבא:
resource.type="gce_instance" log_id("serialconsole.googleapis.com/serial_port_1_output") textPayload=~"took a bus_lock trap"רשומת היומן הזו כוללת את שם התהליך (
<process_name>) ואת מזהה התהליך (<pid>) שאחראי לנעילת אפיק ה-CPU, וגם את כתובת מצביע ההוראה שבה התרחשה התקלה.
פתרון בעיות שקשורות לנעילות של אוטובוס המעבד
אם אתם מפתחים או מהדרים את האפליקציה הפגומה, אתם יכולים להשתמש באזהרות ספציפיות של מהדר C או C++ כדי לזהות משתנים ומבנים שעשויים לגרום לנעילות מפוצלות.
אזהרות של קומפיילר
אם משתמשים ב-GCC או ב-Clang, צריך לקמפל את הקוד עם הדגלים הבאים כדי לזהות בעיות יישור:
-
-Wcast-alignאו-Wcast-align=strict: הדגלים האלה מציגים אזהרה כששינוי של מצביע מגדיל את היישור הנדרש של היעד. העברה של מאגר זמני גנריchar*ל-uint64_t*וביצוע פעולה אטומית עליו היא סיבה קלאסית לפיצול נעילות. -
-Waddress-of-packed-member: הדגל הזה מציג אזהרה כשמבצעים פעולה על כתובת של חבר במבנה דחוס (לדוגמה, באמצעות#pragma pack(1)או__attribute__((packed))). מכיוון שמבנים דחוסים מתעלמים מיישור טבעי של הזיכרון, לכל פעולה אטומית על חבר במבנה דחוס יש סיכוי גבוה לחצות גבול של שורת מטמון של 64 בייט.
איתור נעילות זיכרון שלא ניתן לשמור במטמון (UC)
אם פעולות אטומיות בזיכרון שלא ניתן לשמור במטמון גורמות לנעילת אפיק ה-CPU, אזהרות של קומפיילר לא יזהו את זה. הבעיה הזו מתרחשת בדרך כלל כשמתבצעת אינטראקציה עם זיכרון המכשיר:
- בודקים את מיפוי הזיכרון: בודקים את הקוד כדי לראות אם נעשה שימוש ב-
mmapעם פלאגים כמוO_SYNCאו גישה ישירה ל-/dev/memאו ל-/dev/uio. - לא מומלץ להשתמש בפעולות אטומיות ב-MMIO: אל תשתמשו בפעולות אטומיות כמו
__sync_fetch_and_addאוstd::atomicבאזורי זיכרון שממופים לרישום של מכשירים או למאגרי זיכרון שלא ניתן לשמור במטמון.
תיקון נעילות של אוטובוסים במעבד
כדי לפתור בעיות של נעילת אוטובוס CPU, צריך לתקן את יישור הזיכרון בקוד המקור של האפליקציה.
- מומלץ להימנע משימוש ב-
#pragma packאו ב-__attribute__((packed))במבנים שמכילים משתנים אטומיים, mutex או spinlock. - כדי לאלץ משתנים שנמצאים בשימוש נרחב בפעולות אטומיות להתיישר לגבולות של שורות מטמון, משתמשים בהנחיות יישור רגילות (כמו
alignas(64)ב-C++11 או__attribute__((aligned(64)))ב-C). - מוודאים שאין אזהרות שקשורות ליישור במהלך ההידור.
- חשוב להקפיד להשתמש רק במנגנוני נעילה רגילים (mutexes, spinlocks) או בהוראות אטומיות ב-RAM רגיל שניתן לשמור במטמון, ולא בזיכרון MMIO או UC.
אם הבעיה לא נפתרה בעזרת השלבים לפתרון בעיות, פנו אל Cloud Customer Care וצרפו את כל המידע שאספתם במהלך פתרון הבעיות.