Internalizacija nizova u MicroPythonu¶
MicroPython koristi string interning kako bi uĹĄtedio i RAM i ROM. Time se izbjegava pohranjivanje dvostrukih kopija istog niza. Prvenstveno se to odnosi na identifikatore u vaĹĄem kodu, jer se neĹĄto poput naziva funkcije ili varijable vrlo vjerojatno pojavljuje na viĹĄe mjesta u kodu. U MicroPythonu se internalizirani niz naziva QSTR (uniQue STRing).
QSTR vrijednost (tipa qstr) je indeks u povezanoj listi QSTR spremnika (pools). QSTR-ovi pohranjuju svoju duljinu i hash svog sadrĹžaja za brzu usporedbu tijekom procesa uklanjanja duplikata. Sve operacije bytecodea koje rade s nizovima koriste QSTR argument.
Generiranje QSTR-ova pri prevoÄenju¶
U MicroPython C kodu, svi nizovi koji bi trebali biti internalizirani u konaÄnom ugraÄenom programu (firmware) zapisuju se kao MP_QSTR_Foo. Pri prevoÄenju to Äe se procijeniti na qstr vrijednost koja pokazuje na indeks "Foo" u QSTR spremniku.
ViĹĄekorakovni proces u Makefile omoguÄuje da ovo funkcionira. Ukratko, taj proces ima tri dijela:
PronaÄi sve
MP_QSTR_Footokene u kodu.Generirati statiÄki QSTR spremnik koji sadrĹži sve podatke nizova (ukljuÄujuÄi duljine i hasheve).
Zamijeniti sve
MP_QSTR_Foo(putem pretprocesora) njihovim odgovarajuÄim indeksom.
MP_QSTR_Foo tokeni traĹže se u dva izvora:
Sve datoteke navedene u
$(SRC_QSTR). To je sav C kod (tj.py,extmod,ports/stm32), ali ne ukljuÄuje kod treÄih strana poputlib.Dodatni
$(QSTR_GLOBAL_DEPENDENCIES)(koji ukljuÄujempconfig*.h).
Napomena: frozen_mpy.c (generiran pomoÄu mpy-tool.py) ima vlastito generiranje QSTR-ova i vlastiti spremnik.
Neki dodatni nizovi koji se ne mogu izraziti sintaksom MP_QSTR_Foo (npr. sadrĹže nealfanumeriÄke znakove) eksplicitno se navode u qstrdefs.h i qstrdefsport.h putem varijable $(QSTR_DEFS).
Obrada se odvija u sljedeÄim fazama:
qstr.i.lastje rezultat spajanja svake pojedine ulazne datoteke koja je proĹĄla kroz C pretprocesor. To znaÄi da Äe se sav uvjetno onemoguÄen kod ukloniti, a makroi proĹĄiriti. To znaÄi da u spremnik ne dodajemo nizove koji se neÄe koristiti u konaÄnom ugraÄenom programu (firmware). BuduÄi da u ovoj fazi (zahvaljujuÄi makrouNO_QSTRkoji dodajeQSTR_GEN_CFLAGS) nema definicije zaMP_QSTR_Foo, on prolazi kroz ovu fazu nepromijenjen. Ova datoteka takoÄer ukljuÄuje komentare iz pretprocesora koji sadrĹže informacije o broju retka. Imajte na umu da ovaj korak koristi samo datoteke koje su se promijenile, ĹĄto znaÄi da Äeqstr.i.lastsadrĹžavati samo podatke iz datoteka koje su se promijenile od posljednjeg prevoÄenja.qstr.splitje prazna datoteka stvorena nakon pokretanjamakeqstrdefs.py splitna qstr.i.last. Koristi se samo kao ovisnost koja oznaÄava da je korak pokrenut. Ova skripta ispisuje jednu datoteku po ulaznoj C datoteci,genhdr/qstr/...file.c.qstr, koja sadrĹži samo podudarne QSTR-ove. Svaki QSTR ispisuje se kaoQ(Foo). Ovaj korak je nuĹžan za kombiniranje postojeÄih datoteka s novim podacima generiranima iz inkrementalnog aĹžuriranja uqstr.i.last.qstrdefs.collected.hje rezultat spajanjagenhdr/qstr/*pomoÄumakeqstrdefs.py cat. Ovo je sada potpuni skupMP_QSTR_FoopronaÄenih u kodu, sada formatiran kaoQ(Foo), jedan po retku, s duplikatima. Ova datoteka aĹžurira se samo ako se skup qstr-ova promijenio. Hash QSTR podataka zapisuje se u drugu datoteku (qstrdefs.collected.h.hash) koja omoguÄuje praÄenje promjena kroz buildove.Generirati enumeraciju, Äiji svaki unos preslikava
MP_QSTR_Foona njegov odgovarajuÄi indeks. Spajaqstrdefs.collected.hsqstrdefs*.h, zatim transformira svaki redak izQ(Foo)u"Q(Foo)"kako bi proĹĄli kroz pretprocesor nepromijenjeni. Zatim se pretprocesor koristi za obradu bilo kakvog uvjetnog prevoÄenja uqstrdefs*.h. Zatim se transformacija poniĹĄtava natrag uQ(Foo)i sprema kaoqstrdefs.preprocessed.h.qstrdefs.generated.hje rezultatmakeqstrdata.py. Za svakiQ(Foo)u qstrdefs.preprocessed.h (uz neke dodatne Ävrstodefinirane), ispisujeQDEF(MP_QSTR_Foo, (const byte*)"hash" "Foo").
Zatim se u glavnom prevoÄenju dvije stvari dogaÄaju s qstrdefs.generated.h:
U qstr.h, svaki QDEF postaje unos u enumu, ĹĄto Äini
MP_QSTR_Foodostupnim kodu i jednakim indeksu tog niza u QSTR tablici.U qstr.c, stvarna tablica QSTR podataka generira se kao elementi
mp_qstr_const_pool->qstrs.
Generiranje QSTR-ova pri izvoÄenju¶
Dodatni QSTR spremnici mogu se stvoriti pri izvoÄenju tako da im se mogu dodavati nizovi. Na primjer, kod:
foo[x] = 3
Bit Äe potrebno stvoriti QSTR za vrijednost x kako bi je mogao koristiti „load attr” bytecode.
TakoÄer, pri prevoÄenju Python koda, za identifikatore i literale potrebno je stvoriti QSTR-ove. Napomena: samo literali kraÄi od 10 znakova postaju QSTR-ovi. To je zato ĹĄto obiÄan niz na gomili (heap) uvijek zauzima najmanje 16 bajtova (jedan GC blok), dok QSTR-ovi omoguÄuju da se uÄinkovitije zapakiraju u spremnik.
QSTR spremnici (i osnovni „chunkovi” koji pohranjuju podatke nizova) alociraju se na zahtjev na gomili (heap) s minimalnom veliÄinom.