Eksekusi burst dan antrian pesan cepat

Neural Networks HAL 1.2 memperkenalkan konsep eksekusi burst. Eksekusi beruntun adalah rangkaian eksekusi dari model yang disiapkan sama dan terjadi secara berurutan, misalnya yang beroperasi pada bingkai tangkapan kamera atau sampel audio yang berurutan. Objek burst digunakan untuk mengontrol serangkaian eksekusi burst, dan untuk melestarikan sumber daya di antara eksekusi, sehingga memungkinkan eksekusi memiliki overhead yang lebih rendah. Objek burst memungkinkan tiga pengoptimalan:

  1. Objek burst dibuat sebelum rangkaian eksekusi, dan dibebaskan ketika rangkaian tersebut telah berakhir. Oleh karena itu, umur objek yang meledak memberi petunjuk kepada pengemudi berapa lama objek tersebut harus tetap berada dalam kondisi performa tinggi.
  2. Objek burst dapat mempertahankan sumber daya di antara eksekusi. Misalnya, driver dapat memetakan objek memori pada eksekusi pertama dan menyimpan pemetaan dalam cache objek burst untuk digunakan kembali pada eksekusi berikutnya. Sumber daya apa pun yang disimpan dalam cache dapat dilepaskan ketika objek burst dimusnahkan atau ketika runtime NNAPI memberi tahu objek burst bahwa sumber daya tidak lagi diperlukan.
  3. Objek burst menggunakan antrian pesan cepat (FMQ) untuk berkomunikasi antara proses aplikasi dan driver. Hal ini dapat mengurangi latensi karena FMQ melewati HIDL dan meneruskan data langsung ke proses lain melalui FIFO sirkular atom di memori bersama. Proses konsumen mengetahui untuk melakukan dequeue suatu item dan mulai memproses baik dengan melakukan polling terhadap jumlah elemen di FIFO atau dengan menunggu tanda peristiwa FMQ, yang ditandai oleh produsen. Bendera acara ini adalah mutex ruang pengguna cepat (futex).

FMQ adalah struktur data tingkat rendah yang tidak memberikan jaminan seumur hidup di seluruh proses dan tidak memiliki mekanisme bawaan untuk menentukan apakah proses di ujung lain FMQ berjalan seperti yang diharapkan. Akibatnya, jika produsen FMQ meninggal, konsumen mungkin terjebak menunggu data yang tidak pernah sampai. Salah satu solusi untuk masalah ini adalah driver mengasosiasikan FMQ dengan objek burst level yang lebih tinggi untuk mendeteksi kapan eksekusi burst telah berakhir.

Karena eksekusi burst beroperasi pada argumen yang sama dan mengembalikan hasil yang sama seperti jalur eksekusi lainnya, FMQ yang mendasarinya harus meneruskan data yang sama ke dan dari driver layanan NNAPI. Namun, FMQ hanya dapat mentransfer tipe data biasa. Mentransfer data kompleks dilakukan dengan membuat serialisasi dan deserialisasi buffer bersarang (tipe vektor) langsung di FMQ, dan menggunakan objek panggilan balik HIDL untuk mentransfer pegangan kumpulan memori sesuai permintaan. Sisi produsen FMQ harus mengirimkan pesan permintaan atau hasil ke konsumen secara atom dengan menggunakan MessageQueue::writeBlocking jika antriannya memblokir, atau dengan menggunakan MessageQueue::write jika antriannya nonblocking.

Antarmuka meledak

Antarmuka burst untuk Neural Networks HAL ditemukan di hardware/interfaces/neuralnetworks/1.2/ dan dijelaskan di bawah. Untuk informasi selengkapnya tentang antarmuka burst di lapisan NDK, lihat frameworks/ml/nn/runtime/include/NeuralNetworks.h .

jenis.hal

types.hal mendefinisikan jenis data yang dikirim melalui FMQ.

  • FmqRequestDatum : Elemen tunggal representasi serial dari objek Request eksekusi dan nilai MeasureTiming , yang dikirim melalui antrian pesan cepat.
  • FmqResultDatum : Elemen tunggal representasi serial dari nilai yang dikembalikan dari eksekusi ( ErrorStatus , OutputShapes , dan Timing ), yang dikembalikan melalui antrian pesan cepat.

IBurstContext.hal

IBurstContext.hal mendefinisikan objek antarmuka HIDL yang ada di layanan Neural Networks.

  • IBurstContext : Objek konteks untuk mengelola sumber daya ledakan.

IBurstCallback.hal

IBurstCallback.hal mendefinisikan objek antarmuka HIDL untuk callback yang dibuat oleh runtime Neural Networks dan digunakan oleh layanan Neural Networks untuk mengambil objek hidl_memory yang sesuai dengan pengidentifikasi slot.

  • IBurstCallback : Objek panggilan balik yang digunakan oleh layanan untuk mengambil objek memori.

IPreparedModel.hal

IPreparedModel.hal diperluas di HAL 1.2 dengan metode untuk membuat objek IBurstContext dari model yang telah disiapkan.

  • configureExecutionBurst : Mengonfigurasi objek burst yang digunakan untuk mengeksekusi beberapa inferensi pada model yang disiapkan secara berurutan.

Mendukung eksekusi burst pada driver

Cara termudah untuk mendukung objek burst dalam layanan HIDL NNAPI adalah dengan menggunakan fungsi utilitas burst ::android::nn::ExecutionBurstServer::create , yang ditemukan di ExecutionBurstServer.h dan dikemas dalam pustaka statis libneuralnetworks_common dan libneuralnetworks_util . Fungsi pabrik ini memiliki dua kelebihan beban:

  • Satu kelebihan menerima penunjuk ke objek IPreparedModel . Fungsi utilitas ini menggunakan metode executeSynchronously dalam objek IPreparedModel untuk mengeksekusi model.
  • Satu kelebihan menerima objek IBurstExecutorWithCache yang dapat disesuaikan, yang dapat digunakan untuk menyimpan sumber daya dalam cache (seperti pemetaan hidl_memory ) yang bertahan di beberapa eksekusi.

Setiap kelebihan beban mengembalikan objek IBurstContext (yang mewakili objek burst) yang berisi dan mengelola thread pendengar khusus miliknya sendiri. Thread ini menerima permintaan dari requestChannel FMQ, melakukan inferensi, lalu mengembalikan hasilnya melalui resultChannel FMQ. Thread ini dan semua sumber daya lain yang terdapat dalam objek IBurstContext secara otomatis dilepaskan ketika klien burst kehilangan referensinya ke IBurstContext .

Alternatifnya, Anda dapat membuat implementasi IBurstContext Anda sendiri yang memahami cara mengirim dan menerima pesan melalui requestChannel dan resultChannel FMQ yang diteruskan ke IPreparedModel::configureExecutionBurst .

Fungsi utilitas burst ditemukan di 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);

Berikut ini adalah implementasi referensi antarmuka burst yang ditemukan di driver sampel Neural Networks di 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();
}