وسام البهنسي

مدونة مبرمج معماري

دود ونقط وحذاء لا يتسع

السلام عليكم ورحمة الله...

نتابع اليوم حديثنا في نفس سياق التدوينة السابقة عن إمكانيات الحواسيب هذه الأيام وإحسان برمجتها.

لقد قضيتُ سنوات عدة أحاول تحسين أداء البرمجيات، مروراً بألعاب ومحركات ألعاب وتطبيقات أخرى. 

وقد كونتُ نظرية خاصة بي بعد هذه الخبرة.. هذه النظرية تقول ببساطة أن تحسين الأداء صعب جداً، ومن يستطع اعتصار ١٠% أو ١٥% من الأداء هو شخص عبقري ترفع له القبعة. أما عندما أسمع أن أحدهم استطاع تحسين الأداء بنسبة ١٠٠% أو أكثر فنظريتي تقول أنه لم يفعل الكثير وإنما الكود الذي تم تحسينه كان معتوهاً من الأساس.

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

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

المهم، بمجرد أن ينتهي من إدراج الكود، فإنه يأخذ لقطات من النتائج ويرسلها لكامل الفريق متبجحاً بأنه قد أدخل هذا البحث الجديد في اللعبة بنفسه.

بعد ذلك تأتي الخطوة التالية: إعادة كتابة الكود التعيس الذي كتبه أول مرة، لكن بطريقة أفضل الآن. والنتيجة؟ تحسن كبير في الأداء بنسب خيالية. وهنا طبعاً ينتقل للمستوى الثاني من التبجح وكيف أنه تفوق على البحث الأصلي وجعله يعمل بسرعة فائقة، وطبعاً يضع في مراسلاته المدير ومدير المدير وصولاً إلى بيل جيتس كي يحصد أكبر قدر من الثناء والإطراء، وبالتالي تقدُّم أسرع في السلم الوظيفي.

لماذا أذكر هذه القصة؟ ربما بدأت أخرف... وربما لأننا نسمع كل بضعة أشهر من هذا المحرك أو ذاك أنه "تم تحسين أداء الميزة إكس وهي الآن تعمل بعشرة أضعاف سرعتها مقارنة بالإصدارات السابقة من المحرك". والواقع أن الرسالة ربما يجب أن تكون شيئاً مثل: "في هذا الإصدار تم إصلاح الميزة إكس لتعمل بشكل صحيح بدلاً من أن تستهلك عشرة أضعاف الوقت، ونعتذر لزبائننا السابقين عن تبديد الأداء هذا".

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

طبعاً هذا الديمو يختصر كل الطبقات والمعماريات الضرورية والغير ضرورية التي يحملها أنريل ويونيتي، وبالتالي استطاع أن يلامس الفاعلية المتاحة له بالفعل في جهازه، بدلاً من المرور بسلاسل من النداءات والنظم التي لا تخدم قضيته في شيء.

وبما أن كتّاب المحركات هم بشرٌ أيضاً، فإنهم أيضاً يغارون عند رؤية مثل هذه النتائج ويتمنون فعلاً لو كانت محركاتهم قادرة على تحقيق هذه النتيجة.

وهنا تحضرني قصة أخرى، عن أحد المبرمجين الذين أسسوا إيماناً راسخاً أن كل مشاكل الأداء في الألعاب هي بسبب سوء استخدام الكاش (cache). ومن هذا المنطلق فإن البرمجة غرضية التوجه (object-oriented programming) هي أسوأ اختراع عرفته البشرية، والأمل مبني على التصميم للبيانات (data-oriented design) أو اختصاراً DOD.

في هذا الأسلوب البرمجي يكون كل التركيز على تلقيم الحسابات ببيانات مرصوفة بأمثل طريقة للاستفادة من الكاش وسرعة الوصول للذاكرة. أعتقد أن أقرب مثال على ذلك هو برمجة معالجات الرسوميات، حيث أنها تتعامل بشكل رئيس مع كميات هائلة من البيانات المرصوفة بطريقة معينة تساعد المعالج على التعامل معها بسرعة قصوى. ويتم إدخال هذه البيانات في خط معالجة (pipeline) مكون من خطوات مرحلية تحوّل البيانات من شكل إلى آخر وصولاً للصيغة النهائية الجاهزة للتخريج إلى المستخدم. هذا النموذج أثبت نجاحه في مجال رسوميات الحاسوب لأنه فعلاً ملائم لطبيعة المسألة: حجم هائل من البيانات التي تمر بسلسلة ثابتة من الحسابات لتحويلها من شكل لآخر.

