توضّح هذه المقالة كيفية محاولة نظام الصوت في 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) غير المحظورة للقراءة والكتابة.
- حاوِل نسخ الحالة بدلاً من مشاركة الحالة بين الوحدات ذات الأولوية العالية والوحدات ذات الأولوية المنخفضة.
- عندما يكون من الضروري مشاركة الحالة، يجب حصرها في الحجم الأقصى للكلمة التي يمكن الوصول إليها بشكل موحّد في عملية باستخدام ناقل واحد بدون عمليات إعادة محاولة.
- بالنسبة إلى الحالة المعقدة التي تتألف من عدة كلمات، استخدِم قائمة انتظار للحالات. إنّ "قائمة انتظار الحالة" هي في الأساس مجرد قائمة انتظار 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
مفيدة لمعرفة حدوث انعكاس الأولوية بعد حدوثه، ولكنّها
لا تُعلمك مسبقًا.
كلمة أخيرة
بعد كل هذه المناقشة، لا تخف من استخدام آليات قفل المهام المتعدّدة. إنّ قفلَي المنع هما صديقان لك في الاستخدام العادي، عند استخدامهما وتنفيذهما بشكل صحيح في حالات الاستخدام العادية غير الحرجة من حيث الوقت. ولكن بين المهام ذات الأولوية العالية والمهام ذات الأولوية المنخفضة وفي الأنظمة الحسّاسة للوقت، من المرجّح أن تتسبّب أدوات حظر المهام في مشاكل.