تحليل أداء كود Rust: إيجاد نقاط الاختناق عمليًا
\n\nتشتهر Rust بأدائها العالي، ولكن حتى أسرع كود قد يحتوي على نقاط اختناق غير متوقعة. تحليل الأداء هو فن وعلم اكتشاف هذه المشكلات. في هذه المقالة، سنشرح عمليًا كيفية إيجاد وإزالة "الاختناقات" في تطبيقات Rust باستخدام الأدوات والتقنيات الحديثة.
\n\nلماذا يعتبر تحليل الأداء مهمًا لـ Rust؟
\n\nعلى الرغم من أن Rust تضمن عدم وجود جامع للقمامة وتمنح تحكمًا منخفض المستوى في الذاكرة، إلا أن هذا لا يحمي من الخوارزميات غير الفعالة، أو التخصيصات الزائدة، أو الاستخدام غير الصحيح للذاكرة المؤقتة. بدون تحليل الأداء، فإنك تخاطر بتحسين ما لا يحتاج إلى تحسين. يقدم تحليل الأداء إجابات على الأسئلة التالية:
\n\n- \n
- ما هي الدوال التي تستهلك معظم وقت المعالج (CPU)؟ \n
- أين تحدث تخصيصات الذاكرة المتكررة؟ \n
- ما هي أجزاء الكود التي تمنع التنفيذ (مثلًا بسبب الميوتكسات)؟ \n
- ما مدى كفاءة استخدام ذاكرة التخزين المؤقت للمعالج؟ \n
أدوات تحليل أداء Rust
\n\nدعنا نستعرض ثلاثة أساليب رئيسية تغطي 90% من مهام تحليل الأداء.
\n\n1. قياس الأداء المدمج باستخدام cargo bench
\n\nأبسط طريقة هي استخدام cargo bench من نظام Rust البيئي. يسمح لك بقياس وقت تنفيذ دوال معينة.
مثال لقياس أداء دالة تقوم بفرز مصفوفة:
\n\n// benches/my_bench.rs\nuse criterion::{black_box, criterion_group, criterion_main, Criterion};\n\nfn sort_benchmark(c: &mut Criterion) {\n let mut data: Vec<i32> = (0..10000).rev().collect();\n\n c.bench_function("sort 10k", |b| {\n b.iter(|| {\n // black_box يمنع تحسينات المترجم\n let mut clone = black_box(data.clone());\n clone.sort();\n black_box(clone)\n })\n });\n}\n\ncriterion_group!(benches, sort_benchmark);\ncriterion_main!(benches);\n\nالتشغيل: cargo bench
ستحصل على تقرير بالوقت والانحراف المعياري والمقارنة مع عمليات التشغيل السابقة. هذا مثالي لاختبار الانحدار في الأداء.
\n\n2. محلل الأداء النظامي perf (لينكس)
\n\nperf هي أداة قوية من نواة لينكس. تجمع عينات من عدادات الأداء (دورات المعالج، أخطاء الذاكرة المؤقتة، التعليمات) دون تعديل الكود.
الاستخدام الأساسي:
\n\n# جمع البيانات\nperf record -F 99 --call-graph dwarf ./my_rust_program\n\n# عرض التقرير\nperf report --stdio\n\n# إنشاء flamegraph\nperf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg\n\nالعلامة -F 99 تحدد تردد أخذ العينات 99 هرتز (عادةً ما يكون كافيًا). --call-graph dwarf يتضمن تسجيل مكدس الاستدعاءات. الناتج هو flamegraph تفاعلي (SVG)، حيث المحور X يمثل الوقت، والمحور Y يمثل مكدس الاستدعاءات. عرض المستطيل يوضح مقدار الوقت الذي استغرقته الدالة.
3. أداة flamegraph لـ Rust
\n\nتوجد أداة متخصصة cargo-flamegraph تبسط إنشاء flamegraph لمشاريع Rust:
cargo install flamegraph\ncargo flamegraph --bin my_binary\n\nبعد التنفيذ، سيظهر ملف flamegraph.svg في جذر المشروع. افتحه في المتصفح - سترى فورًا أجزاء الكود "الساخنة".
مثال عملي: تحسين محلل (Parser)
\n\nلنفترض أننا نكتب محلل JSON بلغة Rust، وهو يعمل ببطء. سنستخدم تحليل الأداء لإيجاد المشكلة.
\n\nالخطوة 1: قياس الأداء
\n\nننشئ اختبار أداء لتحليل ملف JSON كبير (مثلًا 10 ميجابايت). نشغل cargo bench ونرى أن التحليل يستغرق 2.5 ثانية. هذا كثير.
الخطوة 2: Flamegraph
\n\nنشغل cargo flamegraph على الملف الثنائي الذي يحلل هذا الملف. نفتح SVG ونرى أن 60% من الوقت