
תיקון לבדיקה ב-netip של Go מבטל את סידור הבתים מחדש בעת המרה מ-IPv4 ל-IPv6
תיקון לבדיקה של המהדר של Go משכתב את התבנית netip.AddrFrom16(ip.As16()) להעתקה ישירה של שדה פנימי ומייצר את אותו אסמבלי קצר, מה שמבטל את הפתרון של הספרייה הסטנדרטית ב-0.88 ns.
למה תבנית ההמרה איטית
netip.Addr של Go מציע את המתודה Unmap(), שמחזירה כתובת IPv4 משוחררת מכתובת IPv6 שמופיעה כ-IPv4. לא קיימת מתודה Map() או To6() לפעולה ההפוכה. מחזקי Go דחו את הוספתה והפנו משתמשים ל-netip.AddrFrom16(ip.As16()), בתקווה שהמהדר יבצע אופטימיזציה זו.
בפנים, netip.Addr שומר כתובת IP כערך של 128 סיביות ומשתמש בשדה נוסף להצפנת המשפחה והאזור שלה. היישום של הספרייה הסטנדרטית של To6() יכול היה לשנות את השדה הזה עבור כתובות IPv4. העוזר החיצוני, לעומת זאת, היה צריך להמיר את הכתובת למערך של 16 בתים ולהחזיר אותו.
תוצאות בנצ'מרק
בבנצ'מרקים שהופעלו על Go 1.27.1 ב-Linux ועל מעבד AMD Ryzen 5 5600X בעל 6 ליבות, הפתרון של הספרייה הסטנדרטית דרש 0.8775 ns לפעולה. העוזר המאובטח דרש 7.137 ns, בעוד היישום הלא מאובטח, שניגש לאותה מצב פנימי באמצעות פרוקסי, דרש 0.8682 ns. לכן העוזר היה איטי פי כשמונה.
האסמבלי של הספרייה הסטנדרטית ושל הגרסאות הלא מאובטחות היה כמעט זהה. שניהם בדקו את משפחת הכתובת ושינו את ערך המשפחה הפנימי בעת עיבוד IPv4. העוזר המאובטח ייצר יותר הוראות, כי סידר את הכתובת במערך של 16 בתים, העתיק את המערך ופרק אותו שוב. עם Go 1.26.8, המהדר לא הסיר את הרצף הזה.
ניסוי בשלב ה-noding של המהדר
הניסוי משכתב בדיוק את התבנית netip.AddrFrom16(ip.As16()) במהלך שלב ה-noding של המהדר. הוא מחליף קריאות במבנה netip.Addr, שמעתיק את הכתובת המקורית ומקצה ערך משפחת IPv6. השכתוב חייב להתרחש ב-noding כי שלב בדיקת הטיפוסים המוקדם יותר חוסם גישה לשדות הלא מיוצאים של המבנה.
בנייה מותאמת עם השכתוב ייצרה את אותו אסמבלי קצר כמו היישום הישיר, והבדיקות עברו בהצלחה עבור net/netip ועבור החבילה העוזרת. הניתוח מציין שמחזקי Go פחות סביר שיסכימו לגישה הזו, כי היא תלויה בסידור הפנימי של netip.Addr ומטילה אחריות נוספת על noder לתרגם בנאמנות עץ תחביר מאומת של טיפוסים.
אופטימיזציית SSA מוצעת
גישה כללית יותר מכוונת לשלב הכללי של SSA של המהדר, ובפרט לעברת memcombine. כללי השכתוב המוצעים מחליפים טעינות באמצעות העברות זיכרון, מעבירים ערכים שמורים לטעינות שלאחר מכן ומבטלים זוגות של פעולות החלפת בתים.
עבור כל חצי של 64 סיביות של הכתובת, טרנספורמציות אלו עוקפות מערך זמני, עותק שלו וגישת זיכרון מיותרת. העברת חצי גבוה יותר אפשרית גם באמצעות פעולת אחסונה על כתובת שכנה וחורגת. לאחר פישוט, כל חצי פלט הופך לעותק של החצי הקלט המתאים, מה שמשאיר את נתוני הכתובת ללא שינוי ומקם את ערך המשפחה הנדרש.
SiTech — פיתוח אתרים בכוח ה-AI
אנחנו בונים אתרים מהירים ומודרניים ומשלבים AI בתהליכי עבודה אמיתיים. יש לכם פרויקט או שאלה? נשמח לעזור.