مجموعات الذاكرة

توضّح هذه الصفحة بنى البيانات والطرق المستخدَمة لنقل مخازن مؤقتة للعوامل بشكل فعّال بين برنامج التشغيل والإطار.

عند تجميع النموذج، يوفّر إطار العمل قيم المعامِلات الثابتة إلى برنامج التشغيل. استنادًا إلى مدة بقاء المعامِل الثابت، يتم تخزين قيمه إما في متّجه HIDL أو في مجموعة ذاكرة مشتركة.

  • إذا كانت مدة البقاء CONSTANT_COPY، تكون القيم في الحقل operandValues ضمن بنية النموذج. بما أنّه يتم نسخ القيم في متجه HIDL أثناء الاتصال بين العمليات (IPC)، لا يتم استخدام هذا المتجه عادةً إلا للاحتفاظ بكمية صغيرة من البيانات، مثل المعامِلات العددية (على سبيل المثال، عدد التنشيط في ADD) ومعلمات الموتر الصغيرة (على سبيل المثال، موتر الشكل في RESHAPE).
  • إذا كانت مدة البقاء CONSTANT_REFERENCE، تكون القيم في الحقل pools ضمن بنية النموذج. يتم تكرار معرّفات مجموعات الذاكرة المشتركة فقط أثناء عملية الاتصال بين العمليات (IPC) بدلاً من نسخ القيم الأولية. لذلك، يكون من الأجدى الاحتفاظ بكمية كبيرة من البيانات (مثل مَعلمات الوزن في الالتفافات) باستخدام مجموعات الذاكرة المشتركة بدلاً من متجهات HIDL.

عند تنفيذ النموذج، يوفّر إطار العمل مخازن مؤقتة لمعامِلات الإدخال والإخراج إلى برنامج التشغيل. على عكس الثوابت في وقت الترجمة البرمجية التي قد يتم إرسالها في متجه HIDL، يتم دائمًا نقل بيانات الإدخال والإخراج الخاصة بعملية التنفيذ من خلال مجموعة من مجموعات الذاكرة.

يُستخدَم نوع بيانات HIDL hidl_memory في كل من عملية التجميع والتنفيذ لتمثيل مجموعة من الذاكرة المشتركة غير المرتبطة. على برنامج التشغيل ربط الذاكرة وفقًا لذلك لجعلها قابلة للاستخدام استنادًا إلى اسم نوع البيانات hidl_memory. أسماء الذاكرة المتوافقة هي:

  • ashmem: الذاكرة المشترَكة في Android لمزيد من التفاصيل، يُرجى الاطّلاع على الذاكرة.
  • mmap_fd: ذاكرة مشتركة يتم الاحتفاظ بنسخة احتياطية منها في واصف ملف من خلال mmap.
  • hardware_buffer_blob: ذاكرة مشتركة مستندة إلى AHardwareBuffer بالتنسيق AHARDWARE_BUFFER_FORMAT_BLOB تتوفّر هذه الميزة من خلال الإصدار 1.2 من طبقة تجريد الأجهزة (HAL) الخاصة بالشبكات العصبية (NN). لمزيد من التفاصيل، يُرجى الاطّلاع على AHardwareBuffer.
  • hardware_buffer: ذاكرة مشتركة تستند إلى AHardwareBuffer عام لا يستخدم التنسيق AHARDWARE_BUFFER_FORMAT_BLOB. لا يتوفّر مخزن مؤقت للأجهزة في وضع غير BLOB إلا عند تنفيذ النماذج.ويتوفّر هذا المخزن بدءًا من الإصدار 1.2 من طبقة HAL الخاصة بشبكة NN. لمزيد من التفاصيل، يُرجى الاطّلاع على AHardwareBuffer.

بدءًا من NN HAL 1.3، تتيح واجهة برمجة التطبيقات NNAPI نطاقات الذاكرة التي توفّر واجهات برنامج تخصيص الذاكرة للمخازن المؤقتة التي يديرها برنامج التشغيل. يمكن أيضًا استخدام المخازن المؤقتة التي يديرها برنامج التشغيل كمدخلات أو مخرجات للتنفيذ. لمزيد من التفاصيل، يُرجى الاطّلاع على نطاقات الذاكرة.

يجب أن تتيح برامج تشغيل NNAPI ربط أسماء الذاكرة ashmem وmmap_fd. بدءًا من الإصدار 1.3 من NN HAL، يجب أن تتوافق برامج التشغيل أيضًا مع ربط hardware_buffer_blob. إنّ إتاحة وضع hardware_buffer العام غير الخاص بـ BLOB ونطاقات الذاكرة أمر اختياري.

