تصف هذه الصفحة بُنى البيانات والطرق المستخدَمة لنقل مخازن المعامِلات بكفاءة بين برنامج التشغيل والإطار.
أثناء تجميع النموذج، يقدّم الإطار قيم المعامِلات الثابتة إلى برنامج التشغيل. اعتمادًا على مدة بقاء المعامِل الثابت، يتم تخزين قيمه إما في متّجه HIDL أو في مجموعة ذاكرة مشترَكة.
- إذا كانت مدة البقاء
CONSTANT_COPY، يتم تخزين القيم في الحقلoperandValuesلبنية النموذج. بما أنّ القيم في متّجه HIDL يتم نسخها أثناء التواصل بين العمليات (IPC)، لا يتم استخدام هذا المتّجه عادةً إلا لتخزين كمية صغيرة من البيانات، مثل المعامِلات العددية (على سبيل المثال، المعامِل العددي للتفعيل فيADD) ومَعلمات الموتر الصغيرة (على سبيل المثال، موتر الشكل فيRESHAPE). - إذا كانت مدة البقاء
CONSTANT_REFERENCE، يتم تخزين القيم في الحقلpoolsلبنية النموذج. أثناء التواصل بين العمليات، يتم تكرار مقابض مجموعات الذاكرة المشترَكة فقط بدلاً من نسخ القيم الأولية. لذلك، من الأفضل تخزين كمية كبيرة من البيانات (على سبيل المثال، مَعلمات الأوزان في الالتفافات) باستخدام مجموعات الذاكرة المشترَكة بدلاً من متّجهات HIDL.
أثناء تنفيذ النموذج، يقدّم إطار العمل مخازن مؤقتة لمعامِلات الإدخال والإخراج إلى برنامج التشغيل. على عكس الثوابت التي يتم إرسالها أثناء التجميع في متّجه HIDL، يتم دائمًا نقل بيانات الإدخال والإخراج لعملية التنفيذ من خلال مجموعة من مجموعات الذاكرة.
يتم استخدام نوع بيانات HIDL hidl_memory في كلٍّ من التجميع والتنفيذ لتمثيل مجموعة ذاكرة مشترَكة غير مُعدّة. على برنامج التشغيل إعداد الذاكرة وفقًا لذلك لجعلها قابلة للاستخدام استنادًا إلى اسم نوع بيانات hidl_memory.
في ما يلي أسماء الذاكرة المتوافقة:
ashmem: ذاكرة Android المشترَكة. لمزيد من التفاصيل، يُرجى الاطّلاع على الذاكرة.mmap_fd: ذاكرة مشترَكة تستند إلى واصف ملف من خلالmmap.hardware_buffer_blob: ذاكرة مشترَكة تستند إلى AHardwareBuffer بالتنسيقAHARDWARE_BUFFER_FORMAT_BLOB. تتوفّر هذه الذاكرة بدءًا من Neural Networks (NN) HAL 1.2. لمزيد من التفاصيل، يُرجى الاطّلاع على AHardwareBuffer.hardware_buffer: ذاكرة مشترَكة تستند إلى AHardwareBuffer عام لا يستخدم التنسيقAHARDWARE_BUFFER_FORMAT_BLOB. لا تتوفّر ذاكرة الأجهزة غير المستندة إلى BLOB إلا أثناء تنفيذ النموذج، بدءًا من NN HAL 1.2. لمزيد من التفاصيل، يُرجى الاطّلاع على AHardwareBuffer.
بدءًا من NN HAL 1.3، تتيح NNAPI نطاقات الذاكرة التي توفّر واجهات تخصيص للمخازن التي يديرها برنامج التشغيل. يمكن أيضًا استخدام المخازن التي يديرها برنامج التشغيل كمدخلات أو مخرجات للتنفيذ. لمزيد من التفاصيل، يُرجى الاطّلاع على نطاقات الذاكرة.
على برامج تشغيل NNAPI أن تتيح إعداد أسماء الذاكرة ashmem وmmap_fd. بدءًا من NN HAL 1.3، على برامج التشغيل أيضًا أن تتيح إعداد hardware_buffer_blob. إنّ إتاحة hardware_buffer العام غير المستند إلى BLOB ونطاقات الذاكرة هي ميزة اختيارية.
AHardwareBuffer
AHardwareBuffer هو نوع من الذاكرة المشترَكة التي تغلّف مخزن
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 إذا كان يتيح تخصيص نطاق الذاكرة. إنّ إتاحة hardware_buffer غير المستند إلى BLOB هي ميزة اختيارية لبرنامج التشغيل.
أثناء تخصيص المخزن، يمكن استنتاج أبعاد المخزن من معامِلات النموذج المقابلة لجميع الأدوار التي يحدّدها BufferRole والأبعاد المقدَّمة في BufferDesc. بعد دمج جميع معلومات الأبعاد، قد يكون للمخزن أبعاد أو رتبة غير معروفة. في هذه الحالة، يكون المخزن المؤقت في حالة مرنة حيث يتم تحديد الأبعاد عند استخدامه كمدخل للنموذج وفي حالة ديناميكية عند استخدامه كمخرجات النموذج. يمكن استخدام المخزن نفسه بأشكال مختلفة للمخرجات في عمليات تنفيذ مختلفة، وعلى برنامج التشغيل التعامل مع تغيير حجم المخزن بشكل صحيح.
نطاق الذاكرة هو ميزة اختيارية. يمكن لبرنامج التشغيل تحديد أنّه لا يمكنه إتاحة طلب تخصيص معيّن لعدد من الأسباب. على سبيل المثال:
- للمخزن المطلوب حجم ديناميكي.
- يواجه برنامج التشغيل قيودًا على الذاكرة تمنعه من التعامل مع المخازن الكبيرة.
يمكن لعدة سلاسل محادثات مختلفة القراءة من المخزن الذي يديره برنامج التشغيل في الوقت نفسه. إنّ الوصول إلى المخزن في الوقت نفسه للكتابة أو القراءة/الكتابة غير محدّد، ولكن يجب ألا يؤدي ذلك إلى تعطُّل خدمة برنامج التشغيل أو حظر المتصل إلى أجل غير مسمّى. يمكن لبرنامج التشغيل عرض خطأ أو ترك محتوى المخزن في حالة غير محدّدة.