Bể nhớ

Trang này mô tả các cấu trúc dữ liệu và phương pháp được sử dụng để giao tiếp hiệu quả các vùng đệm toán hạng giữa trình điều khiển và khung.

Tại thời điểm biên dịch mô hình, khung cung cấp các giá trị của toán hạng không đổi cho trình điều khiển. Tùy thuộc vào thời gian tồn tại của toán hạng không đổi, các giá trị của nó được đặt trong vectơ HIDL hoặc nhóm bộ nhớ dùng chung.

  • Nếu thời gian tồn tại là CONSTANT_COPY thì các giá trị sẽ nằm trong trường operandValues ​​của cấu trúc mô hình. Bởi vì các giá trị trong vectơ HIDL được sao chép trong quá trình giao tiếp giữa các quá trình (IPC), nên điều này thường chỉ được sử dụng để chứa một lượng nhỏ dữ liệu như toán hạng vô hướng (ví dụ: vô hướng kích hoạt trong ADD ) và các tham số tensor nhỏ (ví dụ: tenxơ hình dạng trong RESHAPE ).
  • Nếu thời gian tồn tại là CONSTANT_REFERENCE thì các giá trị được đặt trong trường pools của cấu trúc mô hình. Chỉ các phần điều khiển của nhóm bộ nhớ dùng chung được sao chép trong IPC thay vì sao chép các giá trị thô. Do đó, sẽ hiệu quả hơn khi lưu giữ một lượng lớn dữ liệu (ví dụ: các tham số trọng lượng trong tích chập) bằng cách sử dụng nhóm bộ nhớ dùng chung so với vectơ HIDL.

Tại thời điểm thực thi mô hình, khung cung cấp bộ đệm của toán hạng đầu vào và đầu ra cho trình điều khiển. Không giống như các hằng số thời gian biên dịch có thể được gửi trong vectơ HIDL, dữ liệu đầu vào và đầu ra của quá trình thực thi luôn được truyền thông qua một tập hợp các nhóm bộ nhớ.

Kiểu dữ liệu HIDL hidl_memory được sử dụng trong cả quá trình biên dịch và thực thi để thể hiện một nhóm bộ nhớ dùng chung chưa được ánh xạ. Trình điều khiển nên ánh xạ bộ nhớ phù hợp để làm cho bộ nhớ có thể sử dụng được dựa trên tên của kiểu dữ liệu hidl_memory . Tên bộ nhớ được hỗ trợ là:

  • ashmem : Bộ nhớ dùng chung của Android. Để biết thêm chi tiết, xem bộ nhớ .
  • mmap_fd : Bộ nhớ dùng chung được hỗ trợ bởi bộ mô tả tệp thông qua mmap .
  • hardware_buffer_blob : Bộ nhớ dùng chung được hỗ trợ bởi AHardwareBuffer với định dạng AHARDWARE_BUFFER_FORMAT_BLOB . Có sẵn từ Mạng thần kinh (NN) HAL 1.2. Để biết thêm chi tiết, hãy xem AHardwareBuffer .
  • hardware_buffer : Bộ nhớ dùng chung được hỗ trợ bởi AHardwareBuffer chung không sử dụng định dạng AHARDWARE_BUFFER_FORMAT_BLOB . Bộ đệm phần cứng ở chế độ không phải BLOB chỉ được hỗ trợ khi thực thi mô hình. Có sẵn từ NN HAL 1.2. Để biết thêm chi tiết, hãy xem AHardwareBuffer .

Từ NN HAL 1.3, NNAPI hỗ trợ các miền bộ nhớ cung cấp giao diện cấp phát cho bộ đệm do trình điều khiển quản lý. Bộ đệm do trình điều khiển quản lý cũng có thể được sử dụng làm đầu vào hoặc đầu ra thực thi. Để biết thêm chi tiết, hãy xem Miền bộ nhớ .

Trình điều khiển NNAPI phải hỗ trợ ánh xạ tên bộ nhớ ashmemmmap_fd . Từ NN HAL 1.3, trình điều khiển cũng phải hỗ trợ ánh xạ hardware_buffer_blob . Hỗ trợ cho hardware_buffer và miền bộ nhớ ở chế độ không phải BLOB chung là tùy chọn.

