Thực thi hàng loạt và xếp hàng đợi tin nhắn nhanh chóng

Mạng nơron HAL 1.2 giới thiệu khái niệm thực thi chụp. Bùng nổ quá trình thực thi là một chuỗi các quá trình thực thi cùng một mô hình được chuẩn bị xảy ra trong quá trình diễn ra liên tiếp nhanh chóng, chẳng hạn như hoạt động trên khung hình của máy ảnh chụp hoặc âm thanh liên tiếp mẫu. Đối tượng hàng loạt được dùng để điều khiển một tập hợp các quá trình thực thi hàng loạt và để bảo toàn tài nguyên giữa các lần thực thi, cho phép các lần thực thi có thời lượng chi phí. Đối tượng hàng loạt có 3 tính năng tối ưu hoá:

  1. Một đối tượng hàng loạt được tạo trước một trình tự thực thi và được giải phóng khi trình tự đã kết thúc. Do đó, thời gian tồn tại của loạt ảnh đối tượng gợi ý cho người lái xe về khoảng thời gian cần duy trì để đạt hiệu suất cao trạng thái.
  2. Đối tượng hàng loạt có thể bảo toàn tài nguyên giữa các lần thực thi. Ví dụ: một trình điều khiển có thể ánh xạ một đối tượng bộ nhớ trong lần thực thi đầu tiên và lưu ánh xạ vào bộ nhớ đệm trong đối tượng hàng loạt để sử dụng lại trong các lần thực thi tiếp theo. Mọi tài nguyên được lưu vào bộ nhớ đệm có thể được giải phóng khi đối tượng hàng loạt bị huỷ bỏ hoặc khi NNAPI thời gian chạy sẽ thông báo cho đối tượng hàng loạt rằng tài nguyên không còn cần thiết nữa.
  3. Sử dụng một đối tượng hàng loạt hàng đợi tin nhắn nhanh (FMQ) để giao tiếp giữa các quy trình của ứng dụng và trình điều khiển. Điều này có thể giảm độ trễ vì FMQ bỏ qua HIDL và truyền dữ liệu trực tiếp đến một quá trình khác thông qua FIFO tròn nguyên tử trong bộ nhớ dùng chung. Chiến lược phát hành đĩa đơn quy trình của người tiêu dùng biết để xếp một mặt hàng vào hàng đợi và bắt đầu xử lý bằng cách thăm dò số lượng phần tử trong FIFO hoặc bằng cách chờ sự kiện của FMQ cờ hiệu do nhà sản xuất báo hiệu. Cờ sự kiện này là mutex không gian người dùng (futex).

FMQ là một cấu trúc dữ liệu cấp thấp không đưa ra bảo đảm toàn thời gian đối với và không có sẵn cơ chế tích hợp để xác định xem quá trình trên đầu kia của FMQ đang hoạt động như dự kiến. Do đó, nếu nhà sản xuất FMQ chết, người tiêu dùng có thể bị mắc kẹt trong khi chờ những dữ liệu không bao giờ đến nơi. Một Giải pháp cho vấn đề này là để người lái xe liên kết FMQ với đối tượng trong gói ở cấp cao hơn để phát hiện thời điểm kết thúc quá trình thực thi gói.

Vì các quá trình thực thi hàng loạt hoạt động trên cùng một đối số và trả về cùng một đối số kết quả như các đường dẫn thực thi khác, các FMQ cơ bản phải truyền cùng một dữ liệu đến và từ các trình điều khiển dịch vụ NNAPI. Tuy nhiên, FMQ chỉ có thể chuyển dữ liệu cũ. Quá trình chuyển dữ liệu phức tạp được thực hiện bằng cách chuyển đổi tuần tự và giải tuần tự vùng đệm lồng nhau (loại vectơ) trực tiếp trong FMQ và sử dụng Đối tượng gọi lại HIDL dùng để chuyển các tên người dùng nhóm bộ nhớ theo yêu cầu. Nhà sản xuất phía FMQ phải gửi yêu cầu hoặc thông báo kết quả đến người tiêu dùng một cách tỉ mỉ bằng cách sử dụng MessageQueue::writeBlocking nếu hàng đợi đang chặn, hoặc bằng cách sử dụng MessageQueue::write nếu hàng đợi không chặn.

