عمليات تنفيذ متسلسلة وقوائم انتظار سريعة للرسائل

تقدم الشبكات العصبية HAL 1.2 مفهوم عمليات تنفيذ الصور المتسلسلة. صور متسلسلة عمليات التنفيذ هي سلسلة من عمليات التنفيذ لنفس النموذج المعد والتي تحدث في التتابع السريع، مثل تلك التي تعمل على إطارات التقاط الكاميرا أو مقطع صوتي متتالي العينات. يُستخدم كائن الصور المتسلسلة للتحكم في مجموعة من عمليات تنفيذ الصور المتسلسلة بالموارد بين عمليات التنفيذ، ما يتيح عمليات التنفيذ بتقليل من الأعلى. تتيح الكائنات المتسلسلة ثلاثة تحسينات:

  1. يتم إنشاء كائن متسلسلة قبل تسلسل عمليات التنفيذ، وتحريره عند انتهاء التسلسل. لهذا السبب، لا شك في أن عمر الانفجار تلميحات عن برنامج التشغيل إلى المدة التي يجب أن تظل فيها في الأداء العالي الولاية.
  2. يمكن لكائن الصور المتسلسلة الاحتفاظ بالموارد بين عمليات التنفيذ. على سبيل المثال، يمكن لبرنامج التشغيل تعيين كائن ذاكرة عند أول عملية تنفيذ وتخزين التعيين مؤقتًا في كائن الصور المتسلسلة لإعادة استخدامه في عمليات التنفيذ اللاحقة. أي مورد مخزَّن مؤقتًا يمكن إطلاقها عند تلف الجسم المتفجر أو عندما يُعلم وقت التشغيل كائن الصور المتسلسلة أن المورد لم يعد مطلوبًا.
  3. يستخدم الكائن المتفجر قوائم انتظار الرسائل السريعة (FMQs) للتواصل بين عمليات التطبيق وبرامج التشغيل. يمكن أن تقليل وقت الاستجابة لأن FMQ تتخطى HIDL وتمرر البيانات مباشرةً إلى عملية أخرى من خلال FIFO دائري ذري في الذاكرة المشتركة. تشير رسالة الأشكال البيانية تعرف عملية المستهلك بضرورة إلغاء عنصر ما في قائمة الانتظار وبدء المعالجة إما عن طريق استطلاع عدد العناصر في FIFO أو من خلال انتظار حدث FMQ التي يشير إليها المنتج. تُعد عملية الإبلاغ عن الحدث هذه سريعة كائن userspace التالي (futex).

FMQ هي هيكل بيانات منخفض المستوى لا يقدم أي ضمانات دائمة عبر ولا تحتوي على آلية مدمجة لتحديد ما إذا كانت العملية على تشغيل الطرف الآخر من FMQ كما هو متوقع. وبالتالي، إذا كان منتج يموت FMQ، وقد يكون المستهلك عالقًا في انتظار البيانات التي لا تصل أبدًا. وَاحِدْ لحل هذه المشكلة، أن يربط السائق أجهزة FMQ كائن صورة متسلسلة ذات مستوى أعلى لاكتشاف وقت انتهاء تنفيذ الصور المتسلسلة.

نظرًا لأن عمليات تنفيذ الصور المتسلسلة تعمل على الوسيطات نفسها وتعرض نفس الوسيطات كمسارات تنفيذ أخرى، يجب أن تمرّ FMQs الأساسية البيانات نفسها إلى ومن برامج تشغيل خدمة NNAPI. ومع ذلك، لا يمكن إلا لمحطات FMQ أن تنقل أنواع البيانات البسيطة والقديمة. يتم نقل البيانات المعقدة من خلال التسلسل وإلغاء تسلسل المخازن الاحتياطية المتداخلة (أنواع المتجهات) مباشرةً في FMQs، واستخدام عناصر معاودة الاتصال HIDL لنقل مقابض مجموعة الذاكرة عند الطلب. منتِج من FMQ إرسال الطلب أو رسائل النتائج إلى المستهلك بشكل كامل باستخدام MessageQueue::writeBlocking إذا كانت قائمة الانتظار محظورة، أو باستخدام MessageQueue::write إذا كانت قائمة المحتوى التالي لا تؤدي إلى حظر المحتوى.

واجهات الصور المتسلسلة

توجد الواجهات المتسلسلة الخاصة بـ HAL للشبكات العصبية في hardware/interfaces/neuralnetworks/1.2/ وهي موضحة أدناه. لمزيد من المعلومات عن واجهات الصور المتسلسلة في NDK طبقة، انظر frameworks/ml/nn/runtime/include/NeuralNetworks.h

type.hal

types.hal نوع البيانات التي يتم إرسالها عبر FMQ.

  • FmqRequestDatum: عنصر واحد لتمثيل متسلسل لعملية التنفيذ Request كائن وقيمة MeasureTiming يتم إرسالها عبر الرسالة السريعة قائمة الانتظار.
  • FmqResultDatum: عنصر واحد لتمثيل متسلسل للقيم التي يتم عرضها من عملية تنفيذ (ErrorStatus وOutputShapes وTiming)، وهي من خلال قائمة انتظار الرسائل السريعة.

IBurstContext.hal

IBurstContext.hal كائن واجهة HIDL الموجود في خدمة الشبكات العصبية.

  • IBurstContext: كائن السياق لإدارة موارد الصور المتسلسلة.

IBurstCallback.hal

IBurstCallback.hal كائن واجهة HIDL لمعاودة الاتصال التي تم إنشاؤها بواسطة الشبكات العصبية وتستخدمه خدمة الشبكات العصبية لاسترداد بيانات hidl_memory الكائنات المقابلة لمعرّفات الخانات.

  • IBurstCallback: عنصر معاودة الاتصال الذي تستخدمه إحدى الخدمات لاسترداد عناصر الذاكرة.

