كود C++ الخاص بك بطيء؟ حان الوقت للنظر تحت الغطاء
\n\nلقد كتبت كود C++ يبدو مثاليًا للوهلة الأولى. التجميع تم بدون أخطاء، البرنامج يعمل... لكنه يعمل بطريقة بطيئة. هل هذا مألوف؟ قد تفكر في إعادة كتابة كل شيء بلغة التجميع أو إضافة تعدد المهام على الفور. لا تتعجل. على الأرجح، المشكلة ليست في البنية، بل في عدد قليل من الدوال "الساخنة" التي تستهلك 90% من وقت المعالج.
\n\nفي عالم لينكس، لدينا ترسانة قوية من الأدوات لـ تحليل أداء كود C++. هذا ليس سحرًا، بل علم. نحن لا نخمن، بل نقيس. في هذا الدليل، سأعرض لك أربع طرق عملية: من "نظرة عامة سريعة" إلى اختبارات الأداء الدقيقة. ستتعلم كيفية تحليل أداء C++ على لينكس كمحترف حقيقي.
\n\nلماذا التخمين سيء والتحليل جيد
\n\nقبل الغوص في الكود، تذكر القاعدة الذهبية للتحسين: "لا تحسن ما لم تقم بقياسه". حدسك مستشار سيء. غالبًا ما نقضي ساعات في تحسين دالة تُستدعى مرة في الدقيقة، ونتجاهل حلقة بسيطة من 10 ملايين تكرار.
\n\nالتحليل يعطيك إجابات لثلاثة أسئلة رئيسية:
\n- \n
- أين يقضي البرنامج معظم الوقت؟ \n
- لماذا يحدث هذا (خوارزمية غير فعالة، عمليات إدخال/إخراج كثيرة، أخطاء في التخزين المؤقت)؟ \n
- ماذا تغير بعد تعديلاتك؟ \n
اليوم سنشرح أربع أدوات تغطي 99% من احتياجاتك. هيا بنا!
\n\nالأداة رقم 1: gprof — الكلاسيكية
\n\ngprof هو أداة تحليل أداء GNU القديمة والموثوقة. يعمل على مرحلتين: جمع الإحصائيات أثناء تشغيل البرنامج ثم تحليلها. المزايا: لا حاجة لتثبيت أي شيء إضافي، موجود في كل توزيعة لينكس. العيوب: يعطي نتائج تقريبية ولا يعمل مع البرامج متعددة الخيوط بشكل افتراضي.
\n\nكيفية استخدام gprof
\n\nالخطوة 1. قم بتجميع البرنامج مع العلم الخاص -pg:
g++ -pg -O2 my_program.cpp -o my_program\n\nلاحظ: نستخدم -O2. تحليل نسخة تصحيح بدون تحسينات لا معنى له، ستحصل على صورة مشوهة.
الخطوة 2. قم بتشغيل البرنامج. سيعمل بشكل أبطأ قليلاً لأن gprof يجمع البيانات.
\n./my_program\n\nالخطوة 3. سيظهر ملف gmon.out في المجلد الحالي. قم بتحليله:
gprof my_program gmon.out > analysis.txt\n\nافتح analysis.txt وسترى شيئًا مثل:
Flat profile:\nEach sample counts as 0.01 seconds.\n % cumulative self self total\n time seconds seconds calls us/call us/call name\n 60.00 0.06 0.06 10000 6.00 6.00 slow_function\n 20.00 0.08 0.02 5000 4.00 4.00 fast_function\n 10.00 0.09 0.01 main\n\nها هي! نرى أن slow_function استهلكت 60% من الوقت. هذا هو المرشح للتحسين.
مثال كود للتحليل
\n\nلنكتب برنامجًا بسيطًا سنقوم بتحليله بجميع الأدوات:
\n\n#include <iostream>\n#include <cmath>\n\nvoid slow_function(int n) {\n volatile double sum = 0.0; // volatile لمنع المحول البرمجي من تحسينها للصفر\n for (int i = 0; i < n; ++i) {\n for (int j = 0; j < 1000; ++j) {\n sum += std::sin(i) * std::cos(j);\n }\n }\n std::cout << sum << std::endl;\n}\n\nvoid fast_function(int n) {\n volatile int count = 0;\n for (int i = 0; i < n; ++i) {\n count += i % 2;\n }\n std::cout << count << std::endl;\n}\n\nint main() {\n slow_function(10000);\n fast_function(50000);\n return 0;\n}\n\nقم بتجميعه مع العلم -pg وقم بتشغيله.