فرعٌ يقول من كتبه

ظهر في شجرة النواة الخاصة بلينوس تورفالدس نهاية الأسبوع الماضي فرعٌ اسمه noref-filemap-read-with-llm. ويضم ثماني رقع، كتبها تورفالدس وأودعها جميعًا يومي 9 و10 أكتوبر، فوق الإصدار 7.3-rc6. وآخرها إيداع فارغ لا يحمل سوى الشرح، وقرب نهاية ذلك النص، تحت عنوان “Tools”، فقرة قلّما ترد في إيداعات النواة:

“الشيفرة وبرامج الاختبار والمراجعة التي تقف خلف القائمة أعلاه والمسودة الأولى لهذا النص، كلها أُنجزت بمساعد برمجة قائم على نموذج لغوي كبير (Claude Code) تحت إشرافي. أما القياسات فقد أُجريت على جهازي.”

وأشار موقع Phoronix، الذي عثر على الفرع وهو ينتظر إصدار 7.3-rc7، إلى أن تورفالدس نادرًا ما يحتفظ بفروع عمل في مستودعه الرئيسي أصلًا. والإيداعات الثمانية ليست في الفرع الرئيسي master، ولم يقل إن كانت ستدخل نافذة الدمج للإصدار 7.4.

لوح أبيض مغطّى برسوم تخطيطية مكتوبة باليد في مكتب
يقول تورفالدس إن الشيفرة وبرامج الاختبار والمراجعة أُنجزت بمساعد تحت إشرافه. صورة توضيحية. Christina Morillo · pexels · Pexels License

المشكلة سطر واحد في الذاكرة المخبّأة

تعالج السلسلة مشكلة تزاحم أثارها ماثيو ويلكوكس عام 2024 انطلاقًا من عبء عمل أحد العملاء. فحين تقرأ خيوط كثيرة كميات صغيرة من الملف نفسه، تأخذ كل قراءة مرجعًا على الـ folio الذي يحمل الصفحة ثم تتركه، فتكتب كل قراءة سطر الذاكرة المخبّأة نفسه مرتين. وعلى حاسوب تورفالدس المحمول — وهو i7-8565U بأربع أنوية وثمانية خيوط — تضع ثمانية خيوط تنفّذ استدعاءات pread() بحجم 16 بايت على صفحة واحدة نسبة 99.92% من إصابات load HITM على ذلك السطر وحده.

وحلّه هو ألا يؤخذ المرجع أصلًا. فالـ folio الذي يُزال من مخبأ الصفحات لا يعود الآن إلى مخصّص الصفحات إلا بعد فترة سماح في RCU، ما يعني أن صفحة يُعثر عليها تحت rcu_read_lock() تظل تحمل بيانات الملف حتى يُرفع القفل. وعندها تنسخ القراءة مباشرةً إلى مخزن المستخدم مع تعطيل أخطاء الصفحات: بلا مرجع، وبلا مخزن وسيط على المكدس، وبلا تحقّق بعد النسخ، وبلا حدّ لحجم القراءة.

ويكتب تورفالدس أن المحاولات السابقة كانت تنسخ بلا مرجع إلى مخزن على المكدس ثم تتحقق لاحقًا، وأنها “توقفت عند ما لا يستطيع التحقق رؤيته”: التحرير وإعادة الاستخدام وإعادة الإدراج عند الفهرس نفسه، والترحيل، وقراءة ذاكرة لم تعد مخبأ صفحات على الإطلاق، ومنها secretmem والذاكرة غير المقبولة “أو الأسوأ، MMIO بآثار قراءة غير مرغوبة”. وتأجيل التحرير يزيل تلك الحالات بدل أن يكتشفها.

ثلاثة أضعاف القراءات، و30538 إصابة تهبط إلى 101

أرقام رسالة الإيداع مأخوذة من جهاز واحد، على نظام ملفات ext4، مع تعطيل إجراءات التخفيف في المعالج وتعطيل CONFIG_HARDENED_USERCOPY. فمع ثمانية خيوط تقرأ 16 بايت من صفحة واحدة، تحقق النواة الأساسية من 9.9 إلى 10.4 مليون قراءة في الثانية عند 2937–2975 دورة نواة لكل قراءة. ومع السلسلة تحقق من 30 إلى 33 مليونًا عند 725–726 دورة. وأربعة خيوط، واحد لكل نواة، ترتفع من 8.9–11.6 مليون إلى 25–26 مليونًا. أما إصابات load HITM المقيسة بـ perf c2c فتهبط من 30538 إلى 101.

كومة من الأقراص الصلبة على مكتب
التزاحم الذي تستهدفه السلسلة يظهر حين تقرأ خيوط كثيرة كميات صغيرة من ملف واحد. صورة توضيحية. Marta Branco · pexels · Pexels License

والثمن ذاكرة تنتظر في طابور فترة سماح، وهو الجزء الذي يصفه تورفالدس بأنه الأقل حلًّا. وكان اعتراض ويلكوكس على التأجيل، كما تنقله الرسالة، أنه “يبدو ببساطة محفوفًا بالمخاطر أكثر من اللازم أن يكون هذا القدر من الذاكرة في انتظار إعادة الاستخدام”. ووُجدت الرقعتان 7 و8 لاحتواء ذلك: فوق 1024 صفحة معلّقة على معالج، يستدعي عنصر عمل ثانٍ synchronize_rcu_expedited() ويحرّر القائمة، وهو ما يحدث 4600 مرة في الثانية مع أربع عمليات تثقب الملفات — رغم أن توثيق الدالة نفسها يقول ألا تُستدعى داخل حلقة. ويشير تورفالدس إلى ذلك بنفسه: “هل من سبيل إلى فترة سماح قصيرة من دونها؟”

ما يقول إنه لم يختبره

تنتهي الرسالة بقائمة بما لم تُجرَّب السلسلة عليه: ضغط الذاكرة خارج حالة إعادة إنتاج واحدة في آلة افتراضية، و lockdep، و KASAN، ونواة مبنية بـ clang، ومعمارية 32 بت، و CONFIG_HARDENED_USERCOPY، و”أي جهاز غير هذا”. وعن تعديل المجدول في الرقعة 8 يكتب: “لستُ واثقًا أن هذا هو الاتجاه؛ أفضّل أن تقوم المهمة التي تحرّر بشيء متزامن يترك المجدول وشأنه.”

وهذا هو الجزء الجدير بالمتابعة، أكثر من الأداة. فقد نشر تورفالدس سلسلة لإدارة الذاكرة حرجة من حيث الأداء، ونسب الشيفرة إلى مساعد، واحتفظ بالقياسات لنفسه، وترك سؤالين مفتوحين أمام القائمين على الأنظمة الفرعية. أما أن تصمد أمام المراجعة على القائمة البريدية فاختبار آخر غير أن تعمل بسرعة على حاسوبه المحمول.