4.19. Paměťové pooly¶
Kamera, která uchovává tři snímky v plném rozlišení v poolu snímkového bufferu (frame buffer), souběžně provozuje samostatný náhledový buffer a přitom má stále místo pro Python skript a jeho objekty, žongluje s větším množstvím paměti, než kolik by mohl poskytnout jediný blok RAM na MCU. MicroPython vše vměstná tím, že to rozprostře přes několik odlišných druhů paměti, které MCU poskytuje, a tím, že každý druh alokace směruje do druhu paměti, který skutečně potřebuje.
4.19.1. Druhy paměti¶
Moderní MCU v OpenMV Cam zpřístupňuje čtyři odlišné druhy paměti. První je pro aplikaci neviditelný; zbylé tři jsou pooly, ze kterých mohou alokace pocházet.
Datová cache CPU – malá, velmi rychlá oblast paměti, která se nachází mezi CPU a zbytkem RAM. Když CPU čte nebo zapisuje hodnotu z hlavní paměti, cache automaticky uchová kopii, takže opakované přístupy ke stejným datům zůstávají v cache a nikdy neplatí cenu za cestu do pomalejší paměti. Cache není pool, ze kterého pocházejí alokace. Je pro aplikaci transparentní – pouze způsobuje, že zbytek RAM v praxi působí rychleji, než by naznačovala jeho surová latence, až do bodu, kdy se pracovní množina přestane do cache vejít.
Těsně propojená paměť procesoru – malý blok RAM zapojený přímo k CPU bez sběrnice mezi nimi. Přístup v jediném cyklu, nikdy nemine, nikdy nečeká. Alokace, které skutečně potřebují nejrychlejší možnou paměť – kde záleží na každém cyklu latence – pocházejí z tohoto poolu.
Rychlá on-chip paměť – několik stovek kilobajtů až přibližně megabajt RAM zabudovaný v pouzdře MCU. Nízká latence, vysoká propustnost, ale omezená velikostí. Zde sídlí halda MicroPythonu, aby přístupy k Python objektům zůstaly rychlé; menší pracovní buffery, kterých se CPU často dotýká, sdílejí tento pool.
Pomalejší hromadná paměť – na deskách, které kombinují MCU s externím paměťovým čipem, desítky megabajtů off-chip RAM dosažitelné přes externí sběrnici. Mnohem větší, ale každý přístup trvá déle než u on-chip paměti; datová cache skryje velkou část této ceny pro pracovní množiny, které dokáže pojmout, a rozdíl se projeví u operací, které procházejí daty příliš velkými na to, aby se uložila do cache. Používá se pro alokace, které musí být velké a u nichž CPU snese nižší rychlost – nejdůležitější je pool snímkového bufferu (frame buffer).
Desky v této rodině se nacházejí na spektru: některé mají pouze on-chip RAM; některé kombinují on-chip RAM s mnohem větším externím blokem. Každý ze tří alokovatelných druhů je považován za paměťový pool – blok, ze kterého pocházejí alokace – a je označen tak, aby si každý požadavek mohl vyžádat druh paměti, který skutečně potřebuje.
4.19.2. Primární snímkový buffer (frame buffer)¶
Snímkový buffer (frame buffer), o který se opírá snapshot(), nepožaduje rychlou paměť. Požaduje dostatek paměti – nic víc. To jej umístí do toho poolu, který je největší, takže na desce s on-chip i externí pamětí přistane snímkový buffer v externím bloku.
Trojnásobně bufferovaný snímkový buffer (frame buffer) v plném rozlišení je na většině součástek příliš velký na to, aby se vešel do rychlého on-chip poolu; větší pool je jediný, který jej vůbec dokáže pojmout. Datová cache CPU skryje velkou část ceny za jednotlivý přístup, když aplikace obraz zpracovává, a DMA engine, který plní snímkový buffer ze senzoru, tak jako tak drží krok s datovým tokem senzoru.
Přesná velikost, kterou snímkový buffer (frame buffer) zabírá, se odvozuje z aktuálního pixformat(), framesize() a počtu framebuffers(); roste nebo se zmenšuje pokaždé, když se kterýkoli z nich změní.
4.19.3. Sekundární snímkové buffery senzoru¶
Druhá instance CSI dostane svůj vlastní snímkový buffer (frame buffer) alokovaný ze stejného poolu, který používá primární. Pool je sdílený; buffery jsou nezávislé. Stopa sekundárního senzoru je obvykle mnohem menší než primárního, protože sekundární senzory běží na nižších rozlišeních, takže paměť navíc, kterou druhý snímkový buffer zabírá, je malým zlomkem té primární.
4.19.4. Streamovací snímkový buffer (frame buffer)¶
Buffer náhledu obrazu je výjimkou. Není za běhu alokován z žádného z poolů; je to pevná oblast vyhrazená v době sestavení se známou adresou a známou velikostí. Tím se náhledová cesta drží stranou od všech ostatních alokací – tato oblast existuje od startu a nikdy se nepřesouvá.
4.19.5. Halda MicroPythonu¶
Python objekty – proměnné, seznamy, slovníky, instance tříd, obal Image, který vrací volání snapshot(), každý řetězec a n-tice, které aplikace vytvoří – sídlí na haldě MicroPythonu spravované garbage collectorem, která je oddělená od paměťových poolů kamery. Halda spravovaná garbage collectorem (GC) je oblast paměti, kterou si MicroPython spravuje sám: Python kód z ní alokuje implicitně pokaždé, když je vytvořen objekt, a MicroPython periodicky prochází haldu a získává zpět prostor zabraný objekty, na které již aplikace neodkazuje, takže aplikace nikdy nemusí nic uvolňovat ručně.
Při startu je pro GC haldu vyhrazena vyhrazená oblast, typicky umístěná v rychlé on-chip paměti, aby přístup z Pythonu zůstal rychlý, s volitelným přetečením do většího externího bloku na deskách, které potřebují více rezervy pro velké datové struktury.
Objekt Image vrácený metodou snapshot() je malý obalový objekt na GC haldě; podkladová pixelová data sídlí ve snímkovém bufferu (frame buffer) v jednom z poolů kamery. Tyto dvě věci nikdy nesoupeří o stejnou paměť.
4.19.6. Vše dohromady¶
Směrování každého druhu alokace do správného poolu – velké buffery do většího poolu, kam se vejdou, data citlivá na latenci do rychlejších poolů, Python haldu do její vlastní oblasti, náhled do jeho vyhrazeného slotu – je to, co umožňuje provozovat vedle sebe pipeline pro snímání v plném rozlišení, náhledový kanál a netriviální Python skript na součástkách, které mají celkem jen pár megabajtů rychlé paměti.