4.19. Pool memori

Kamera yang menyimpan tiga bingkai resolusi penuh dalam pool framebuffer, menjalankan buffer pratinjau terpisah secara bersamaan, dan masih memiliki ruang untuk skrip Python beserta objek-objeknya, mengelola lebih banyak memori daripada yang dapat disediakan oleh satu blok RAM di MCU. MicroPython menampung semuanya dengan menyebarkannya ke beberapa jenis memori berbeda yang disediakan MCU, dan dengan mengarahkan setiap jenis alokasi ke jenis memori yang benar-benar dibutuhkan.

4.19.1. Jenis-jenis memori

MCU OpenMV Cam modern menghadirkan empat jenis memori yang berbeda. Yang pertama tidak terlihat oleh aplikasi; tiga lainnya adalah pool tempat alokasi dapat diambil.

  • Cache data CPU -- wilayah memori kecil yang sangat cepat yang berada di antara CPU dan sisa RAM. Ketika CPU membaca atau menulis nilai dari memori utama, cache secara otomatis menyimpan salinannya, sehingga akses berulang ke data yang sama tetap berada di cache dan tidak perlu membayar biaya akses ke memori yang lebih lambat. Cache bukan pool tempat alokasi berasal. Cache transparan terhadap aplikasi -- cache hanya membuat sisa RAM terasa lebih cepat dalam praktiknya daripada yang ditunjukkan oleh latensi mentahnya, hingga titik di mana working set tidak lagi muat di dalamnya.

  • Memori prosesor yang terhubung erat -- blok kecil RAM yang terhubung langsung ke CPU tanpa bus di antaranya. Akses single-cycle, tidak pernah miss, tidak pernah menunggu. Alokasi yang benar-benar membutuhkan memori secepat mungkin -- di mana setiap siklus latensi penting -- berasal dari pool ini.

  • Memori on-chip yang cepat -- beberapa ratus kilobyte hingga sekitar satu megabyte RAM, tertanam dalam paket MCU. Latensi rendah, bandwidth tinggi, tetapi terbatas dalam ukuran. Heap MicroPython tinggal di sini agar akses objek Python tetap cepat; buffer kerja yang lebih kecil yang sering disentuh CPU berbagi pool ini.

  • Memori massal yang lebih lambat -- pada board yang memasangkan MCU dengan chip memori eksternal, puluhan megabyte RAM off-chip yang diakses melalui bus eksternal. Jauh lebih besar, tetapi setiap akses membutuhkan waktu lebih lama daripada memori on-chip; cache data menyembunyikan banyak biaya tersebut untuk working set yang dapat ditampungnya, dan perbedaannya terlihat pada operasi yang menyapu data terlalu besar untuk di-cache. Digunakan untuk alokasi yang harus berukuran besar dan CPU dapat mentolerirnya pada kecepatan lebih lambat -- yang paling penting, pool framebuffer.

Board dalam keluarga ini berada pada spektrum: beberapa hanya memiliki RAM on-chip; beberapa memasangkan RAM on-chip dengan blok eksternal yang jauh lebih besar. Masing-masing dari tiga jenis yang dapat dialokasikan diperlakukan sebagai pool memori -- potongan tempat alokasi berasal -- dan diberi label sehingga setiap permintaan dapat meminta jenis memori yang benar-benar dibutuhkan.

4.19.2. Framebuffer utama

Framebuffer yang mendukung snapshot() tidak meminta memori yang cepat. Ia meminta memori yang cukup -- tidak lebih. Itu menempatkannya di pool mana pun yang terbesar, sehingga pada board dengan memori on-chip dan eksternal, framebuffer mendarat di blok eksternal.

Framebuffer triple-buffered dengan resolusi penuh terlalu besar untuk muat di pool on-chip yang cepat pada sebagian besar komponen; pool yang lebih besar adalah satu-satunya yang dapat menampungnya sama sekali. Cache data CPU menyembunyikan banyak biaya per-akses ketika aplikasi memproses citra, dan mesin DMA yang mengisi framebuffer dari sensor mengimbangi laju data sensor dengan cara apapun.

Ukuran tepat yang diambil framebuffer dipilih dari pixformat(), framesize(), dan jumlah framebuffers() saat ini; ukurannya bertambah atau berkurang setiap kali salah satunya berubah.

4.19.3. Framebuffer sensor sekunder

Instans CSI kedua mendapatkan framebuffer-nya sendiri, dialokasikan dari pool yang sama yang digunakan oleh yang utama. Pool tersebut digunakan bersama; buffer-nya independen. Jejak memori sekunder biasanya jauh lebih kecil dari yang utama, karena sensor sekunder beroperasi pada resolusi yang lebih rendah, sehingga memori tambahan yang diambil framebuffer kedua hanya sebagian kecil dari yang utama.

4.19.4. Framebuffer stream

Buffer pratinjau citra adalah pengecualian. Buffer ini tidak dialokasikan dari pool manapun saat runtime; buffer ini adalah wilayah tetap yang dicadangkan saat waktu build, dengan alamat yang diketahui dan ukuran yang diketahui. Itu membuat jalur pratinjau tidak mengganggu setiap alokasi lain -- wilayah ini ada sejak boot dan tidak pernah berpindah.

4.19.5. Heap MicroPython

Objek Python -- variabel, list, dictionary, instans class, wrapper Image yang dikembalikan oleh panggilan snapshot(), setiap string dan tuple yang dibuat oleh aplikasi -- tinggal di heap yang dikelola garbage collection MicroPython, yang terpisah dari pool memori kamera. Heap GC (garbage-collected) adalah wilayah memori yang dikelola sendiri oleh MicroPython: kode Python mengalokasikan darinya secara implisit setiap kali objek dibuat, dan MicroPython secara berkala memindai heap dan mengambil kembali ruang yang ditempati oleh objek yang tidak lagi direferensikan oleh aplikasi, sehingga aplikasi tidak perlu membebaskan apapun secara manual.

Wilayah khusus disisihkan untuk heap GC saat boot, biasanya ditempatkan di memori on-chip yang cepat agar akses Python tetap cepat, dengan opsi overflow ke blok eksternal yang lebih besar pada board yang membutuhkan lebih banyak ruang untuk struktur data besar.

Image yang dikembalikan oleh snapshot() adalah objek wrapper kecil di heap GC; data piksel yang mendasarinya tinggal di framebuffer di salah satu pool kamera. Keduanya tidak pernah bersaing untuk memori yang sama.

4.19.6. Menyatukan semuanya

Mengarahkan setiap jenis alokasi ke pool yang tepat -- buffer besar ke pool yang lebih besar tempat mereka muat, data yang sensitif terhadap latensi ke pool yang lebih cepat, heap Python ke wilayahnya sendiri, pratinjau ke slot yang dicadangkan -- inilah yang memungkinkan menjalankan pipeline penangkapan resolusi penuh, saluran pratinjau, dan skrip Python yang tidak sepele secara bersamaan pada komponen yang hanya memiliki beberapa megabyte memori cepat secara total.