كما أن هذه البيانات لا ترتبط بين بعضها البعض. فمثلاً لو أردنا صبغ كل بكسل من الشاشة بطيف أزرق فيمكننا تنفيذ إجراء الصبغ على كل بكسل بمعزل عن البكسلات الأخرى. هذا الاستقلال يسمح بمعالجة البكسلات مع بعضها البعض على التوازي. وفي الحالة المثالية لو كان عندنا عدد من خطوط المعالجة يساوي عدد البكسلات، فإن صبغ جميع البكسلات لن يستغرق أكثر من الزمن اللازم لصبغ بكسل واحد! مرة أخرى نذكّر أن رسوميات الحاسوب هي مسألة مثالية لهذا الأسلوب البرمجي، ودائماً نسمع عن رسوميات الحاسوب أنها مسألة معالجة متوازية لدرجة الخجل (embarrassingly-parallel problem)، وذلك لاستقلالية البيانات فيها عن بعضها البعض.

نعود إلى صاحبنا الذي يبشّر بالتصميم للبيانات كمخرج من بئر الأداء الذي سقطت فيه محركات الألعاب. لنجد أن رئيس أحد هذه المحركات قد آمن بهذا الدين واتخذ من هذا المبشر ساعداً أيمناً يقوده لوضع تصميم جديد للمحرك. للأسف نحن لا نتحدث عن حالة تبني عقلانية. فما كان من هذا الرئيس إلا أن فرض على كافة مكونات المحرك أن يتم بناؤها وفقاً لمبدأ التصميم للبيانات، أو "دود" كما يحبون أن يختصروه. وعندما أقول "كافة" فإنني أعنيها فعلاً... بدءاً من نظم كالرسوميات والفيزياء والأصوات وصولاً إلى برمجة واجهات الاستخدام! وقد تم تسمية هذه النظم بحزمة التقنيات الموجهة للبيانات (data-oriented technology stack)، أو اختصاراً DOTS أو "دوتس".

المشكلة هنا أن محركات الألعاب لها جوانب عديدة.. بعضها فعلاً يتماشى مع هذه المنهجية البرمجية (كالرسوميات)، وبعضها لا يتماشى معها البتة (كواجهات الاستخدام)! لكن صاحبنا هذا أشبه بالمسحور ويبدو من الصعب إقناعه بأننا سنذهب في ستين داهية لو عمّمنا دوتس على كل شيء في العالم.

طبعاً حظي اللطيف يحب أن يمازحني كل فترة، فما كان منه إلا أن رماني على رأس فريق رسوميات واجهات الاستخدام في المحرك إياه. وهنا تكونت معركة صريحة بين فريقي الصغير ذو الثلاث أشخاص ضد ما لا يقل عن ٤٥٠ مبرمج يؤمنون بديانة الدوتس. وقد تم نعت فريقي باسم "عدو-الدوتس" من باب الطُّرفة.

طبعاً المعركة كانت خاسرة رغم أننا أصلحنا أداء نظام رسم واجهات الاستخدام ليعمل بحوالي ٣٠٠ ضعف سرعة الكود السابق، وبدون الاعتماد على مبدأ الدود. وكانت حجتي الدفاعية (التي لا زلت مقتنعاً بها) هي أن نُظُم واجهات الاستخدام لها خصائص تنفيذ تميزها عن بقية النظم في الألعاب، أهمها أنها حَدَثيّة التوجه (event-based) والتغييرات التي تطرأ عليها محدودة ولا تؤثر في الحالة العامة على كامل مكونات النظام (ممن فاتتهم محاضرتي عن هذا الموضوع، يمكنكم مشاهدتها هنا وشرائح العرض هنا).

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

للأسف لم أستطع أن أحشر نفسي في الحذاء آنف الذكر، وأعتقد أن من أصعب المواقف هو أن تعمل على شيء يخالف قناعاتك، وهكذا كانت نهاية عملي مع ذلك الفريق. ربما أحكي لكم قصتي معه يوماً ما، لأن فيها عِبَر كثيرة تعلمتها بالطريقة الصعبة، لكن يكفينا هذا القدر اليوم، وإلى موضوع آخر بإذن الله.

والسلام عليكم ورحمة الله!

أضف تعليقاً

Loading