AHardwareBuffer

‫HardwareBuffer هو نوع من الذاكرة المشتركة التي تتضمّن مخزنًا مؤقتًا من Gralloc. في نظام التشغيل Android 10، تتيح واجهة برمجة التطبيقات Neural Networks API (NNAPI) استخدام AHardwareBuffer، ما يسمح لبرنامج التشغيل بتنفيذ العمليات بدون نسخ البيانات، ما يؤدي إلى تحسين الأداء واستهلاك الطاقة للتطبيقات. على سبيل المثال، يمكن لمجموعة من طبقات HAL الخاصة بالكاميرا تمرير عناصر AHardwareBuffer إلى NNAPI لأحمال عمل تعلُّم الآلة باستخدام مقابض AHardwareBuffer التي تم إنشاؤها بواسطة واجهات برمجة تطبيقات NDK الخاصة بالكاميرا وNDK الخاصة بالوسائط. لمزيد من المعلومات، يُرجى الاطّلاع على ANeuralNetworksMemory_createFromAHardwareBuffer.

يتم تمرير عناصر AHardwareBuffer المستخدَمة في NNAPI إلى برنامج التشغيل من خلال بنية hidl_memory تُسمى إما hardware_buffer أو hardware_buffer_blob. لا يمثّل بنية hidl_memory hardware_buffer_blob سوى عناصر AHardwareBuffer بالتنسيق AHARDWAREBUFFER_FORMAT_BLOB.

يتم ترميز المعلومات المطلوبة من خلال إطار العمل في الحقل hidl_handle للبنية hidl_memory. يحتوي الحقل hidl_handle على native_handle، الذي يشفّر جميع البيانات الوصفية المطلوبة حول AHardwareBuffer أو مخزن Gralloc المؤقت.

يجب أن يفكّ برنامج التشغيل ترميز الحقل hidl_handle المقدَّم بشكل صحيح وأن يصل إلى الذاكرة الموضّحة في hidl_handle. عند استدعاء الطريقة getSupportedOperations_1_2 أو getSupportedOperations_1_1 أو getSupportedOperations، يجب أن يرصد برنامج التشغيل ما إذا كان بإمكانه فك ترميز hidl_handle المقدَّم والوصول إلى الذاكرة الموضّحة من خلال hidl_handle. يجب أن يتعذّر إعداد النموذج إذا لم يكن الحقل hidl_handle المستخدَم في معامل ثابت متوافقًا. يجب أن يتعذّر التنفيذ إذا كان الحقل hidl_handle المستخدَم كعامل تشغيل إدخال أو إخراج للتنفيذ غير متوافق. يُنصح بأن يعرض برنامج التشغيل رمز الخطأ GENERAL_FAILURE في حال تعذّر إعداد النموذج أو تنفيذه.

نطاقات الذكريات

بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل Android 11 أو إصدار أحدث، تتوافق واجهة برمجة التطبيقات NNAPI مع نطاقات الذاكرة التي توفّر واجهات تخصيص للمخازن المؤقتة التي يديرها برنامج التشغيل. يتيح ذلك تمرير الذاكرات الأصلية للجهاز بين عمليات التنفيذ، ما يؤدي إلى منع نسخ البيانات وتحويلها بشكل غير ضروري بين عمليات التنفيذ المتتالية على برنامج التشغيل نفسه. يوضّح الشكل 1 هذا المسار.

تدفّق بيانات المخزن المؤقت مع نطاقات الذاكرة وبدونها

الشكل 1. تخزين البيانات مؤقتًا باستخدام نطاقات الذاكرة

ميزة "نطاق الذاكرة" مخصّصة للموترات التي تكون داخلية في معظم الأحيان بالنسبة إلى برنامج التشغيل ولا تحتاج إلى الوصول المتكرّر إليها من جهة العميل. وتشمل أمثلة هذه الموترات موترات الحالة في النماذج التسلسلية. بالنسبة إلى الموترات التي تحتاج إلى الوصول إلى وحدة المعالجة المركزية بشكل متكرر من جهة العميل، من الأفضل استخدام مجموعات ذاكرة مشتركة.

