الارتعاش هو سلوك النظام العشوائي الذي يمنع تنفيذ العمل الملحوظ. توضّح هذه الصفحة كيفية تحديد ومعالجة مشاكل الارتباك المرتبطة بالتشويش.
تأخُّر جدولة مؤشرات تسلسل التطبيقات
تأخُّر جدولة المهام هو العرض الأكثر وضوحًا للتشويش: عملية يجب إجراؤها، ولكن لا يتم إجراؤها لبعض الوقت. تختلف أهمية التأخير حسب السياق. مثلاً:
- من المحتمل أن يتأخّر خيط مساعد عشوائي في أحد التطبيقات لعدة ملي ثانية بدون حدوث أي مشكلة.
- قد يتمكّن مؤشر تسلسل واجهة المستخدم في التطبيق من تحمل 1 إلى 2 مللي ثانية من الارتعاش.
- قد تتسبب مؤشرات kthreads الخاصة بالبرامج في حدوث مشاكل إذا كانت قابلة للتنفيذ لمدة 500 ميكرو ثانية قبل التشغيل.
يمكن تحديد أوقات التشغيل في systrace من خلال الشريط الأزرق الذي يسبق
الجزء الجاري من سلسلة محادثات. يمكن أيضًا تحديد وقت التشغيل حسب
المدة الزمنية بين حدث sched_wakeup
لسلسلة مهام وحدث
sched_switch
الذي يشير إلى بدء تنفيذ سلسلة المهام.
سلاسل المحادثات التي تستغرق وقتًا طويلاً جدًا
يمكن أن تتسبب سلاسل محادثات واجهة مستخدم التطبيق التي يمكن تشغيلها لفترة طويلة جدًا في حدوث مشاكل. إنّ سلاسل المهام ذات المستوى الأدنى التي تستغرق وقتًا طويلاً في التنفيذ لها أسباب مختلفة بشكل عام، ولكن قد تتطلّب محاولة تقليل وقت تنفيذ سلسلة مهام واجهة المستخدم إلى الصفر حلّ بعض المشاكل نفسها التي تؤدي إلى أن تستغرق سلاسل المهام ذات المستوى الأدنى وقتًا طويلاً في التنفيذ. للحدّ من التأخيرات:
- استخدِم cpusets كما هو موضّح في تقييد الأداء بسبب الحرارة.
- ارفع قيمة CONFIG_HZ.
- في السابق، تم ضبط القيمة على 100 على منصّتَي arm وarm64. ومع ذلك، هذا خطأ في السجلّ وليس قيمة جيدة لاستخدامها مع الأجهزة التفاعلية. يعني الخيار CONFIG_HZ=100 أنّ مدة الفاصل الزمني هي 10 مللي ثانية، ما يعني أنّ موازنة التحميل بين وحدات المعالجة المركزية قد تستغرق 20 مللي ثانية (فاصلان زمنيّان). ويمكن أن يؤدي ذلك إلى حدوث تقطُّع في الأداء بشكل ملحوظ على نظام مشغول.
- تم شحن الأجهزة الحديثة (Nexus 5X وNexus 6P وPixel وPixel XL) مع الإعداد CONFIG_HZ=300. من المفترض أن يكون استهلاك الطاقة ضئيلًا مع تحسين أوقات التشغيل بشكلٍ ملحوظ. إذا لاحظت زيادات كبيرة في استهلاك الطاقة أو مشاكل في الأداء بعد تغيير CONFIG_HZ، من المحتمل أنّ أحد برامج التشغيل يستخدم موقّتًا يستند إلى وحدات jiffies الأوّلية بدلاً من الوحدات الميلي ثانية ويحولها إلى وحدات jiffies. يمكن حلّ هذه المشكلة عادةً بسهولة (اطّلِع على التصحيح الذي حلّ مشاكل موقّت kgsl على جهازَي Nexus 5X و6P عند التحويل إلى CONFIG_HZ=300).
- أخيرًا، جرّبنا الإعداد CONFIG_HZ=1000 على هواتف Nexus/Pixel ووجدنا أنّه يؤدي إلى تحسين الأداء وخفض استهلاك الطاقة بشكل ملحوظ بسبب انخفاض تكاليف RCU.
من خلال هذين التغييرَين فقط، من المفترض أن يُظهر الجهاز أداءً أفضل بكثير في ما يتعلّق بوقت تنفيذ سلسلتَي المهام الخاصة بواجهة المستخدم في ظلّ الضغط.
استخدام sys.use_fifo_ui
يمكنك محاولة ضبط وقت التشغيل المسموح به لسلسلة مهام واجهة المستخدم على القيمة صفر من خلال ضبط سمة
sys.use_fifo_ui
على القيمة 1.
تحذير: لا تستخدِم هذا الخيار في
إعدادات وحدة المعالجة المركزية غير المتجانسة ما لم يكن لديك جدولة RT مدركة للسعة.
وفي الوقت الحالي، لا يتوفّر جدول زمني متاح للشحن يراعي السعة. نحن نعمل على توفير حلّ لخدمات EAS، ولكنّه ليس متاحًا بعد. يستند جدولة RT التلقائية إلى أولويات RT فقط وما إذا كانت وحدة المعالجة المركزية تملك حاليًا مؤشر تسلسل RT بأولوية متساوية أو أعلى.
نتيجةً لذلك، سينقل جدولة RT التلقائية بثقة سلسلتك المبرمَجة لوحدة التحكّم في المستخدم التي تستغرق وقتًا طويلاً نسبيًا من نواة كبيرة ذات تردد عالٍ إلى نواة صغيرة ذات الحد الأدنى من التردد إذا تم تشغيل سلسلة مبرمَجة أخرى ذات أولوية أعلى وتعمل بأولوية FIFO على النواة الكبيرة نفسها. سيؤدي ذلك إلى حدوث هبوط كبير في الأداء. بما أنّ هذا الخيار لم يتم استخدامه بعد على جهاز Android
شحن، إذا أردت استخدامه، يُرجى التواصل مع فريق أداء Android لمساعدة
في إثبات صحته.
عند تفعيل sys.use_fifo_ui
، يتتبّع ActivityManager مؤشر UI
وRenderThread (المؤشران الأكثر أهمية لواجهة المستخدم) في التطبيق الذي يستهلك معظم موارد الجهاز ويجعل هذين المؤشران SCHED_FIFO بدلاً من SCHED_OTHER. يزيل هذا الإجراء بشكل فعّال الارتعاش من واجهة المستخدم وRenderThreads. إنّ عمليات التتبّع التي جمعناها باستخدام هذا الخيار سمحت بعرض أوقات التشغيل بالترتيب
بالميكرو ثانية بدلاً من المللي ثانية.
ومع ذلك، بسبب عدم قدرة أداة موازنة الحمولة RT على رصد السعة، حدث انخفاض بنسبة% 30 في أداء بدء تشغيل التطبيق لأنّه سيتم نقل سلسلة مهام واجهة المستخدم المسؤولة عن بدء تشغيل التطبيق من معالج Kryo الذهبي بسرعة 2.1 غيغاهرتز إلى معالج Kryo الفضي بسرعة 1.5 غيغاهرتز. باستخدام أداة توزيع الأحمال للوقت الفعلي (RT) التي تراعي السعة، نلاحظ حصولنا على أداء مماثل في العمليات المجمّعة وانخفاضًا بنسبة تتراوح بين %10 و%15 في أوقات عرض اللقطات في الشريحة المئوية التسعون والتاسع والتسعون في العديد من مقاييس الأداء لواجهة المستخدم.
مقاطعة حركة المرور
بما أنّ منصّات ARM ترسل المقاطعات إلى وحدة المعالجة المركزية 0 فقط تلقائيًا، ننصحك باستخدام أداة موازنة طلب المقاطعة (irqbalance أو msm_irqbalance على منصّات Qualcomm).
أثناء تطوير هواتف Pixel، لاحظنا حدوث تقطُّع في الأداء يمكن أن يُعزى مباشرةً إلى
زيادة عدد عمليات المقاطعة في وحدة المعالجة المركزية (CPU) 0. على سبيل المثال، إذا تم جدولة سلسلة mdss_fb0
المهام على وحدة المعالجة المركزية 0، كان من المرجّح حدوث تقطُّع
بسبب انقطاع يُشغّله العرض على الفور تقريبًا
قبل عملية المسح. سيكون mdss_fb0
في منتصف عمله
مع مهلة زمنية ضيقة جدًا، وبعد ذلك سيفقد بعض الوقت بسبب معالج المقاطعات في MDSS. في البداية، حاولنا حلّ هذه المشكلة من خلال ضبط ملف mdss_fb0 على وحدة المعالجة المركزية (CPU) 1 إلى 3 لتجنُّب التعارض مع المقاطعة، ولكن تبيّن لنا بعد ذلك أنّنا لم نتمكّن من تفعيل msm_irqbalance. بعد تفعيل ملف برمجي
msm_irqbalance، تحسّن الأداء بشكل ملحوظ حتى عندما كان كل من mdss_fb0 و
انقطاع MDSS على وحدة المعالجة المركزية نفسها بسبب انخفاض التعارض من المقاطعات
الأخرى.
يمكن تحديد ذلك في systrace من خلال الاطّلاع على قسم sched بالإضافة إلى قسم irq. يعرض قسم sched ما تم تحديد موعده، ولكن تعني المنطقة المتراكبة في قسم irq أنّ هناك عملية انقطاع يتم تنفيذها خلال ذلك الوقت بدلاً من العملية المُجدوَلة عادةً. إذا لاحظت أجزاء كبيرة من الوقت المستغرَق أثناء المقاطعة، تشمل خياراتك ما يلي:
- تسريع معالِج المقاطعات
- تجنُّب حدوث المقاطعة في المقام الأول
- غيِّر معدّل تكرار المقاطعة ليكون خارج الطور مع العمل العادي الآخر الذي قد يتداخل معه (إذا كان المقاطعة منتظمة).
- اضبط الارتباط بوحدة المعالجة المركزية للمقاطعة مباشرةً ومنع توازنه.
- اضبط الارتباط بوحدة المعالجة المركزية (CPU) للسلسلة التي يتداخل معها المقاطع لتجنب المقاطعة.
- استخدِم أداة موازنة عمليات المقاطعة لنقل عملية المقاطعة إلى وحدة معالجة مركزية أقل انشغالاً.
لا يُنصح عمومًا بضبط الارتباط بوحدة المعالجة المركزية، ولكن يمكن أن يكون مفيدًا في حالات معيّنة. بشكل عام، من الصعب جدًا توقّع حالة النظام في ما يتعلّق بالانقطاعات الأكثر شيوعًا، ولكن إذا كانت لديك مجموعة محدّدة جدًا من الشروط التي تؤدي إلى حدوث انقطاعات معيّنة عندما يكون النظام أكثر تقييدًا من المعتاد (مثل الواقع الافتراضي)، قد يكون تحديد وحدة المعالجة المركزية (CPU) الواضحة هو الحلّ المناسب.
عمليات softirqs الطويلة
أثناء تشغيل إحدى مهام softirq، يتم إيقاف الاستيلاء. ويمكن أيضًا تفعيل مهام softirq في العديد من الأماكن داخل النواة ويمكن تشغيلها داخل عملية مستخدم. إذا كان هناك نشاط كافٍ في softirq، ستتوقف عمليات المستخدم عن تشغيل softirqs، وسيتم تشغيل ksoftirqd لتشغيل softirqs وتوزيع الحمل. لا بأس في ذلك عادةً. ومع ذلك، يمكن أن يتسبب طلب واحد طويل جدًا في حدوث مشاكل في النظام.
تظهر softirqs ضمن قسم irq في التتبُّع، لذا من السهل رصدها إذا كان بالإمكان إعادة إنتاج المشكلة أثناء التتبُّع. بما أنّه يمكن تشغيل مهمة softirq داخل عملية مستخدم، يمكن أن تظهر مهمة softirq سيئة أيضًا كوقت تشغيل إضافي داخل عملية مستخدم بدون سبب واضح. إذا لاحظت ذلك، تحقّق من قسم irq لمعرفة ما إذا كانت هناك أخطاء في softirqs.
برامج التشغيل التي تترك وضع الاستباق أو طلبات المقاطعة (IRQ) غير مفعَّلة لفترة طويلة جدًا
يؤدي إيقاف الاستباق أو المقاطعات لفترة طويلة جدًا (عشرات المللي ثانية) إلى حدوث تقطُّع. يظهر عادةً الأداء غير السلس على شكل سلسلة مهام تصبح قابلة للتنفيذ ولكنها لا تعمل على وحدة معالجة مركزية معيّنة، حتى إذا كانت سلسلة المهام القابلة للتنفيذ مهمة مهمة بأولوية أعلى (أو SCHED_FIFO) من سلسلة المهام الأخرى.
إليك بعض الإرشادات:
- إذا كان الخيط القابل للتنفيذ هو SCHED_FIFO وكان الخيط الجاري هو SCHED_OTHER، يتم إيقاف الاستيلاء أو المقاطعات في الخيط الجاري.
- إذا كان الخيط القابل للتنفيذ له أولوية أعلى بكثير (100) من الخيط الجاري (120)، من المحتمل أن يكون قد تم إيقاف الاستيلاء أو المقاطعات في الخيط الجاري إذا لم يتم تنفيذ الخيط القابل للتنفيذ خلال جولتين من وحدات قياس الوقت.
- إذا كان للسلسلة المُشغَّلة والسلسلة الجارية الأولوية نفسها، من المرجّح أن تكون ميزة الاستيلاء أو المقاطعات غير مفعَّلة في السلسلة الجارية إذا لم يتم تشغيل السلسلة المُشغَّلة خلال 20 ملي ثانية.
يُرجى العِلم أنّ تشغيل معالِج للمقاطعات يمنعك من معالجة المقاطعات الأخرى، ما يؤدي أيضًا إلى إيقاف الاستباق.
هناك خيار آخر لتحديد المناطق التي تتسبب في حدوث المشكلة، وهو استخدام أداة التتبُّع preemptirqsoff (راجِع استخدام ftrace الديناميكي). يمكن أن يوفّر هذا التتبُّع إحصاءات أكثر تفصيلاً عن السبب الأساسي لمنطقة لا يمكن مقاطعتها (مثل أسماء الدوال)، ولكن يتطلّب تفعيله عملاً أكثر تدخلاً. على الرغم من أنّه قد يكون له تأثير أكبر في الأداء، إلا أنّه يستحقّ التجربة بالتأكيد.
الاستخدام غير الصحيح لقوائم العمل
غالبًا ما تحتاج معالجات المقاطعات إلى تنفيذ عمل يمكن تنفيذه خارج سياق المقاطعة، ما يتيح توزيع العمل على سلاسل مهام مختلفة في النواة. قد يلاحظ مطوِّر البرامج المشغِّلة أنّ نواة النظام تتضمّن وظائف مهام غير متزامنة مفيدة جدًا على مستوى النظام تُعرف باسم workqueues، وقد يستخدمها للعمل المرتبط بالمقاطعات.
ومع ذلك، تكون قوائم العمل دائمًا الإجابة الخاطئة لهذه المشكلة لأنّها تكون دائمًا SCHED_OTHER. تقع العديد من عمليات مقاطعة الأجهزة في المسار الحرج للأداء ويجب تنفيذها على الفور. لا يمكن تقديم أي ضمانات بشأن وقت تنفيذ قوائم العمل. في كل مرة رصدنا فيها قائمة عمل في مسار الأداء الحرج، كان ذلك مصدرًا للانقطاعات المفاجئة بغض النظر عن الجهاز. في أجهزة Pixel التي تعمل بمعالج رائد، تبيّن لنا أنّه يمكن تأخير معالجة مهمة واحدة في "قائمة المهام" بحد أقصى 7 مللي ثانية إذا كان الجهاز يعمل بطاقة عالية، وذلك استنادًا إلى سلوك "جدول التشغيل" وغيرها من العمليات التي تعمل على النظام.
بدلاً من "قائمة العمل"، يجب أن تنشئ برامج التشغيل التي تحتاج إلى معالجة عمل مماثل للمقاطعة داخل سلسلة محادثات منفصلة سلسلة محادثات kthread الخاصة بها من النوع SCHED_FIFO. للحصول على مساعدة بشأن تنفيذ ذلك باستخدام وظائف kthread_work، يُرجى الرجوع إلى هذا الإصلاح.
تزايد الطلب على دالة الاستبعاد المتبادل في إطار العمل
يمكن أن يكون التنافس على قفل إطار العمل مصدرًا للانقطاع أو غيرها من مشاكل الأداء. تحدث هذه المشكلة عادةً بسبب قفل ActivityManagerService، ولكن يمكن مشاهدتها في أقفال أخرى أيضًا. على سبيل المثال، يمكن أن يؤثر قفل PowerManagerService في أداء ميزة "إبقاء الشاشة مُضاءة". إذا ظهر لك هذا الخطأ على جهازك، لا يمكن إصلاحه بشكلٍ جيد، لأنّه لا يمكن تحسينه إلا من خلال إجراء تحسينات على الإطار الأساسي. ومع ذلك، إذا كنت تعدّل الرمز البرمجي الذي يتم تشغيله داخل system_server، من الواجب تجنُّب الاحتفاظ بالقيود لفترة طويلة، خاصةً قفل ActivityManagerService.
تزايد الطلب على قفل الشبكة
في السابق، كان لدى أداة الربط قفلًا عالميًا واحدًا. إذا تمّ استبدال سلسلة الرسائل التي تُجري معاملة ربط أثناء الاحتفاظ بالقفل، لا يمكن لأي سلسلة رسائل أخرى تنفيذ معاملة ربط إلى أن تُطلق سلسلة الرسائل الأصلية القفل. هذا أمر سيئ، لأنّ تعارض Binder يمكن أن يؤدي إلى حظر كل شيء في النظام، بما في ذلك إرسال تعديلات واجهة المستخدم إلى الشاشة (تتواصل سلاسل مهام واجهة المستخدم مع SurfaceFlinger من خلال Binder).
يتضمّن الإصدار 6.0 من Android عدة تصحيحات لتحسين هذا السلوك من خلال إيقاف الأولوية أثناء قفل الرابط. ولم يكن هذا الإجراء آمنًا إلا لأنّه من المفترض أن يتم الاحتفاظ بقفل الربط لحظات قليلة من وقت التشغيل الفعلي. أدّى ذلك إلى تحسين الأداء بشكلٍ كبير في الحالات التي لا يكون فيها هناك تنافس، ومنع حدوث التنافس من خلال منع معظم عمليات تبديل جدولة المهام أثناء قفل الرابط. ومع ذلك، تعذّر إيقاف الاستبدال خلال وقت التشغيل بالكامل الذي يُحتفظ فيه بقفل الربط ، ما يعني أنّه تم تفعيل الاستبدال للدوالّ التي يمكنها الدخول في وضع السكون (مثل copy_from_user)، ما قد يؤدي إلى الاستبدال نفسه في الحالة الأصلية. عندما أرسلنا التعديلات إلى فريق التطوير، أخبرونا على الفور أنّ هذه هي أسوأ فكرة في التاريخ. (لقد وافقنا على ذلك، ولكن لم نتمكّن أيضًا من الاعتراض على فعالية التعديلات في منع حدوث التقطُّع).
تعارض fd ضمن عملية
نادرًا ما يحدث ذلك. من المحتمل أنّ هذا ليس سببًا في حدوث التقطُّع.
ومع ذلك، إذا كانت لديك سلاسل محادثات متعددة ضمن عملية تكتب ملف الوصف نفسه، من الممكن أن تلاحظ تعارضًا في هذا الملف، ولكن المرة الوحيدة التي لاحظنا فيها ذلك أثناء بدء تشغيل Pixel هي أثناء اختبار حاولت فيه سلاسل المحادثات ذات الأولوية المنخفضة استخدام كل وقت وحدة المعالجة المركزية أثناء تشغيل سلسلة محادثات واحدة ذات أولوية عالية ضمن العملية نفسها. كانت جميع سلاسل المحادثات تكتب في ملف وصف علامة التتبُّع، وقد يتم حظر سلاسل المحادثات ذات الأولوية العالية في ملف وصف علامة التتبُّع إذا كانت سلسلة محادثات ذات أولوية منخفضة تمتلك قفل ملف الوصف وتم استبدالها بعد ذلك. عندما تم إيقاف التتبُّع من سلاسل المحادثات ذات الأولوية المنخفضة، لم تظهر أي مشكلة في الأداء.
لم نتمكّن من إعادة إنتاج هذا الخطأ في أيّ حالة أخرى، ولكن يُرجى الإشارة إليه كسبب محتمل لمشاكل الأداء أثناء التتبّع.
عمليات الانتقال غير الضرورية إلى وضع السكون في وحدة المعالجة المركزية
عند التعامل مع واجهة برمجة التطبيقات بين العمليات، خاصةً مسارات العمليات المتعددة، من الشائع ملاحظة اختلافات في السلوك التالي أثناء التشغيل:
- يتم تشغيل سلسلة المهام "أ" على وحدة المعالجة المركزية 1.
- سلسلة المحادثات "أ" توقظ سلسلة المحادثات "ب".
- يبدأ تشغيل الخيط "ب" على وحدة المعالجة المركزية 2.
- ينتقل مؤشر التسلسل "أ" إلى وضع السكون على الفور، ليوقظه مؤشر التسلسل "ب" عندما ينتهي مؤشر التسلسل "ب" من عمله الحالي.
من الشائع أن يكون مصدر الوقت المستغرَق بين الخطوة 2 والخطوة 3. إذا كانت وحدة المعالجة المركزية 2 غير نشطة، يجب إعادتها إلى حالة نشطة قبل أن يتم تشغيل الخيط "ب". استنادًا إلى وحدة المعالجة المركزية ومدى التوقف عن العمل، قد يستغرق ذلك عشرات الميكرو ثانية قبل أن يبدأ ملف المعالجة B بالعمل. إذا كان وقت التشغيل الفعلي لكل جانب من جانبَي واجهة IPC قريبًا بدرجة كافية من الوقت المستغرَق في عمليات المعالجة غير الضرورية، يمكن أن ينخفض الأداء العام لمسار الإرسال هذا بشكل كبير بسبب عمليات النقل إلى وضع السكون في وحدة المعالجة المركزية. إنّ أكثر الأماكن شيوعًا التي يواجه فيها نظام Android هذا الخطأ هي في معاملات Binder، والعديد من الخدمات التي تستخدم Binder تنتهي بمظهر يشبه الموقف الموضّح أعلاه.
أولاً، استخدِم الدالة wake_up_interruptible_sync()
في
برامج تشغيل النواة وفعِّلها من أي جدول زمني مخصّص. يجب التعامل مع هذه الخطوة على أنّها
شرط، وليس مجرد تلميح. يستخدم Binder هذا الأسلوب حاليًا، ويساعد كثيرًا في
معاملات Binder المتزامنة لتجنُّب عمليات النقل غير الضرورية لوحدة المعالجة المركزية.
ثانيًا، تأكَّد من أنّ أوقات الانتقال في cpuidle واقعية وأنّ أداة التحكّم في cpuidle تأخذها في الاعتبار بشكلٍ صحيح. إذا كان نظام التشغيل ينتقل بشكل متكرر بين حالة السكون العميق وحالة السكون العادية، لن تتمكن من توفير الطاقة من خلال الانتقال إلى حالة السكون العميق.
التسجيل
لا تُعدّ عملية التسجيل مجانية لعمليات وحدة المعالجة المركزية أو الذاكرة، لذا لا تُرسِل سجلّات غير مرغوب فيها إلى ذاكرة التخزين المؤقت للسجلّ. تتكرّر تكاليف التسجيل في تطبيقك (مباشرةً) وفي برنامج تسجيل الخدمات. عليك إزالة أي سجلات تصحيح أخطاء قبل شحن جهازك.
مشاكل الإدخال والإخراج
إنّ العمليات المتعلقة بوحدات الإدخال والإخراج هي مصادر شائعة للتشويش. إذا وصل خيط إلىملف تم ربطه بالذاكرة ولم تكن الصفحة في ذاكرة التخزين المؤقت للصفحات، سيحدث خطأ ويقرأ الصفحة من القرص. يؤدي ذلك إلى حظر سلسلة المهام (عادةً لمدة تزيد عن 10 مللي ثانية)، وإذا حدث ذلك في المسار الحرج لعرض واجهة المستخدم، قد يؤدي ذلك إلى حدوث تقطُّع. هناك أسباب كثيرة جدًا لعمليات I/O لا يمكن مناقشتها هنا، ولكن عليك التحقّق من المواقع التالية عند محاولة تحسين سلوك I/O:
- PinnerService تمّت إضافة فئة PinnerService في الإصدار 7.0 من Android، وهي تتيح
لإطار العمل قفل بعض الملفات في ذاكرة التخزين المؤقت للصفحة. يؤدي ذلك إلى إزالة الذاكرة ليقوم أي عملية أخرى باستخدامها، ولكن إذا كانت هناك بعض الملفات التي يُعرف مسبقًا أنّه يتم استخدامها بانتظام، قد يكون من الفعال mlock هذه الملفات.
على أجهزة Pixel وNexus 6P التي تعمل بنظام التشغيل Android 7.0، تم قفل أربعة ملفات:- /system/framework/arm64/boot-framework.oat
- /system/framework/oat/arm64/services.odex
- /system/framework/arm64/boot.oat
- /system/framework/arm64/boot-core-libart.oat
- التشفير: سبب آخر محتمل لمشاكل الإدخال/الإخراج تبيّن لنا أنّ التشفير المضمّن يقدّم أفضل أداء مقارنةً بالتشفير المستنِد إلى وحدة المعالجة المركزية أو باستخدام وحدة أجهزة يمكن الوصول إليها من خلال DMA. والأهم من ذلك، أنّه يقلل من التشويش المرتبط بعمليات الإدخال/الإخراج، خاصةً عند مقارنته بعمليات التشفير المستندة إلى وحدة المعالجة المركزية. وبما أنّ عمليات الجلب إلى ذاكرة التخزين المؤقت للصفحة غالبًا ما تكون في
المسار الحرج لعرض واجهة المستخدم، فإنّ التشفير المستنِد إلى وحدة المعالجة المركزية يضيف مزيدًا من
الحمل على وحدة المعالجة المركزية في المسار الحرج، ما يضيف المزيد من التقلّبات أكثر من مجرد جلب الإدخال/الإخراج.
تواجه محرّكات التشفير المستندة إلى الأجهزة وإلى DMA مشكلة مشابهة، لأنّه على kernel إنفاق دورات لإدارة هذا العمل حتى إذا كان هناك عمل مهم آخر متاحًا لتنفيذه. ننصح بشدة أيّ مورّد لنظام التحكّم في حدود الجلسة (SOC) ينشئ أجهزة جديدة بتضمين دعم التشفير المضمّن.
تجميع المهام الصغيرة بشكلٍ مكثّف
توفّر بعض أدوات تحديد الجداول الزمنية إمكانية تجميع المهام الصغيرة في نوى وحدة معالجة مركزية واحدة لمحاولة تقليل استهلاك الطاقة من خلال إبقاء المزيد من وحدات المعالجة المركزية في وضع السكون لفترة أطول. على الرغم من أنّ هذا الإجراء يعمل بشكل جيد في ما يتعلق بمعدل نقل البيانات واستهلاك الطاقة، إلا أنّه يمكن أن يؤدي إلى نتائج كارثية في وقت الاستجابة. هناك العديد من سلاسل المهام التي تستغرق وقتًا قصيرًا في المسار الحرج لعرض واجهة المستخدم والتي يمكن اعتبارها صغيرة. إذا تم تأخُّر سلاسل المهام هذه أثناء نقلها ببطء إلى وحدات المعالجة المركزية الأخرى، سيؤدي ذلك إلى حدوث تقطُّع في الأداء. ننصحك باستخدام ميزة تجميع المهام الصغيرة بحذر شديد.
ذاكرة التخزين المؤقت للصفحة
قد يصبح الجهاز الذي لا يتوفّر فيه ذاكرة مجانية كافية بطيئًا للغاية فجأة أثناء تنفيذ عملية تستغرق وقتًا طويلاً، مثل فتح تطبيق جديد. وقد يكشف أثر التطبيق عن أنّه يتم حظره باستمرار في وحدات الإدخال والإخراج أثناء تنفيذ عملية معيّنة، حتى إذا لم يكن محظورًا في وحدات الإدخال والإخراج في أغلب الأحيان. يشير ذلك عادةً إلى استخدام ذاكرة التخزين المؤقت للصفحة بشكل مفرط، خاصةً على الأجهزة التي تحتوي على ذاكرة أقل.
وإحدى الطرق لتحديد ذلك هي إجراء تتبع للنظام باستخدام علامة pagecache و
إدخال هذا التتبّع إلى النص البرمجي على الرابط
system/extras/pagecache/pagecache.py
. يترجم ملف pagecache.py
الطلبات الفردية لربط الملفات في ذاكرة التخزين المؤقت للصفحة إلى إحصاءات إجمالية لكل ملف. إذا تبيّن لك أنّه تم قراءة عدد أكبر من البايتات من ملف معيّن مقارنةً بإجمالي
حجم هذا الملف على القرص، يعني ذلك أنّ ذاكرة التخزين المؤقت للصفحة تواجه مشكلة.
ويعني ذلك أنّ مجموعة العمل المطلوبة من خلال حمولتك (عادةً تطبيق واحد بالإضافة إلى system_server) أكبر من مقدار الذاكرة المتاحة لمخزّن التخزين المؤقت للصفحة على جهازك. نتيجةً لذلك، عندما يحصل جزء من عبء العمل على البيانات التي يحتاجها في ذاكرة التخزين المؤقت للصفحة، سيتم إخراج جزء آخر سيتم استخدامه في المستقبل القريب ويجب استرجاعه مرة أخرى، مما يؤدي إلى تكرار المشكلة إلى أن تكتمل عملية التحميل. هذا هو السبب العميق لمشاكل الأداء عند عدم توفّر ذاكرة كافية على الجهاز.
لا تتوفّر طريقة أكيدة لحلّ مشكلة استهلاك ذاكرة التخزين المؤقت للصفحة بشكل كبير، ولكن هناك بعض الطرق التي يمكنك تجربتها لتحسين هذه المشكلة على جهاز معيّن.
- استخدام ذاكرة أقل في العمليات الدائمة كلما قلّت الذاكرة التي تستخدمها العمليات الدائمة، زادت الذاكرة المتوفّرة للتطبيقات وذاكرة التخزين المؤقت للصفحات.
- تحقَّق من عمليات الاستبعاد التي أجريتها على جهازك للتأكّد من عدم إزالة ذاكرة من نظام التشغيل بدون داعٍ. لاحظنا حالات تم فيها عن طريق الخطأ ترك مساحات مخصّصة لإصلاح الأخطاء في إعدادات نواة التشغيل، مما أدّى إلى استخدام عشرات الميغابايت من الذاكرة. ويمكن أن يحدِّد ذلك الفرق بين الوصول إلى ذاكرة التخزين المؤقت للصفحة بشكلٍ كبير وعدم الوصول إليها، خاصةً على الأجهزة التي تحتوي على كمية أقل من الذاكرة.
- إذا لاحظت زيادة في استخدام ذاكرة التخزين المؤقت للصفحات في system_server على الملفات المهمة، ننصح بتثبيت هذه الملفات. سيؤدي ذلك إلى زيادة الضغط على الذاكرة في مكان آخر، ولكن قد يغيّر السلوك بما يكفي لتجنُّب حدوث تداخل.
- أعِد ضبط lowmemorykiller لمحاولة إبقاء المزيد من الذاكرة خالية. تستند حدود lowmemorykiller إلى كل من الذاكرة الفارغة المطلقة وذاكرة التخزين المؤقت للصفحات، لذا قد يؤدي زيادة الحدّ الذي يتم عنده إنهاء العمليات عند مستوى oom_adj معيّن إلى تحسين الأداء على حساب زيادة عمليات إنهاء التطبيقات في الخلفية.
- جرِّب استخدام ذاكرة ZRAM. نستخدم تقنية ZRAM على هواتف Pixel، على الرغم من أنّها تتضمّن ذاكرة وصول عشوائي بسعة 4 غيغابايت، لأنّها قد تساعد في معالجة الصفحات غير النظيفة التي نادرًا ما يتم استخدامها.