Bộ đệm phần cứng

AHardwareBuffer là một loại bộ nhớ dùng chung bao bọc bộ đệm Gralloc . Trong Android 10, API mạng thần kinh (NNAPI) hỗ trợ sử dụng AHardwareBuffer , cho phép trình điều khiển thực hiện các lệnh thực thi mà không cần sao chép dữ liệu, giúp cải thiện hiệu suất và mức tiêu thụ điện năng cho ứng dụng. Ví dụ: ngăn xếp HAL của máy ảnh có thể chuyển các đối tượng AHardwareBuffer tới NNAPI cho khối lượng công việc máy học bằng cách sử dụng các bộ điều khiển AHardwareBuffer do NDK của máy ảnh và API NDK đa phương tiện tạo ra. Để biết thêm thông tin, hãy xem ANeuralNetworksMemory_createFromAHardwareBuffer .

Các đối tượng AHardwareBuffer được sử dụng trong NNAPI được chuyển đến trình điều khiển thông qua cấu trúc hidl_memory có tên là hardware_buffer hoặc hardware_buffer_blob . Cấu trúc hidl_memory hardware_buffer_blob chỉ đại diện cho các đối tượng AHardwareBuffer có định dạng AHARDWAREBUFFER_FORMAT_BLOB .

Thông tin mà khung yêu cầu được mã hóa trong trường hidl_handle của cấu trúc hidl_memory . Trường hidl_handle bao bọc native_handle , mã hóa tất cả siêu dữ liệu cần thiết về bộ đệm AHardwareBuffer hoặc Gralloc.

Trình điều khiển phải giải mã chính xác trường hidl_handle được cung cấp và truy cập vào bộ nhớ được mô tả bởi hidl_handle . Khi phương thức getSupportedOperations_1_2 , getSupportedOperations_1_1 hoặc getSupportedOperations được gọi, trình điều khiển sẽ phát hiện xem liệu nó có thể giải hidl_handle được cung cấp và truy cập vào bộ nhớ được mô tả bởi hidl_handle . Quá trình chuẩn bị mô hình phải thất bại nếu trường hidl_handle dùng cho toán hạng không đổi không được hỗ trợ. Quá trình thực thi phải thất bại nếu trường hidl_handle được sử dụng cho toán hạng đầu vào hoặc đầu ra của quá trình thực thi không được hỗ trợ. Trình điều khiển nên trả về mã lỗi GENERAL_FAILURE nếu quá trình chuẩn bị hoặc thực thi mô hình không thành công.

Miền bộ nhớ

Đối với các thiết bị chạy Android 11 trở lên, NNAPI hỗ trợ các miền bộ nhớ cung cấp giao diện cấp phát cho vùng đệm do trình điều khiển quản lý. Điều này cho phép truyền bộ nhớ gốc của thiết bị qua các lần thực thi, ngăn chặn việc sao chép và chuyển đổi dữ liệu không cần thiết giữa các lần thực thi liên tiếp trên cùng một trình điều khiển. Luồng này được minh họa trong Hình 1.

Luồng dữ liệu đệm có và không có miền bộ nhớ

Hình 1. Luồng dữ liệu đệm sử dụng miền bộ nhớ

Tính năng miền bộ nhớ dành cho các tensor hầu hết nằm bên trong trình điều khiển và không cần truy cập thường xuyên ở phía máy khách. Ví dụ về các tensor như vậy bao gồm các tensor trạng thái trong các mô hình tuần tự. Đối với các tensor cần truy cập CPU thường xuyên ở phía máy khách, tốt nhất nên sử dụng nhóm bộ nhớ dùng chung.

