توضّح هذه المقالة كيفية محاولة نظام الصوت في Android تجنُّب عكس الأولوية، وتسلّط الضوء على الأساليب التي يمكنك استخدامها أيضًا.
قد تكون هذه التقنيات مفيدة لمطوّري التطبيقات الصوتية العالية الأداء ومصنّعي الأجهزة الأصليين ومقدّمي وحدات المعالجة المركزية (SoC) الذين ينفذون واجهة برمجة التطبيقات لمعالجة الصعوبات المتعلّقة بالصوت (HAL). يُرجى العِلم أنّه لا يمكن ضمان عدم حدوث مشاكل أو أعطال أخرى عند استخدام هذه الأساليب، خاصةً إذا تم استخدامها خارج سياق الصوت. قد تختلف النتائج، وعليك إجراء تقييمك واختبارك الخاصَّين.
الخلفية
نعمل على إعادة تصميم خادم الصوت AudioFlinger وتنفيذ العميل AudioTrack/AudioRecord في Android لتقليل وقت الاستجابة. بدأ هذا العمل في الإصدار 4.1 من Android، واستمر مع إجراء المزيد من التحسينات في الإصدارات 4.2 و4.3 و4.4 و5.0.
لتحقيق هذا الانخفاض في وقت الاستجابة، كان من الضروري إجراء العديد من التغييرات في جميع أنحاء النظام. ومن بين التغييرات العميقة التي أجريناها، منح موارد وحدة المعالجة المركزية إلى سلاسل المهام المُهمّة من حيث الوقت، وذلك من خلال سياسة جدولة أكثر قابلية للتنبؤ. من خلال تحديد الجداول الزمنية بشكل موثوق، يمكن تقليل أحجام وعدد وحدات التخزين المؤقت للصوت مع الاستمرار في تجنُّب النقص أو الزيادة في المساحة.
انعكاس الأولوية
قلب الأولويات: هو أحد حالات الفشل الكلاسيكية للأنظمة المستندة إلى الوقت الفعلي، ويحدث عندما يتم حظر مهمة ذات أولوية أعلى لفترة غير محدودة في انتظار مهمة ذات أولوية أقل لتحرير مورد، مثل (حالة مشترَكة محمية من قِبل) متغيّر استبعاد متبادل.
في نظام الصوت، يظهر عادةً انعكاس الأولوية على شكل عطل (نقرة أو صوت عالٍ أو انقطاع) صوت متكرّر عند استخدام وحدات التخزين الدائرية أو تأخّر في الاستجابة لأمر.
من الحلول الشائعة لعكس الأولوية زيادة أحجام التخزين المؤقت للصوت. ومع ذلك، تؤدي هذه الطريقة إلى زيادة وقت الاستجابة وتؤدي إلى إخفاء المشكلة بدلاً من حلّها. من الأفضل فهم عملية قلب الأولوية وعدم السماح بها، كما هو موضّح أدناه.
في عملية تنفيذ الصوت على Android، من المرجّح أن يحدث انعكاس الأولوية في هذه الأماكن. لذا، عليك التركيز على ما يلي:
- بين سلسلة المخطّط العادي وسلسلة المخطّط السريع في AudioFlinger
- بين سلسلة محادثات طلب الاستدعاء للتطبيق الخاصة بمسار صوتي سريع وسلسلة محادثات أداة المزج السريع (لكلتا السلاسل أولوية مرتفعة، ولكنهما مختلفتان قليلاً في مستوياتهم)
- بين سلسلة محادثات ردّ الاتصال بالتطبيق لسلسلة تسجيل صوتي سريعة وسلسلة تسجيل سريع (مشابهة للسابقة)
- ضمن تنفيذ "طبقة تجريد الأجهزة الصوتية" (HAL)، مثلاً لاستخدامها في الاتصال الهاتفي أو إلغاء الصدى
- ضمن برنامج تشغيل الصوت في النواة
- بين سلسلة محادثات طلب معاودة الاتصال في AudioTrack أو AudioRecord وسلاسل محادثات التطبيق الأخرى (هذه العملية خارج نطاق سيطرتنا)
الحلول الشائعة
تشمل الحلول المعتادة ما يلي:
- إيقاف المقاطعات
- عمليات قفل المهام المشترَكة لميزة اكتساب الأولوية
لا يمكن إيقاف عمليات المقاطعة في مساحة مستخدم Linux، ولا يعمل هذا الإجراء مع وحدات المعالجة المتعدّدة المكافئة (SMP).
لا يتم استخدام ميزة اكتساب الأولوية futexes (ملفات قفل سريعة في مساحة المستخدم) في نظام الصوت لأنّها ثقيلة نسبيًا، ولأنّها تعتمد على برنامج موثوق.
التقنيات المستخدَمة في Android
بدأت التجارب باستخدام "محاولة القفل" والقفل مع مهلة. هذه هي الصيغ غير المحظورة والمحظورة ذات الحدود لعملية قفل mutex. لقد عملت وظيفتا قفل القفل مع مهلة بشكل جيد إلى حدٍ ما، ولكن كانتا عرضة لبعض أوضاع الفشل غير الواضحة: لم يكن هناك ضمان بأنّه يمكن للخادم الوصول إلى الحالة المشتركة إذا كان العميل مشغولاً، وقد يكون المهلة التراكمية طويلة جدًا إذا كانت هناك سلسلة طويلة من عمليات القفل غير ذات الصلة التي انتهت مهلة كلّها.
نستخدم أيضًا العمليات الذرية مثل:
- زيادة
- "أو" على مستوى البت
- "و" على مستوى الوحدات البِنيوية
تعرض كل هذه الوظائف القيمة السابقة وتشمل موانع SMP اللازمة. ويتمثل عيوبها في أنّها قد تتطلّب عمليات إعادة محاولة غير محدودة. تبيّن لنا من خلال التجربة أنّ عمليات إعادة المحاولة لا تتسبّب في أي مشكلة.
ملاحظة: يُعرف أنّ العمليات الذرية وتفاعلاتها مع حواجز الذاكرة يُساء فهمها ويُساء استخدامها. لقد أدرجنا هذه الطرق هنا من أجل الاكتمال، ولكن ننصحك أيضًا بقراءة المقالة مقدّمة عن "إدارة الموافقة" على Android لمزيد من المعلومات.
لا تزال معظم الأدوات المذكورة أعلاه متوفّرة لدينا ونستخدمها، وقد أضفنا مؤخرًا هذه الأساليب:
- استخدِم قوائم الانتظار بأولوية الوصول إلى الذاكرة أولاً غير المحظورة للقراءة والكتابة.
- حاوِل نسخ الحالة بدلاً من مشاركة الحالة بين الوحدات ذات الأولوية العالية والوحدات ذات الأولوية المنخفضة.
- عندما يكون من الضروري مشاركة الحالة، يجب حصرها في الحجم الأقصى للكلمة التي يمكن الوصول إليها بشكل موحّد في عملية باستخدام ناقل واحد بدون عمليات إعادة محاولة.
- بالنسبة إلى الحالة المعقدة التي تتألف من عدة كلمات، استخدِم قائمة انتظار للحالات. إنّ "قائمة انتظار الحالة" هي في الأساس مجرد قائمة انتظار FIFO واحدة للقارئ والكاتب غير المحظورة، وتُستخدَم للحالة بدلاً من البيانات، باستثناء أنّ الكاتب يدمج عمليات الإرسال المجاورة في عملية إرسال واحدة.
- انتبه إلى حواجز الذاكرة لضمان صحة SMP.
- الثقة، ولكن التحقّق عند مشاركة الحالة بين العمليات، لاتفترض أنّ الحالة صحيحة. على سبيل المثال، تأكَّد من أنّ الفهارس ضمن الحدود المسموح بها. ولا يلزم إجراء هذا التحقّق بين سلاسل المحادثات في العملية نفسها، أو بين العمليات المتبادلة الثقة (التي تستخدم عادةً المعرّف الفريد نفسه). ولا يلزم أيضًا استخدامها مع البيانات المشترَكة، مثل الملفات الصوتية بتنسيق PCM التي لا يؤثر تلفها في النتيجة النهائية.
الخوارزميات غير المحظورة
الخوارزميات غير المحظورة كانت موضوعًا للعديد من الدراسات الحديثة. ولكن باستثناء قوائم الانتظار FIFO ذات القارئ والكاتب الواحدَين، تبيّن لنا أنّها معقّدة وعرضة للخطأ.
اعتبارًا من الإصدار 4.2 من نظام التشغيل Android، يمكنك العثور على فئات القراءة/الكتابة غير المحظورة الواحدة في المواقع التالية:
- frameworks/av/include/media/nbaio/
- frameworks/av/media/libnbaio/
- frameworks/av/services/audioflinger/StateQueue*
تم تصميم هذه الوظائف خصيصًا لخدمة AudioFlinger، وهي ليست مخصّصة للأغراض العامة. تشتهر الخوارزميات غير المحظورة بصعوبة تصحيح أخطاءها. يمكنك الاطّلاع على هذا الرمز كنموذج. يُرجى العِلم أنّه قد تكون هناك أخطاء، ولا يمكن ضمان أن تكون الفئات مناسبة لأغراض أخرى.
بالنسبة إلى المطوّرين، يجب تعديل بعض نماذج رموز تطبيق OpenSL ES لمحاولة استخدام خوارزميات غير محظورة أو الإشارة إلى مكتبة مفتوحة المصدر غير مخصّصة لنظام التشغيل Android.
لقد نشرنا مثالاً على تنفيذ FIFO غير المحظور المصمّم خصيصًا ل
رمز التطبيق. اطّلِع على هذه الملفات في دليل مصدر النظام الأساسي
frameworks/av/audio_utils
:
الأدوات
حسب أفضل تقديراتنا، لا تتوفّر أدوات تلقائية لتحديد انعكاس الأولوية، خاصةً قبل حدوثه. يمكن لبعض
أدوات البحث في تحليل الرموز الثابتة العثور على ملفّات برمجية مهمة
مُعكوسة إذا كان بإمكانها الوصول إلى قاعدة البيانات بالكامل. بالطبع، إذا كان هناك
رمز مستخدم عشوائي (كما هو الحال هنا للتطبيق)
أو قاعدة بيانات كبيرة (مثل نواة Linux وبرامج تشغيل الأجهزة)،
قد يكون التحليل الثابت غير عملي. من المهم جدًا قراءة الرمز بعناية وفهم النظام والتفاعلات بالكامل. إنّ أدوات مثل
systrace
و
ps -t -p
مفيدة لمعرفة حدوث انعكاس الأولوية بعد حدوثه، ولكنّها
لا تُعلمك مسبقًا.
كلمة أخيرة
بعد كل هذه المناقشة، لا تخف من استخدام آليات قفل المهام المتعدّدة. إنّ قفلَي المنع هما صديقان لك في الاستخدام العادي، عند استخدامهما وتنفيذهما بشكل صحيح في حالات الاستخدام العادية غير الحرجة من حيث الوقت. ولكن بين المهام ذات الأولوية العالية والمهام ذات الأولوية المنخفضة وفي الأنظمة الحسّاسة للوقت، من المرجّح أن تتسبّب أدوات حظر المهام في مشاكل.