Filemapping

Fórumok

Egy érdekes program: tutor/filemap/demo.prg


function main()
local fd:=fopen("demo.prg")
local map:=filemap.open(fd)

    fclose(fd) //már nem kell

    // map olyan, mint egy binary string
    // működnek rá a függvények és operátorok
    
    ? valtype(map)
    ? len(map)
    ? map::left(20)
    ? map::right(20)
    ? at(a"demo.prg",map)
    ? rat(a"demo.prg",map)
    ? map[1..32]
    ? map[1],map[2],map[3],map[4],map[5],map[6],map[7],map[8]
    ? a"demo.prg"$map
    ? a"function main()"<=map

// A közönséges bájtstringekkel szemben egy map óriási, akár
// sok GB is lehet (amekkora a címtér), ugyanis valójában nincs 
// benn a tényleges memóriában (csak a virtuális memóriában),
// és az operációs rendszer biztosítja, hogy a buffer megcímzett
// részei (amikor kell) bekerüljenek a tényleges fizikai memóriába.
//
// A map[offset..offset+1023] kifejezés egy avi fájl akármelyik
// részletét beolvassa. Tudni kell, hogy az ilyen "beolvasott" részek
// a fizikai memóriába kerülnek, ezért nem lehetnek akármilyen nagyok,
// a CCC védekezik a MAXBINLEN-nél nagyobb változók ellen.
// Pl. a map[..] vagy substr(map,1) kifejezések áttöltenék az egész 
// buffert a virtuális memóriából a fizikaiba, ami csak akkor sikerülhet,
// ha a buffer mérete < MAXBINLEN.

A program kiírásai:


X
      1288
function main()
loca
mérete < MAXBINLEN.
        34
       420