Để hỗ trợ tính năng miền bộ nhớ, hãy triển khai IDevice::allocate để cho phép khung yêu cầu phân bổ bộ đệm do trình điều khiển quản lý. Trong quá trình phân bổ, khung cung cấp các thuộc tính và kiểu sử dụng sau cho bộ đệm:

  • BufferDesc mô tả các thuộc tính cần thiết của bộ đệm.
  • BufferRole mô tả kiểu sử dụng tiềm năng của bộ đệm dưới dạng đầu vào hoặc đầu ra của mô hình đã chuẩn bị. Nhiều vai trò có thể được chỉ định trong quá trình cấp phát bộ đệm và bộ đệm được phân bổ chỉ có thể được sử dụng làm các vai trò được chỉ định đó.

Bộ đệm được phân bổ nằm bên trong trình điều khiển. Trình điều khiển có thể chọn bất kỳ vị trí bộ đệm hoặc bố cục dữ liệu nào. Khi bộ đệm được cấp phát thành công, máy khách của trình điều khiển có thể tham chiếu hoặc tương tác với bộ đệm bằng cách sử dụng mã thông báo được trả về hoặc đối tượng IBuffer .

Mã thông báo từ IDevice::allocate được cung cấp khi tham chiếu bộ đệm dưới dạng một trong các đối tượng MemoryPool trong cấu trúc Request của quá trình thực thi. Để ngăn một quá trình cố gắng truy cập vào bộ đệm được phân bổ trong một quy trình khác, trình điều khiển phải áp dụng xác thực hợp lệ cho mỗi lần sử dụng bộ đệm. Trình điều khiển phải xác thực rằng việc sử dụng bộ đệm là một trong các vai trò BufferRole được cung cấp trong quá trình phân bổ và phải thực thi không thành công ngay lập tức nếu việc sử dụng đó là bất hợp pháp.

Đối tượng IBuffer được sử dụng để sao chép bộ nhớ rõ ràng. Trong một số trường hợp nhất định, máy khách của trình điều khiển phải khởi tạo bộ đệm do trình điều khiển quản lý từ nhóm bộ nhớ dùng chung hoặc sao chép bộ đệm ra nhóm bộ nhớ dùng chung. Các trường hợp sử dụng ví dụ bao gồm:

  • Khởi tạo tensor trạng thái
  • Lưu kết quả trung gian vào bộ nhớ đệm
  • Thực thi dự phòng trên CPU

Để hỗ trợ các trường hợp sử dụng này, trình điều khiển phải triển khai IBuffer::copyToIBuffer::copyFrom với ashmem , mmap_fdhardware_buffer_blob nếu nó hỗ trợ phân bổ miền bộ nhớ. Trình điều khiển có thể tùy chọn hỗ trợ chế độ không phải BLOB hardware_buffer .

Trong quá trình phân bổ bộ đệm, kích thước của bộ đệm có thể được suy ra từ toán hạng mô hình tương ứng của tất cả các vai trò được chỉ định bởi BufferRole và kích thước được cung cấp trong BufferDesc . Với tất cả thông tin về chiều được kết hợp, bộ đệm có thể có thứ nguyên hoặc thứ hạng không xác định. Trong trường hợp như vậy, bộ đệm ở trạng thái linh hoạt trong đó các kích thước được cố định khi được sử dụng làm đầu vào mô hình và ở trạng thái động khi được sử dụng làm đầu ra mô hình. Có thể sử dụng cùng một bộ đệm với các hình dạng đầu ra khác nhau trong các lần thực thi khác nhau và trình điều khiển phải xử lý việc thay đổi kích thước bộ đệm một cách chính xác.

Miền bộ nhớ là một tính năng tùy chọn. Trình điều khiển có thể xác định rằng nó không thể hỗ trợ một yêu cầu phân bổ nhất định vì một số lý do. Ví dụ:

  • Bộ đệm được yêu cầu có kích thước động.
  • Trình điều khiển có các hạn chế về bộ nhớ khiến nó không thể xử lý các bộ đệm lớn.

Có thể có nhiều luồng khác nhau đọc đồng thời từ bộ đệm do trình điều khiển quản lý. Việc truy cập đồng thời vào bộ đệm để ghi hoặc đọc/ghi là không xác định, nhưng nó không được làm hỏng dịch vụ trình điều khiển hoặc chặn người gọi vô thời hạn. Trình điều khiển có thể trả về lỗi hoặc để nội dung của bộ đệm ở trạng thái không xác định.