Kumpulan memori

Halaman ini menjelaskan struktur data dan metode yang digunakan untuk menyampaikan buffering operand secara efisien antara driver dan framework.

Pada waktu kompilasi model, framework akan memberikan nilai operand konstan ke driver. Bergantung pada masa aktif operand konstan, nilainya berada di vektor HIDL atau kumpulan memori bersama.

  • Jika masa aktifnya adalah CONSTANT_COPY, nilai tersebut berada di kolom operandValues dalam struktur model. Karena nilai dalam vektor HIDL disalin selama komunikasi antarproses (IPC), hal ini biasanya hanya digunakan untuk menyimpan sejumlah kecil data seperti operand skalar (misalnya, skalar aktivasi di ADD) dan parameter tensor kecil (misalnya, tensor bentuk di RESHAPE).
  • Jika masa aktifnya adalah CONSTANT_REFERENCE, nilainya terletak di kolom pools dari struktur model. Hanya tuas kumpulan memori bersama yang diduplikasi selama IPC, bukan menyalin nilai mentah. Oleh karena itu, akan lebih efisien untuk menyimpan data dalam jumlah besar (misalnya, parameter bobot dalam konvolusi) menggunakan kumpulan memori bersama daripada vektor HIDL.

Pada waktu eksekusi model, framework menyediakan buffering operand input dan output ke driver. Tidak seperti konstanta waktu kompilasi yang mungkin dikirim dalam vektor HIDL, data input dan output dari eksekusi selalu dikomunikasikan melalui kumpulan kumpulan memori.

Jenis data HIDL hidl_memory digunakan dalam kompilasi dan eksekusi untuk mewakili kumpulan memori bersama yang tidak dipetakan. Driver harus memetakan memori sesuai agar dapat digunakan berdasarkan nama jenis data hidl_memory. Nama memori yang didukung adalah:

  • ashmem: Kenangan bersama Android. Untuk detail selengkapnya, lihat memori.
  • mmap_fd: Memori bersama yang didukung oleh deskriptor file melalui mmap.
  • hardware_buffer_blob: Memori bersama yang didukung oleh AHardwareBuffer dengan format AHARDWARE_BUFFER_FORMAT_BLOB. Tersedia dari Neural Networks (NN) HAL 1.2. Untuk detail selengkapnya, lihat AHardwareBuffer.
  • hardware_buffer: Memori bersama yang didukung oleh AHardwareBuffer umum yang tidak menggunakan format AHARDWARE_BUFFER_FORMAT_BLOB. Buffer hardware mode non-BLOB hanya didukung dalam eksekusi model.Tersedia dari NN HAL 1.2. Untuk detail selengkapnya, lihat AHardwareBuffer.

Dari NN HAL 1.3, NNAPI mendukung domain memori yang menyediakan antarmuka pengalokasi untuk buffer yang dikelola driver. Buffer yang dikelola driver juga dapat digunakan sebagai input atau output eksekusi. Untuk mengetahui detail selengkapnya, lihat Domain memori.

Driver NNAPI harus mendukung pemetaan nama memori ashmem dan mmap_fd. Dari NN HAL 1.3, driver juga harus mendukung pemetaan hardware_buffer_blob. Dukungan untuk domain memori dan hardware_buffer mode non-BLOB umum bersifat opsional.

{i>AHardwareBuffer<i}

AHardwareBuffer adalah jenis memori bersama yang menggabungkan buffer GTFS. Di Android 10, Neural Networks API (NNAPI) mendukung penggunaan AHardwareBuffer, sehingga driver dapat melakukan eksekusi tanpa menyalin data, yang meningkatkan performa dan konsumsi daya untuk aplikasi. Misalnya, stack HAL kamera dapat meneruskan objek AHardwareBuffer ke NNAPI untuk beban kerja machine learning menggunakan tuas AHardwareBuffer yang dihasilkan oleh NDK kamera dan API NDK media. Untuk informasi selengkapnya, lihat ANeuralNetworksMemory_createFromAHardwareBuffer.

Objek AHardwareBuffer yang digunakan di NNAPI diteruskan ke driver melalui struct hidl_memory yang bernama hardware_buffer atau hardware_buffer_blob. Struct hidl_memory hardware_buffer_blob hanya mewakili objek AHardwareBuffer dengan format AHARDWAREBUFFER_FORMAT_BLOB.

Informasi yang diperlukan oleh framework dienkode di kolom hidl_handle dari struct hidl_memory. Kolom hidl_handle menggabungkan native_handle, yang mengenkode semua metadata yang diperlukan tentang buffer AHardwareBuffer atau Gralloc.