مؤسسة IPreparedModel.hal

IPreparedModel.hal في HAL 1.2 بطريقة لإنشاء كائن IBurstContext من إعداد نموذجي.

  • configureExecutionBurst: تعمل هذه السياسة على إعداد كائن متسلسلة يُستخدم لتنفيذ استنتاجات متعددة على عنصر تم إعداده. النموذج بتتابع سريع.

دعم عمليات تنفيذ الصور المتسلسلة في برنامج التشغيل

وأبسط طريقة لدعم الكائنات المتسلسلة في خدمة HIDL NNAPI هي استخدام دالة فائدة الصور المتسلسلة ::android::nn::ExecutionBurstServer::create، وهي تم العثور عليها في ExecutionBurstServer.h ومضمّنة في الحزمة في libneuralnetworks_common وlibneuralnetworks_util. والمكتبات الثابتة. تتضمن وظيفة المصنع هذه حملتين زائدتين:

  • فعملية التحميل الزائدة تقبل مؤشر الماوس إلى عنصر IPreparedModel. هذا النمط استخدام طريقة executeSynchronously في الكائن IPreparedModel لتنفيذ النموذج.
  • تقبل التحميل الزائد عنصر IBurstExecutorWithCache قابل للتخصيص. والتي يمكن استخدامها لتخزين الموارد في ذاكرة التخزين المؤقت (مثل تعيينات hidl_memory) التي تستمر عبر عمليات التنفيذ المتعددة.

تعرض كل حِمل زائد عنصر IBurstContext (يمثل الصور المتسلسلة. ) يحتوي على سلسلة المستمعين المخصصة وتديرها. سلسلة المحادثات الحالية يتلقى طلبات من FMQ requestChannel، وينفذ الاستنتاج، ثم يعرض النتائج من خلال resultChannel FMQ. سلسلة المحادثات هذه وجميع يتم تلقائيًا تحرير الموارد المضمَّنة في الكائن IBurstContext عندما يفقد عميل الصور المتسلسلة مرجعه إلى IBurstContext.

بدلاً من ذلك، يمكنك إنشاء عملية تنفيذ خاصة بك لـ IBurstContext والتي طريقة إرسال الرسائل واستلامها عبر requestChannel تم تمرير resultChannel من أجهزة FMQ إلى IPreparedModel::configureExecutionBurst.

توجد دوال المنفعة المتسلسلة في ExecutionBurstServer.h

/**
 * Create automated context to manage FMQ-based executions.
 *
 * This function is intended to be used by a service to automatically:
 * 1) Receive data from a provided FMQ
 * 2) Execute a model with the given information
 * 3) Send the result to the created FMQ
 *
 * @param callback Callback used to retrieve memories corresponding to
 *     unrecognized slots.
 * @param requestChannel Input FMQ channel through which the client passes the
 *     request to the service.
 * @param resultChannel Output FMQ channel from which the client can retrieve
 *     the result of the execution.
 * @param executorWithCache Object which maintains a local cache of the
 *     memory pools and executes using the cached memory pools.
 * @result IBurstContext Handle to the burst context.
 */
static sp<ExecutionBurstServer> create(
        const sp<IBurstCallback>& callback, const FmqRequestDescriptor& requestChannel,
        const FmqResultDescriptor& resultChannel,
        std::shared_ptr<IBurstExecutorWithCache> executorWithCache);

/**
 * Create automated context to manage FMQ-based executions.
 *
 * This function is intended to be used by a service to automatically:
 * 1) Receive data from a provided FMQ
 * 2) Execute a model with the given information
 * 3) Send the result to the created FMQ
 *
 * @param callback Callback used to retrieve memories corresponding to
 *     unrecognized slots.
 * @param requestChannel Input FMQ channel through which the client passes the
 *     request to the service.
 * @param resultChannel Output FMQ channel from which the client can retrieve
 *     the result of the execution.
 * @param preparedModel PreparedModel that the burst object was created from.
 *     IPreparedModel::executeSynchronously will be used to perform the
 *     execution.
 * @result IBurstContext Handle to the burst context.
 */
  static sp<ExecutionBurstServer> create(const sp<IBurstCallback>& callback,
                                         const FmqRequestDescriptor& requestChannel,
                                         const FmqResultDescriptor& resultChannel,
                                         IPreparedModel* preparedModel);

في ما يلي تطبيق مرجعي لواجهة متسلسلة في العنصر عينة برنامج تشغيل الشبكات العصبية في frameworks/ml/nn/driver/sample/SampleDriver.cpp

Return<void> SamplePreparedModel::configureExecutionBurst(
        const sp<V1_2::IBurstCallback>& callback,
        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
        configureExecutionBurst_cb cb) {
    NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION,
                 "SampleDriver::configureExecutionBurst");
    // Alternatively, the burst could be configured via:
    // const sp<V1_2::IBurstContext> burst =
    //         ExecutionBurstServer::create(callback, requestChannel,
    //                                      resultChannel, this);
    //
    // However, this alternative representation does not include a memory map
    // caching optimization, and adds overhead.
    const std::shared_ptr<BurstExecutorWithCache> executorWithCache =
            std::make_shared<BurstExecutorWithCache>(mModel, mDriver, mPoolInfos);
    const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(
            callback, requestChannel, resultChannel, executorWithCache);
    if (burst == nullptr) {
        cb(ErrorStatus::GENERAL_FAILURE, {});
    } else {
        cb(ErrorStatus::NONE, burst);
    }
    return Void();
}