במסמך הזה מוסבר איך לזהות ולפתור בעיות שקשורות לנעילות של אוטובוס 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 הזו ומיישמת אמצעי להפחתת הסיכון, בדרך כלל על ידי הגבלת קצב של התהליך הפגום. על ידי הכרחת התהליך לישון, ליבת המערכת מונעת מאפליקציה אחת להעמיס על אפיק הזיכרון, וכך משמרת את ביצועי המערכת עבור שאר מופע המחשוב, על חשבון ביצועי האפליקציה הפגומה.
תסמינים
אם תהליך במערכת האורחת של Linux מפעיל נעילות של אפיק המעבד, יכול להיות שתיתקלו בתסמינים הבאים:
- ביצועי האפליקציה יורדים: נעילות של אוטובוס המעבד עלולות לגרום לחביון לא צפוי באפליקציות.
- עליות פתאומיות בעומס על המערכת: יכול להיות שתהיה ירידה ברמת ההיענות הכוללת של המערכת.
- קריסות לא צפויות של אפליקציות: אם מגדירים את ליבת המערכת לטפל בפיצול או בנעילות של אפיק נתונים באופן קפדני (
split_lock_detect=fatal), יכול להיות שהאפליקציה הפגומה תקרוס עם שגיאהSIGBUS.
זיהוי נעילות של אפיק המעבד
כדי לזהות אם מופעלים נעילות של אוטובוס ה-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)
אם פעולות אטומיות בזיכרון שלא ניתן לשמור במטמון גורמות לנעילת אפיק המעבד, אזהרות של קומפיילר לא יזהו את זה. הבעיה הזו מתרחשת בדרך כלל כשמתבצעת אינטראקציה עם זיכרון המכשיר:
- ביקורת על מיפויים של זיכרון: בודקים את הקוד כדי לראות אם נעשה שימוש ב-
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 ולכלול את כל המידע שאספתם במהלך פתרון הבעיה.