Driver harus mendekode kolom hidl_handle yang disediakan dengan benar dan mengakses memori yang dijelaskan oleh hidl_handle. Saat metode getSupportedOperations_1_2, getSupportedOperations_1_1, atau getSupportedOperations dipanggil, driver harus mendeteksi apakah metode tersebut dapat mendekode hidl_handle yang disediakan dan mengakses memori yang dijelaskan oleh hidl_handle. Persiapan model harus gagal jika kolom hidl_handle yang digunakan untuk operand konstan tidak didukung. Eksekusi harus gagal jika kolom hidl_handle yang digunakan untuk operand input atau output eksekusi tidak didukung. Sebaiknya driver menampilkan kode error GENERAL_FAILURE jika persiapan atau eksekusi model gagal.

Domain memori

Untuk perangkat yang menjalankan Android 11 atau yang lebih tinggi, NNAPI mendukung domain memori yang menyediakan antarmuka pengalokasi untuk buffer yang dikelola driver. Hal ini memungkinkan penerusan memori native perangkat di seluruh eksekusi, sehingga menyembunyikan dan mengubah penyalinan data yang tidak perlu antara eksekusi berurutan pada driver yang sama. Alur ini diilustrasikan dalam Gambar 1.

Buffering aliran data dengan dan tanpa domain memori

Gambar 1. Buffering aliran data menggunakan domain memori

Fitur domain memori ditujukan untuk tensor yang sebagian besar bersifat internal bagi driver dan tidak memerlukan akses sering di sisi klien. Contoh tensor tersebut mencakup tensor status dalam model urutan. Untuk tensor yang perlu sering mengakses CPU pada sisi klien, sebaiknya gunakan gabungan memori bersama.

Untuk mendukung fitur domain memori, terapkan IDevice::allocate agar framework dapat meminta alokasi buffer yang dikelola driver. Selama alokasi, framework menyediakan properti dan pola penggunaan berikut untuk buffering:

  • BufferDesc menjelaskan properti buffer yang diperlukan.
  • BufferRole menjelaskan potensi pola penggunaan buffering sebagai input atau output dari model yang disiapkan. Beberapa peran dapat ditentukan selama alokasi buffer, dan buffer yang dialokasikan hanya dapat digunakan sebagai peran yang ditetapkan tersebut.

Buffer yang dialokasikan bersifat internal untuk driver. Pengemudi dapat memilih lokasi buffer atau tata letak data. Saat buffering berhasil dialokasikan, klien driver dapat mereferensikan atau berinteraksi dengan buffering menggunakan token yang ditampilkan atau objek IBuffer.

Token dari IDevice::allocate diberikan saat mereferensikan buffer sebagai salah satu objek MemoryPool dalam struktur Request eksekusi. Untuk mencegah proses mencoba mengakses buffer yang dialokasikan dalam proses lain, driver harus menerapkan validasi yang tepat pada setiap penggunaan buffer. Driver harus memvalidasi bahwa penggunaan buffering adalah salah satu peran BufferRole yang disediakan selama alokasi dan harus segera menggagalkan eksekusi jika penggunaannya ilegal.

Objek IBuffer digunakan untuk penyalinan memori eksplisit. Dalam situasi tertentu, klien driver harus melakukan inisialisasi buffering yang dikelola driver dari kumpulan memori bersama atau menyalin buffering ke kumpulan memori bersama. Contoh kasus penggunaan mencakup:

  • Inisialisasi tensor status
  • Menyimpan hasil menengah dalam cache
  • Eksekusi penggantian di CPU

Untuk mendukung kasus penggunaan ini, driver harus mengimplementasikan IBuffer::copyTo dan IBuffer::copyFrom dengan ashmem, mmap_fd, dan hardware_buffer_blob jika mendukung alokasi domain memori. Driver dapat mendukung mode non-BLOB hardware_buffer secara opsional.

Selama alokasi buffer, dimensi buffer dapat disimpulkan dari operand model yang sesuai dari semua peran yang ditetapkan oleh BufferRole, dan dimensi yang disediakan dalam BufferDesc. Jika semua informasi dimensi digabungkan, buffer mungkin memiliki dimensi atau peringkat yang tidak diketahui. Dalam kasus tersebut, buffering berada dalam status fleksibel dengan dimensi yang tetap saat digunakan sebagai input model dan dalam status dinamis saat digunakan sebagai output model. Buffer yang sama dapat digunakan dengan berbagai bentuk output dalam eksekusi yang berbeda dan driver harus menangani pengubahan ukuran buffer dengan benar.

Domain memori adalah fitur opsional. Driver dapat menentukan bahwa driver tidak dapat mendukung permintaan alokasi tertentu karena sejumlah alasan. Contoh:

  • Buffer yang diminta memiliki ukuran dinamis.
  • Driver memiliki batasan memori yang mencegahnya menangani buffering besar.

Beberapa thread yang berbeda dapat membaca dari buffering yang dikelola driver secara serentak. Mengakses buffer secara bersamaan untuk menulis atau membaca/menulis tidak ditentukan, tetapi tidak boleh membuat layanan driver error atau memblokir pemanggil secara tidak terbatas. Pengemudi dapat menampilkan error atau membiarkan konten buffering dalam status yang tidak ditentukan.