Giao diện Burst

Các giao diện hàng loạt cho HAL mạng nơron có trong hardware/interfaces/neuralnetworks/1.2/ và được mô tả bên dưới. Để biết thêm thông tin về giao diện chụp liên tục trong NDK lớp, xem frameworks/ml/nn/runtime/include/NeuralNetworks.h.

type.hal

types.hal xác định loại dữ liệu được gửi qua FMQ.

  • FmqRequestDatum: Một phần tử của bản trình bày chuyển đổi tuần tự của quá trình thực thi Request và một giá trị MeasureTiming được gửi qua thông báo nhanh hàng đợi.
  • FmqResultDatum: Một phần tử biểu diễn tuần tự của các giá trị được trả về từ một lần thực thi (ErrorStatus, OutputShapesTiming), tức là trả lại qua hàng đợi thư nhanh.

IBurstContext.hal

IBurstContext.hal xác định đối tượng giao diện HIDL hoạt động trong dịch vụ Mạng nơron.

  • IBurstContext: Đối tượng ngữ cảnh để quản lý tài nguyên của gói.

Hàm IBurstCallback.hal

IBurstCallback.hal xác định đối tượng giao diện HIDL cho lệnh gọi lại do mạng nơron tạo ra thời gian chạy và được dịch vụ Neural Networks dùng để truy xuất hidl_memory tương ứng với giá trị nhận dạng vị trí.

  • IBurstCallback: Đối tượng gọi lại mà dịch vụ sử dụng để truy xuất đối tượng bộ nhớ.

IPreparedModel.hal

IPreparedModel.hal được mở rộng trong HAL 1.2 với phương thức tạo đối tượng IBurstContext từ mô hình đã chuẩn bị.

  • configureExecutionBurst: Định cấu hình một đối tượng hàng loạt dùng để thực thi nhiều suy luận trên một đối tượng đã chuẩn bị mô hình được nối tiếp và nối tiếp nhau nhanh chóng.

Hỗ trợ thực thi hàng loạt trong trình điều khiển

Cách đơn giản nhất để hỗ trợ các đối tượng hàng loạt trong dịch vụ HIDL NNAPI là sử dụng hàm số hiệu dụng hàng loạt ::android::nn::ExecutionBurstServer::create, là được tìm thấy trong ExecutionBurstServer.h và được đóng gói trong libneuralnetworks_commonlibneuralnetworks_util thư viện tĩnh. Hàm nhà máy này có 2 phương thức nạp chồng:

  • Một phương thức nạp chồng chấp nhận con trỏ trỏ đến đối tượng IPreparedModel. Chiến dịch này hàm hiệu dụng sử dụng phương thức executeSynchronously trong một Đối tượng IPreparedModel để thực thi mô hình.
  • Một phương thức nạp chồng chấp nhận đối tượng IBurstExecutorWithCache có thể tuỳ chỉnh, Tài nguyên này có thể được dùng để lưu vào bộ nhớ đệm các tài nguyên (chẳng hạn như ánh xạ hidl_memory) duy trì qua nhiều lần thực thi.

Mỗi phương thức nạp chồng trả về một đối tượng IBurstContext (đại diện cho loạt ảnh) ) chứa và quản lý luồng trình nghe chuyên dụng riêng. Chuỗi cuộc trò chuyện này nhận các yêu cầu từ FMQ của requestChannel, tiến hành suy luận, sau đó sẽ trả về kết quả thông qua FMQ resultChannel. Chuỗi cuộc trò chuyện này và tất cả các chuỗi khác các tài nguyên có trong đối tượng IBurstContext sẽ tự động được giải phóng khi ứng dụng của hàng loạt mất tham chiếu đến IBurstContext.

Ngoài ra, bạn có thể tạo cách triển khai IBurstContext của riêng mình hiểu cách gửi và nhận tin nhắn qua requestChannelresultChannel FMQ được chuyển đến IPreparedModel::configureExecutionBurst.

Bạn có thể tìm thấy các hàm số hiệu dụng hàng loạt trong 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);

Sau đây là cách triển khai tham chiếu của giao diện chụp liên tục được tìm thấy trong Trình điều khiển mẫu của Neural Networks tại 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();
}