function main()
local fd:=fopen(
f u n c t i o n
.T.
.T.

Hozzászólások

Természetesen Jávában is van filemapping.


File f = ...
RandomAccessFile raf = new RandomAccessFile(f, "rw");
FileChannel fc = raf.getChannel();
ByteBuffer fileArea = fc.map(MapMode.READ_WRITE, offset, len);

Az előző demo.prg CCC programban a filemappingnak nincs a ByteBuffer-hez hasonló burkoló osztálya. Mivel a map burkoló osztály nélkül is jól használható, nem foglalkozom a becsomagolással. (Akkor sem, ha egyesek majd megállapítják, hogy így lábon lövi magát a programozó.)

A CCC map változó szinte pontosan ugyanolyan, mint egy közönséges binary string.


local x:=a"vanaki forrón szereti" //binary string
local m:=filemap.open(fd)

Az x és m változóknak ugyanaz a Clipper típusa, ugyanazok a műveletek, függvények, operátorok működnek velük. A különbség, hogy az x (referencia) memóriabuffere egy programba fordított string literál, az m memóriabuffere viszont egy filemap. A string literál nem tud megszűnni, a filemap megszűnik, ha lezárják. Az x maximális mérete MAXBINLEN (CCC fordítási opció), az m max mérete a címtér, vagyis a _virtuális_ memória mérete. A szemétgyűjtés mindkét buffert kikerüli.

A CCC filemap-ban külön érdekes, hogy nem kell hozzá módosítani a CCC futtató környezetet, sem a fordítót, sem az alapkönyvtárakat, mert alkalmazásszinten megoldható. Egy kb. száz soros C modulban megvan a filemap.open, filemap.close, filemap.sync primitív (valójában csak interfészek), ez a C modul aztán az alkalmazás többi programjával együtt automatikusan fordul. Ez nagyon jellemző a CCC-re, mármint, hogy nem kell az égvilágon mindennek eleve benne lennie az alapkönyvtárakban, mert amire szükség van, alkalmazásszinten bevehető.

Egyébként a filemapping ötlete akkor jött, amikor fájlba rögzített audio streameket akartam összetoldani. Egyórásnál valamivel hosszabb audio stream szakaszaim vannak, amik az órahatárokon pár perc átfedő részt tartalmaznak. Úgy toldom őket össze, hogy az átfedő részeken egyező bájtsorozatot keresek. A filemap sokkal kényelmesebb eszköz a keresésre, mint az fread.

--
CCC3

Egy érdekes alkalmazás.

Btree indexet kell készíteni egy sokmillió rekordos táblához. Ha a kulcsokat véletlen sorrendben adjuk hozzá a btree-hez, akkor egy idő után az eljárás a végtelenségig lelassul, mert örökösen át kell rendezni a btree-t (split). Az indexelés órákig vagy akár napokig is eltart. (Vagy a diszk szétesik, mielőtt elkészülne a btree.)

Célszerűbb a kulcsokat előzőleg rendezni, és növekvő sorrendben breakni a btree-be, akkor a kapott struktúra tömör lesz, és menet közben egyáltalán nincs szükség átrendezésre. Hogyan történjen a rendezés?

Egy lehetőség: Kiírjuk a kulcsokat egy fájlba (szép katonásan, sorban egymás után), a fájlt bemapoljuk, és a mapot a C könyvtári qsort-tal (!) rendezzük. 1-2 perc alatt kész. A poén, hogy egy memóriatömbökre megírt rendező algoritmust használtunk egy fájlra.

--
CCC3

Kísérletezgetünk egy kicsit.


function main()
local fd
local map1,map2
local size:=0x50000000
//local size:=0x200000000

    inkey(0)

    fd:=fcreate("shared")
    chsize(fd,size)
    map1:=filemap.open(fd,"rw")
    fclose(fd)

    inkey(0)

    fd:=fopen("shared")
    map2:=filemap.open(fd,"r")
    fclose(fd)

    inkey(0)

Elindítjuk a top-ot és elindítjuk a példaprogramot. A progam az inkey(0) soroknál billentyűleütésre vár, ezeken a helyeken van időnk megnézni a top VIRT és RES oszlopát. A VIRT a program által használt virtuális memória nagyságát, a RES a fizikai memóriát mutatja. 32-bites gépen ilyen adatokat kapok:


              VIRT  RES
1. megállás   6672 2012
2. megállás  1286m 2068
3. megállás  2566m 2072

Néhány dolog, ami a hasonló próbálgatásokból kiderül:

(1) Hogy a program mennyi memóriát tud használni, az nem a fizikai, hanem a virtuális memória nagyságától függ. Ezt úgy kell érteni, hogy a (C könyvtári) qsort függvény le tud rendezni akkora mapot, ami egyszerre nem fér be a fizikai memóriába. Az én 32-bites gépemben pl. csak 1.5G memória van, a program mégis közel 3G memóriát használ.

(2) 32-bites gépen a virtuális memória (címtér) max mérete elvileg 4G. A felső 1G tartományt a Linux valami speciális célra használhatja, ezért a gyakorlatban a határ 3G. A példaprogramban a size:=0x50000000 értéke tehát a felső határ közelében van.

(3) Egy processzen belül a mapok mérete összeadódik, és az összegre vonatkozik a felső határ.

Átvisszük a példaprogramot 64-bites rendszerre. Azt tapasztaljuk, hogy a 3G-s limit megszűnik. A size:=0x200000000 értékkel a 2G fizikai memóriával rendelkező gépemen ilyen adatokat mutat a top:


  VIRT  RES
 22620 2788
 8214m 2832
 16.0g 2832

Vagyis a 2G-s gép akár 16G memóriát használ. Az elvi határ 64-bit, CCC-ben egyéb korlátok miatt a gyakorlati határ kb. 51-52 bit.

A tanulság, amire ki akarok lyukadni, hogy a 64-bites rendszereknek akkor is értelme van, ha a gépben nincs sok fizikai memória.

Végül: Ne felejtsük el letörölni a példaprogramban létrehozott 8G-s fájlt.
--
CCC3