C / المتقدم: حدود اللغة والأنظمة / الدرس 18
الأداء والقياس والصحة
حسن برنامجا معرّف السلوك على حمل ممثل وافصل تحسين الخوارزمية عن ادعاءات توقيت غير مسندة.
في هذه الصفحة
أهداف الدرس
- اختيار الحمل ومرجع الصحة قبل القياس.
- مقارنة العمل الخوارزمي ومحلية البيانات.
- تمييز مخاطر التحسين وrestrict والقياس.
طرح سؤال قابل للقياس
يبدأ تحسين الأداء بهدف: زمن استجابة أو معدل إنجاز أو ذروة ذاكرة أو مورد ملموس آخر تحت حمل محدد. سجل حجم البيانات وتوزيعها والمترجم وخياراته والعتاد وظروف النظام. لا تثبت نتيجة أسرع لمدخل صغير تحسنا مفيدا للحمل الحقيقي. أثبت صحة المخرجات أولا.
استخدم التحليل لتحديد العمل المكلف بدلا من التخمين من شكل المصدر. قس العمليات الكاملة المناسبة وكرر التجارب وأبلغ التفاوت. افصل التهيئة والإدخال والإخراج فقط عندما يستبعدها سؤال المنتج. لا يقارن اختبار يختلف عمل مرشحيه بعدل مهما دقت الساعة.
تقليل العمل المتكرر ببرهان
قد يهم تغيير الخوارزمية أكثر من تعبير ذكي. لاستعلامات مجاميع بادئات متكررة على بيانات ثابتة، يكلف حساب البادئات مرة واحدة عملا خطيا ويجيب كل استعلام بفهرسة مباشرة. تكلف المصفوفة الإضافية ذاكرة وتصبح قديمة عند تغير المصدر، فيعتمد الخيار على نسبة الاستعلامات إلى التحديثات.
يحسب المثال الأول بادئات أربع قيم صغيرة ثابتة ويفحص نتيجة استعلام معروفة. يلائم كل مجموع وسيط int. وللمدخلات العامة الكبيرة أو ذات الإشارة استخدم سياسة تجاوز صريحة. يثبت المثال نتيجة الحساب دون ادعاء تحسن زمني على كل مترجم وآلة.
#include <stddef.h>
#include <stdio.h>
int main(void)
{
const int data[] = {2, 4, 1, 3};
int prefix[5] = {0};
for (size_t i = 0; i < 4; ++i) prefix[i + 1] = prefix[i] + data[i];
int first_three = prefix[3];
if (first_three != 7) return 1;
printf("first-three=%d all=%d\n", first_three, prefix[4]);
return 0;
}
first-three=7 all=10
تخزن prefix[k] مجموع أول k قيم؛ والمخرجان الثابتان سبعة وعشرة.
فحص المرشح بمرجع بسيط
يمكن لتنفيذ بسيط أن يكون مرجع صحة لمرشح أعقد على بيانات اختبار محدودة. قارن الحالات العادية والفارغة والحدية وغير المنتظمة. احفظ مجموع تحقق أو استهلك النتيجة بطريقة ملحوظة في القياس حتى يرى المترجم غرضا؛ ولا تضف volatile في كل مكان كأداة عامة لمنع التحسين.
يفحص المثال الثاني اتفاق مجموع مباشر وحساب بادئات على البيانات الثابتة نفسها. يطبع عبارة صحة عمدا لا رقم توقيت مختلقا. ولقياس فعلي اختر ساعة مدعومة تناسب دقتها ومعناها السؤال؛ تقيس clock القياسية زمن المعالج لا ساعة جدار رتيبة عالمية.
#include <stddef.h>
#include <stdio.h>
int main(void)
{
const int data[] = {2, 4, 1, 3};
int direct = 0;
int prefix[5] = {0};
for (size_t i = 0; i < 4; ++i) direct += data[i];
for (size_t i = 0; i < 4; ++i) prefix[i + 1] = prefix[i] + data[i];
if (direct != prefix[4]) return 1;
printf("equivalent sum=%d\n", direct);
return 0;
}
equivalent sum=10
تحسب الخوارزميتان عشرة للمدخلات نفسها، فتثبتان فحص الصحة المحدود هذا.
التحسين يحتاج وعودا صحيحة
تفعل مستويات تحسين المترجم تحويلات مختلفة ذات آثار تعتمد على الهدف. اخترها وسجلها صراحة؛ ولا تفحص السلوك المحسن إلا بعد تعريف سلوك البرنامج. يعد GCC -O2 إعداد أداة لا ضمان سرعة لغويا. قد تغير خيارات مثل fast-math افتراضات العائم ويجب تقييمها وفق عقد الحساب العددي.
تُنشئ restrict، وهي مؤهل مؤشر في C، التزامات وصول بشأن التداخل أثناء تنفيذ الكتلة. ليست تلميحا عابرا بأن «المؤشرين مختلفان غالبا»، وقد يسبب خرق عقدها سلوكا غير معرّف. لا تضفها قبل فهم الوصولات وضمان قدرة المستدعين على الوفاء؛ وابدأ بواجهات بسيطة لا تتداخل عندما يمكن.
حفظ التحسن المقاس قابلا للصيانة
قد تحسن البيانات المتجاورة والتخصيصات الأقل والاجتياز المتكرر الأقل المحلية وتقلل الكلفة، لكن الفائدة الفعلية تعتمد على حجم العنصر ونمط الوصول. تجنب تحويل خوارزمية واضحة إلى حيل مؤشرات مبهمة لمكسب غير مقاس. أدرج استهلاك الذاكرة وتعقيد الفشل في المقارنة، لا زمن النجاح وحده.
بعد تحسين مبرر احتفظ باختبارات الصحة والحمل الممثل وظروف القياس وسبب قبول المقايضة. أعد فحص الأداء عند تغير الحمل أو الأدوات جوهريا. التحسين الذي يبطل ضمان الملكية أو الحساب تراجع في الصحة مهما بدا توقيته جذابا.
الأخطاء الشائعة وإصلاحها
يبلغ القياس عملا معدوما أو زمنا ضئيلا غير معقول.
- لماذا يحدث؟
- حذف المترجم الحساب غير المستخدم أو لم تكف دقة الساعة.
- كيف تصلحه؟
- استهلك نتيجة متحقق منها واختر حملا وساعة مناسبين.
- كيف تتجنب تكراره؟
- افحص بنية القياس قبل الوثوق بالرقم.
يغير البناء الأسرع النتائج العددية خارج الهامش.
- لماذا يحدث؟
- أضعفت الخيارات افتراضات يحتاجها التطبيق.
- كيف تصلحه؟
- استعد الخيارات المتوافقة أو عدل النموذج صراحة.
- كيف تتجنب تكراره؟
- أدرج فحوص الدقة في كل مقارنة أداء.
تكسر إضافة restrict مستدعين متداخلين.
- لماذا يحدث؟
- أُدخل وعد تداخل تعاقدي دون برهان.
- كيف تصلحه؟
- أزل المؤهل أو أعد التصميم وافرض وصولا غير متداخل.
- كيف تتجنب تكراره؟
- راجع كل المستدعين قبل تشديد شروط الوصول.
اختبر فهمك
1. يجري برنامج استعلام بادئة واحدا بعد كل تحديث لمصفوفة كبيرة. لماذا قد يكون الحساب المسبق تحسينا ضعيفا؟
اعرض الحل المشروح
تكلف إعادة كل البادئات بعد كل تحديث عملا خطيا وتخزينا إضافيا، بينما قد يكلف الاستعلام المباشر الواحد عملا خطيا بصيانة أقل. لا توزع نسبة الاستعلامات إلى التحديثات كلفة التحضير. قس مجالات الاستعلام الفعلية وفكر ببنية أخرى فقط إذا بررت المتطلبات تعقيدها وملكيتها. لا تنتقل ميزة الاستعلام المتكرر تلقائيا.
2. صمم مقارنة عادلة لمحللين دون اختلاق نتائج توقيت.
اعرض الحل المشروح
استخدم السجلات الاصطناعية الممثلة نفسها وافحص المخرجين بمرجع موثوق، مع حالات مقبولة ومرفوضة. ابن بخيارات موثقة متقاربة وكرر التجارب في ظروف مسجلة. حدد إدراج التخصيص والإدخال والإخراج وأبلغ التفاوت وذروة الذاكرة واحتفظ بالبيانات. لا تنشر قيما إلا بعد جمعها وافصل فشل الصحة عن مقارنة السرعة.
أهم ما تعلمته
- حسن حسابا معرّف السلوك ومتحققا منه وفق حمل محدد.
- قس العمل الخوارزمي والمحلية وكلفة الذاكرة معا.
- يجب أن تحفظ وعود المترجم والتداخل عقد صحة التطبيق.