لإتاحة ميزة نطاق الذاكرة، نفِّذ IDevice::allocate للسماح للإطار بطلب تخصيص المخزن المؤقت الذي يديره برنامج التشغيل. أثناء عملية التخصيص، يوفّر إطار العمل الخصائص وأنماط الاستخدام التالية للمخزن المؤقت:

  • تصف BufferDesc السمات المطلوبة للمخزن المؤقت.
  • تصف السمة BufferRole نمط الاستخدام المحتمل للمخزن المؤقت كمدخل أو مخرج لنموذج مُعدّ. يمكن تحديد أدوار متعددة أثناء عملية تخصيص المخزن المؤقت، ولا يمكن استخدام المخزن المؤقت المخصّص إلا للأدوار المحدّدة.

المخزن المؤقت المخصّص هو جزء داخلي من برنامج التشغيل. يمكن للسائق اختيار أي موقع مؤقت أو تخطيط بيانات. عند تخصيص المخزن المؤقت بنجاح، يمكن لعميل برنامج التشغيل الرجوع إلى المخزن المؤقت أو التفاعل معه باستخدام الرمز المميز الذي تم عرضه أو عنصر IBuffer.

يتم توفير الرمز المميّز من IDevice::allocate عند الإشارة إلى المخزن المؤقت كأحد عناصر MemoryPool في بنية Request لأحد عمليات التنفيذ. ولمنع إحدى العمليات من محاولة الوصول إلى المخزن المؤقت المخصّص في عملية أخرى، يجب أن يطبّق برنامج التشغيل عملية التحقّق المناسبة عند كل استخدام للمخزن المؤقت. على برنامج التشغيل التحقّق من أنّ استخدام المخزن المؤقت هو أحد الأدوار BufferRole المقدَّمة أثناء التخصيص، ويجب أن يتعذّر التنفيذ على الفور إذا كان الاستخدام غير قانوني.

يُستخدَم الكائن IBuffer لنسخ الذاكرة بشكل صريح. في بعض الحالات، يجب أن يبدأ عميل برنامج التشغيل المخزن المؤقت الذي يديره برنامج التشغيل من مجموعة ذاكرة مشتركة أو ينسخ المخزن المؤقت إلى مجموعة ذاكرة مشتركة. تشمل الأمثلة على حالات الاستخدام ما يلي:

  • إعداد موتر الحالة
  • تخزين النتائج الوسيطة مؤقتًا
  • التنفيذ الاحتياطي على وحدة المعالجة المركزية

لدعم حالات الاستخدام هذه، يجب أن ينفّذ برنامج التشغيل IBuffer::copyTo وIBuffer::copyFrom مع ashmem وmmap_fd وhardware_buffer_blob إذا كان يتيح تخصيص نطاق الذاكرة. يُعدّ توفير برنامج التشغيل لوضع غير BLOB أمرًا اختياريًا hardware_buffer.

أثناء عملية تخصيص المخزن المؤقت، يمكن استنتاج أبعاد المخزن المؤقت من معاملات النموذج المقابلة لجميع الأدوار المحددة بواسطة BufferRole، ومن الأبعاد المقدَّمة في BufferDesc. مع دمج كل المعلومات المتعلقة بالأبعاد، قد يحتوي المخزن المؤقت على أبعاد أو ترتيب غير معروفَين. في هذه الحالة، تكون المخزن المؤقت في حالة مرنة حيث يتم تثبيت الأبعاد عند استخدامها كمدخل للنموذج وفي حالة ديناميكية عند استخدامها كمخرج للنموذج. يمكن استخدام المخزن المؤقت نفسه مع أشكال مختلفة من النواتج في عمليات التنفيذ المختلفة، ويجب أن يتعامل برنامج التشغيل مع تغيير حجم المخزن المؤقت بشكل صحيح.

نطاق الذاكرة هو ميزة اختيارية. يمكن أن يحدّد برنامج التشغيل أنّه لا يمكنه تنفيذ طلب تخصيص معيّن لعدة أسباب. مثلاً:

  • يحتوي المخزن المؤقت المطلوب على حجم ديناميكي.
  • يواجه برنامج التشغيل قيودًا على الذاكرة تمنعه من التعامل مع المخازن المؤقتة الكبيرة.

من الممكن أن تقرأ عدة سلاسل محادثات مختلفة من المخزن المؤقت الذي تديره برامج التشغيل بشكل متزامن. لا يمكن تحديد ما سيحدث عند الوصول إلى المخزن المؤقت في الوقت نفسه للكتابة أو القراءة/الكتابة، ولكن يجب ألا يؤدي ذلك إلى تعطُّل خدمة برنامج التشغيل أو حظر المتصل إلى أجل غير مسمى. يمكن أن يعرض برنامج التشغيل خطأً أو يترك محتوى المخزن المؤقت في حالة غير محددة.