爆發執行作業與快速訊息佇列

類神經網路 HAL 1.2 介紹爆發執行的概念。火花 「執行作業」是指在 像是在相機拍攝畫面中運作 連續音訊 樣本。爆發物件可用於控制一組爆發執行作業 保留執行作業之間的資源,讓執行作業能減少 同時免除不必要的負擔爆發物件支援三種最佳化功能:

  1. 系統會在執行一系列執行作業前建立爆發物件 序列結束時因此,連拍的生命週期 並向驅動程式提示駕駛人應能維持高效能物件的時間長度 時間。
  2. 爆發物件可以保留執行作業之間的資源。舉例來說 驅動程式可在首次執行時對應記憶體物件,並快取對應 放入爆發物件中,以便在後續執行作業中重複使用。任何快取的資源 等到爆發物件刪除或 NNAPI 後 執行階段會通知爆發物件,說明不再需要資源。
  3. 爆發物件會使用 快速訊息佇列 (FMQ) 以在應用程式和驅動程式程序之間進行通訊。這可以 降低延遲時間,因為 FMQ 會略過 HIDL,並將資料直接傳送給 透過共用記憶體中的原子環 FIFO 通過另一個程序。 消費者程序知道將項目移出佇列並由以下兩個方法開始處理: 輪詢 FIFO 或 FMQ 事件的數目 標記,並由生產者發出訊號。這個事件旗標是非常快速 使用者空間互斥鎖 (futex)。

FMQ 是一種低階資料結構,在 且沒有內建可判斷處理程序 FMQ 另一端運作正常。因此如果生產端 FMQ 公司因此難免會卡住一 此問題的解決方法,是駕駛人將 FMQ 與 來偵測爆發執行何時結束。

因為爆發執行作業會在相同的引數上運作 與其他執行路徑一樣,基礎 FMQ 必須將相同的資料傳送至 以及依據 NNAPI 服務驅動程式不過,FMQ 只能轉 純粹的資料型別將複雜資料序列化即可完成移轉 以及直接在 FMQ 中反序列化巢狀緩衝區 (向量類型),然後使用 用於轉移記憶體集區的 HIDL 回呼物件。製作人 FMQ 最終必須將要求或結果訊息傳送給用戶端 如果佇列處於封鎖狀態,則使用 MessageQueue::writeBlocking,或者 如果佇列為非阻斷式,請使用 MessageQueue::write

爆發介面

類神經網路 HAL 的爆發介面位於 hardware/interfaces/neuralnetworks/1.2/敬上 。請參閱 NDK 中爆發介面的詳細資訊 圖層,請參閱 frameworks/ml/nn/runtime/include/NeuralNetworks.h

types.hal

types.hal敬上 定義 FMQ 所傳送的資料類型。

  • FmqRequestDatum: 執行 Request 序列化表示法的單一元素 物件和 MeasureTiming 值,可在快速訊息中傳送 佇列。
  • FmqResultDatum: 所傳回值的序列化表示法的單一元素 執行程序 (ErrorStatusOutputShapesTiming), 傳回的結果。

IBurstContext.hal

IBurstContext.hal敬上 會定義位於類神經網路服務中的 HIDL 介面物件。

IBurstCallback.hal

IBurstCallback.hal敬上 為類神經網路建立的回呼定義 HIDL 介面物件 執行階段,並由類神經網路服務用來擷取 hidl_memory 對應至運算單元 ID 的物件

  • IBurstCallback: 服務用來擷取記憶體物件的回呼物件。

IPreparedModel.hal

IPreparedModel.hal敬上 已在 HAL 1.2 中擴充,並提供從IBurstContext 預先準備的模型

  • configureExecutionBurst: 設定爆發物件,用來對準備的多個推論執行多項推論 快速連續執行模型

支援驅動程式中的爆發執行

如要在 HIDL NNAPI 服務中支援爆發物件,最簡單的方法就是使用 爆發公用程式函式 ::android::nn::ExecutionBurstServer::create 來源: ExecutionBurstServer.h 並封裝在 libneuralnetworks_commonlibneuralnetworks_util 中 靜態程式庫這個工廠函式有兩個超載:

  • 其中一個超載接受指向 IPreparedModel 物件的指標。這個 公用函式會使用 executeSynchronously 方法, IPreparedModel 物件來執行模型。
  • 其中一個超載接受可自訂的 IBurstExecutorWithCache 物件, 可用來快取資源 (例如 hidl_memory 對應) 仍會保留至多次執行

每個超載都會傳回一個 IBurstContext 物件,代表爆發 物件),其中包含及管理其專屬的事件監聽器執行緒。這個對話串 接收來自「requestChannel」FMQ 的要求,執行推論,然後 會透過 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();
}