
სატესტო პატჩი Go-ს netip-ში IPv4-ის IPv6-ზე გადაყვანისას ბაიტების გადალაგებას აუქმებს
სატესტო კომპილატორის გადაწერა Go-ს netip.AddrFrom16(ip.As16()) ნიმუშს შიდა ველის პირდაპირ კოპირებად აქცევს და იმავე მოკლე ასემბლერს გამოიმუშავებს, რასაც 0,88 ns-იანი სტანდარტული ბიბლიოთეკის გადაწყვეტა.
რატომ არის გადაყვანის ნიმუში ნელი
Go-ს netip.Addr გთავაზობს 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-ის მდგომარეობით, კომპილატორი ამ მიმდევრობას არ აშორებდა.
კომპილატორის დონის ექსპერიმენტი
ექსპერიმენტი ზუსტად netip.AddrFrom16(ip.As16()) ნიმუშს კომპილატორის noding ფაზის დროს გადაწერს. ის გამოძახებებს netip.Addr სტრუქტურით ცვლის, რომელიც ორიგინალ მისამართს აკოპირებს და IPv6 ოჯახის მნიშვნელობას ანიჭებს. გადაწერა noding-ის დროს უნდა მოხდეს, რადგან უფრო ადრეული ტიპების შემოწმების ფაზა სტრუქტურის არაექსპორტირებულ ველებზე წვდომას კრძალავს.
მორგებული ბილდი გადაწერით იმავე მოკლე ასემბლერს აგენერირებდა, როგორც პირდაპირი იმპლემენტაცია, და ტესტები წარმატებით გაიარა net/netip-სა და დამხმარე პაკეტისთვის. ანალიზი ამბობს, რომ Go-ს მენტენერები ნაკლებად სავარაუდოა ამ მიდგომას დათანხმდნენ, რადგან ის netip.Addr-ის შიდა განლაგებაზეა დამოკიდებული და noder-ს ტიპების შემოწმებული სინტაქსური ხის ერთგულად გადათარგმნაზე მეტ პასუხისმგებლობას აკისრებს.
შემოთავაზებული SSA ოპტიმიზაცია
უფრო ზოგადი მიდგომა კომპილატორის ზოგად SSA ფაზას, კერძოდ memcombine პასს, სამიზნედ ირჩევს. შემოთავაზებული გადაწერის წესები ჩატვირთვებს მეხსიერების გადაადგილებების გავლით გადაამისამართებს, შენახულ მნიშვნელობებს შემდგომ ჩატვირთვებამდე გადასცემს და ბაიტების გაცვლის ოპერაციების წყვილებს აუქმებს.
მისამართის თითოეული 64-ბიტიანი ნახევრისთვის ეს ტრანსფორმაციები დროებით მასივს, მის ასლს და ზედმეტ მეხსიერების წვდომას აცილებს. უფრო მაღალი ნახევრის გადაცემა ასევე შესაძლებელია შენახვის ოპერაციის გავლით მეზობელ, გადაუფარავ მისამართზე. გამარტივების შემდეგ ყოველი გამომავალი ნახევარი შესაბამისი შემავალი ნახევრის ასლი ხდება, რაც მისამართის მონაცემებს უცვლელად ტოვებს და საჭირო ოჯახის მნიშვნელობას აყენებს.
SiTech — AI-გაძლიერებული ვებ დეველოპმენტი
ვქმნით სწრაფ, თანამედროვე ვებსაიტებს და AI-ს ვაერთიანებთ ქართული ბიზნესებისთვის. გაქვთ პროექტი ან კითხვა? სიამოვნებით დაგეხმარებით.