類神經網路 HAL 1.2 介紹爆發執行的概念。爆發執行作業是針對同一準備好的模型,快速連續進行的一系列執行作業,例如執行相機所拍攝的影格或連續音訊取樣。爆發物件可用於控制一組爆發執行作業,並在執行作業之間保留資源,讓執行作業的額外負擔降低。Burst 物件可啟用三種最佳化功能:
- 系統會在執行一系列執行作業前建立爆發物件 序列結束時因此,連拍的生命週期 並向驅動程式提示駕駛人應能維持高效能物件的時間長度 時間。
- 爆發物件可在執行作業之間保留資源。舉例來說,驅動程式可以在第一次執行時對應記憶體物件,並在爆發物件中快取對應項目,以便在後續執行作業中重複使用。當爆發物件遭到銷毀,或 NNAPI 執行階段通知爆發物件不再需要該資源時,系統可以釋出任何快取的資源。
- 爆發物件會使用快速訊息佇列 (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
: 所傳回值的序列化表示法的單一元素 執行程序 (ErrorStatus
、OutputShapes
和Timing
), 傳回的結果。
IBurstContext.hal
IBurstContext.hal
會定義位於類神經網路服務中的 HIDL 介面物件。
IBurstContext
:用於管理連拍相片資源的內容物件。
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_common
和 libneuralnetworks_util
靜態程式庫中。這個工廠函式有兩個超載:
- 其中一個超載會接受指向
IPreparedModel
物件的指標。這個公用函式會使用IPreparedModel
物件中的executeSynchronously
方法執行模型。 - 其中一個超載方法會接受可自訂的
IBurstExecutorWithCache
物件,可用於快取在多個執行作業中持續存在的資源 (例如hidl_memory
對應)。
每個超載都會傳回一個 IBurstContext
物件,代表爆發
物件),其中包含及管理其專屬的事件監聽器執行緒。這個對話串
接收來自「requestChannel
」FMQ 的要求,執行推論,然後
會透過 resultChannel
FMQ 傳回結果。這個對話串和所有其他類別
IBurstContext
物件包含的資源會自動釋出
當爆發的用戶端失去對 IBurstContext
的參照時。
或者,您也可以自行建立 IBurstContext
的實作項目,瞭解如何透過傳遞至 IPreparedModel::configureExecutionBurst
的 requestChannel
和 resultChannel
FMQ 傳送及接收訊息。
爆發公用程式函式位於
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();
}