Java, sebesség, gyorstár, betöltés, futási teljesítmény..... tökös-mákos
2020-04-30T10:22:37+02:00
2020-05-02T00:48:13+02:00
2022-07-20T15:31:52+02:00
  • Jó, akkor nézzük :)

    Ezt írta hoat4:

    Ha fut azon a gépen a "műveleti kódon" kívül bármi, mondjuk egy kernel, akkor nem is lehet máshogy mérni, egy interrupt miatti context switch is sokat ronthat a cache misseken.

    Te erre replikáztál: 

    Éppen ezért volt balgaság BlaZember részéről bedobni az állítólagos tesztjei által mutatott hit ratio, aminek ebben a formában, ahogy ő előadta kb. annyi relevanciája volt azzal, amire bedobta, mint a moszkvicsosztogatásnak a mercédeszosztogatáshoz.

    Ezzel pont azt mondod, hogy nem lehet kerneltől (vagy más processtől) függetlenül mérni. Most meg azt mondod, hogy te ilyet nem is mondtál, és a kernelt én hoztam fel... 

    Aztán nézzük az L2-t...

    És bármi, amit egy benchmarkolt programon át mérsz, abba beleszámít és abban benne van a gép minden komponense és tulajdonsága, ahogy a program szervezésének és kódjának minden sajátossága is. Amikből nem tudod mágikusan kiszűrni az L2 hit/miss arányát. Ahhoz azt külön kellene mérni, figyelni.

    Legyünk jóindulatúak, és mondjuk azt, hogy ez a két kiemelt mondat a végén akkor azt jelentette, hogy nem tudod az L2 cache/miss arányát kizárólag a saját kódod függvényében vizsgálni a bármi mástól függetlenül. De ez így sem igaz. Mert tudod, ha akarod. Tudsz különválasztani mérést user/kernel kód mentén, pid mentén, adott magra, programodon belül 2 tetszőleges pont között elindíthatod, leállíthatod a mérést. Átteheted a programod vizsgált szálait izolált magokra, ahonnan eltünteted az irq feldolgozást, kikapcsolod a watchdogot, és bármit, amit a kernel az adott magokon szeretne végrehajtani. Konkrétan context switched se lesz az adott szálak vonatkozásában, és vegytisztán megméred a saját alkalmazásodat. Ha úgy tetszik, minden alkalmazás kódból "kivülre" hívás esetén szüneteltetve a mérést. Úgyhogy de, lehet. Csak nincs értelme, mert a mikrobenchmarkolást kivéve az alkalmazást együtt, a környezetével együtt mérjük, amiben használva lesz. Az egyetlen, amikor annak van bármi értelme amivel "próbáltál megfogni", amikor az alkalmazásod így, minden egyéb processtől (core szinten) izolálva lesz használva. 

    Nem, annak a hülyeségnek, amit amit te írtál a (valójában nem létező) mintafelismerésről, meg annak, amit beidéztél az Intel kézikönyvből, és ami gyakorlatilag azt mondja, hogy amikor a processzor látja hogy közelítesz a lap valamelyik határa felé egy utasítássorral, akkor előre behúzza a következő (vagy előző) lapot, annak semmi köze nincs egymáshoz. Illetve maximum annyi, mint amennyi köze van az ősember kőbaltájának egy CNC géphez.

    Akkor ezt most olvasd el még egyszer.

    Streamer: This prefetcher monitors read requests from the L1 cache for ascending and descending sequences of addresses. Monitored read requests include L1 DCache requests initiated by load and store operations and by the hardware prefetchers, and L1 ICache requests for code fetch. When a forward or backward stream of requests is detected, the anticipated cache lines are prefetched. Prefetched cache lines must be in the same 4K page.

    Ez bizony nem azt csinálja, amit te mondasz (kiemelve a hozzászólásodban vastaggal). Már csak azért sem, mert a prefetcher nem lapokat tölt elő, hanem cache line-okat. Hogy mennyit előre, és melyiket hova, az elég dinamikusan van kezelve. Ami köze ennek van a laphoz, hogy a prefetchelés csak az adott 4K-s lap határáig történik. És a következő lapot, vagy lapról nem fog betölteni a következő demand loadig. Ahhoz, hogy a "következő (vagy előző) lapot" betöltse, vagy arról bármit, kéne egy TLB lookupot is csináljon, ami ráadásul nem is az L2 szintjén van (ezért nem megy 4K laphatár mögé a hw prefetch akkor se, ha nagyobb lapméretet használsz). De aki ebben a témában akkora ász, hogy úgy oszthatja az észt mint te, az ezt persze úgyis tudja. És az arra is rájön, hogy miért nem stimmel a 99.805%-os hit arányt kihozó matekja...

    Egy rövid segítség az idézet értelmezéséhez: monitorozza az L1 load és store műveleteket, és ha azt detektálja (felismerés), hogy folyamatosan csökkenő, vagy növekvő címet hivatkozik a kód (minta), akkor prefetcheli az azt követő valahány cache line-t (L2-be és/vagy L3-ba). Ha szerinted ez nem mintafelismerés, akkor nem tudom mi az :) De teljesen mindegy minek nevezed, ez pont az a működés, amit én mondtam. 

    Viszont respect azért, hogy végre írtál konkrétumot valaminek a(z elképzelésed szerinti) működéséről. Még akkor is, ha az egy félreértelmezése egy angol szövegnek, és totál fals.

    Ha kicsit is értenél bármit is abból, amit ennek kapcsán az elmúlt vagy fél tucat hozzászólásban leírtam, akkor nem kérdeznéd ezt, mert megértenéd, hogy a probléma itt pont az, hogy ezt nem lehet egyértelműen megmondani. Mert hogy egy sokváltozós egyenletben, pl. egy A+B+C+D=E műveletben pusztán az E változásából akarod kiszűrni azt, hogy A, B, C vagy D változása miatt változott -e E, amikor ez nyilván pusztán E ismerete alapján lehetetlen. Sőt, akkor is az lenne, ha még másik kettő változót is ismernél. Ehhez képest meg a valóság az adott helyzetben, hogy te még azt se tudod, hogy a "egyenleted" hány változóból rakódik össze.

    Sajnos ez viszont megint csak bullshit. A valóság az, hogy az egy utasításra eső L2 prefetch több, mint duplája a második mérésben, min az elsőnek. Úgyhogy pont az történt, amit mondtam, vagyis a streamer prefetcher következménye az L2 hit arány növekedése. Ismerve a tesztelési körülményeket és az alkalmazást magát, ez egyértelműen alátámasztja az általam adott értelmezését az L2 hit ratio növekedésének.

    Ehhez képest az, hogy még a saját hit ratio ábrádat sem tudod értelmezni, és azt sem érted, hogy abban nem "nő meg az L2 cache hit és csökken az LLC miss", mert hogy annak százalékos skálája nem a hit és a miss arányokat ábrázolja az egyes gyorstárak vonatkozásában, hanem azt mutatja meg, hogy az összes hozzáférések hány százalékában melyik tárig (milyen "messzire") kellett elmenni az adatért, már igazán semmiség.

    Vagyis, ha az egyik "csíkod" "vékony" a felette lévőkhöz képest (első kép), akkor ott az adott cache rétegben magas volt a miss arány, ha "vastag" (második kép), akkor pedig alacsony. Pl ha az L1 missed 10% (a zöld csík 90%-on áll meg), és 1% az L2, akkor az L1 miss 10%-a volt L2 hit, ha 5%, akkor 50%-a. Remélem segítettem...
    Mutasd a teljes hozzászólást!
  • Amit mi sem bizonyít jobban, minthogy először leírod, hogy az L2 hit arányt nem lehet mérni, majd miután kiderül, hogy de lehet, leírod, hogy nem lehet a kerneltől külön mérni.

    Ami persze megint nem igaz, duplán sem. Hiszen se azt nem írtam, hogy általánosságban az L2 hit arányt ne lehetne mérni, sem a kernelt nem emlegettem. Utóbbi megint egy olyan szó és fogalom, amit a témában te dobsz be először, azt állítva persze, hogy más beszélt erről, miközben nem, senki, nem hogy más, de még te sem, egészen eddig a pontig.

    Ehelyett amit írtam az volt, hogy "kérlek küldj screenshotot arról, hogy megmérted mondjuk a processzorod L2 gyorstárának hit/miss arányát, ráadásul kizárólag csak a te programod és a 1TB-os adatfeldolgozásod vonatkozásában"

    Na, akkor ki az, aki vagy nem olvassa el azt, amit neki írnak, vagy szándékosan meghamisítja azt? Na, ki? Bizony te.

    Aztán a sokadik "nem nem nem" után kiderül, hogy de, a prefetcher pont úgy működik, ahogy írtam

    Nem, annak a hülyeségnek, amit amit te írtál a (valójában nem létező) mintafelismerésről, meg annak, amit beidéztél az Intel kézikönyvből, és ami gyakorlatilag azt mondja, hogy amikor a processzor látja hogy közelítesz a lap valamelyik határa felé egy utasítássorral, akkor előre behúzza a következő (vagy előző) lapot, annak semmi köze nincs egymáshoz. Illetve maximum annyi, mint amennyi köze van az ősember kőbaltájának egy CNC géphez.

    Mert szokás szerint a ködösítés mellett konkrétumokat soha nem írsz semmire, akkor ugyanis objektíven kiderülne, hogy meztelen a király.

    Jaja. Mese habbal. Sőt, ez maga az a konkrétumok nélküli ködösítés amiről mesélsz és amivel engem vádolsz. Leírod, hogy állítólag mi volt, és közben egyetlen egy linket, idézetet nem tudsz hozni az alátámasztására. Ezére a ködösítéses vádéra sem, de a fenti gyorstárazósra sem. Mert hogy ugye semmi olyan nem volt, amit állítasz. Csak rosszabb esetben kamuzol, mert vergődésed közepette másra már nem vagy képes, vagy jobb esetben egyszerűen csak rosszul emlékszel, illetve már eleve meg sem értetted a leírt szavak, mondatok jelentését. Nem tudom melyik a rosszabb.

    De, kifejezetten annak. Mivel semmi más nem fut a gépen

    És íme, az újabb bizonyítéka annak, hogy halvány lila segédfogalmaid sincsenek arról, hogy egy gép, egy operációs rendszer, egy processzor a felszín alatt hogyan is működik, és mennyi minden fut azon akkor is, amikor te azt hiszed, hogy semmi sem fut rajta. Vagy hogy azt se tudod, hogy az idő mekkora részében fut az a kód, amire valamilyen módon mondhatjuk, hogy a tiéd, mert legalábbis a te általad írt utasítások alapján lett képezve, és mennyi olyan kód fut (rengeteg), amihez semmi közöd nincs.

    Amiről te komolysággal ki tudsz jelenteni bármit, hogy jó-e, vagy sem. 

    Nem, hogy én, hanem bárki aki egy kicsit is érti, hogy miről beszél. Amely emberhalmaznak ugye te nem képezed részét.

    Az, hogy ahhoz, hogy a szekvenciális olvasás arányát egy alkalmazásban (nem egy adott algoritmusban) egyáltalán megközelítsd, az nagyon nem triviális, már csak egy másik dolog.

    Annyira "nem triviális", hogy önmagában egymás után írt "NOP" műveletek 'végtelen' sorozatával simán el lehet érni - hogy tényleg csak a lehető leglegegyszerűbb példát mondjam rá. Na, ennyire nem jelent semmiféle kiválóságot az algoritmusról önmagában az, hogy a hit arány eléri a szekvenciális olvasásét, és ennyire nem értesz semmit abból, hogy ezeket a számokat hogyan lehet elérni és hogyan kell értelmezni.

    Ok, akkor jöhet a te értelmezésed konkrétumokkal. Mitől nő meg az L2 cache hit és csökken az LLC miss a megfigyelt mértékben az említett szituációban?

    Ha kicsit is értenél bármit is abból, amit ennek kapcsán az elmúlt vagy fél tucat hozzászólásban leírtam, akkor nem kérdeznéd ezt, mert megértenéd, hogy a probléma itt pont az, hogy ezt nem lehet egyértelműen megmondani. Mert hogy egy sokváltozós egyenletben, pl. egy A+B+C+D=E műveletben pusztán az E változásából akarod kiszűrni azt, hogy A, B, C vagy D változása miatt változott -e E, amikor ez nyilván pusztán E ismerete alapján lehetetlen. Sőt, akkor is az lenne, ha még másik kettő változót is ismernél. Ehhez képest meg a valóság az adott helyzetben, hogy te még azt se tudod, hogy a "egyenleted" hány változóból rakódik össze.

    Ehhez képest az, hogy még a saját hit ratio ábrádat sem tudod értelmezni, és azt sem érted, hogy abban nem "nő meg az L2 cache hit és csökken az LLC miss", mert hogy annak százalékos skálája nem a hit és a miss arányokat ábrázolja az egyes gyorstárak vonatkozásában, hanem azt mutatja meg, hogy az összes hozzáférések hány százalékában melyik tárig (milyen "messzire") kellett elmenni az adatért, már igazán semmiség.
    Mutasd a teljes hozzászólást!
  • Megint sokadszorra nem olvasod el normálisan, hogy mit írnak neked. Azt sem sikerült felismerned, hogy a "nem, nem és nem"-ednek konkrétan ellent mondott a link.

    És megint nem sikerül értelmezni, hogy nem vitatta senki, hogy diskről is kellhet olvasni. Csak kb 10x írtam ezt le. Először még előtted. Az már egy másik kérdés, hogy ez hogyan és mikor jelenik meg az alkalmazásban, és milyen késleltetést okoz. Ha egyáltalán történik ilyen. Amiről neked csak feltételezéseid vannak, én meg mint mondtam, ezt is mérem. De kijelentesz dolgokat.

    Hát, igen, én nem egy gyors Google keresésből tudtam meg azt, amit te igen.

    Amit mi sem bizonyít jobban, minthogy először leírod, hogy az L2 hit arányt nem lehet mérni, majd miután kiderül, hogy de lehet, leírod, hogy nem lehet a kerneltől külön mérni. Pedig hát azt is lehet, ha akarod. És benne is volt a hozzászólásomban, hogy hogyan. Csak ahhoz értelmezni kellett volna, amit írtam. Aztán a sokadik "nem nem nem" után kiderül, hogy de, a prefetcher pont úgy működik, ahogy írtam, szemben az általad egyébként meg nem nevezett "nem nem nem" működéssel. Mert szokás szerint a ködösítés mellett konkrétumokat soha nem írsz semmire, akkor ugyanis objektíven kiderülne, hogy meztelen a király. De bár te nem gyors guglizás alapján vitatkozol, de a gugli kb első válaszát linkelted a részletes és hiteles forrás helyett, amit én linkeltem. A konkrét mérési eredmény mellett. Ennyit az állításaid hitelességéről.

    Egyrészt ez nem kifejezetten a te alkalmazásod műveleti kódjának hit/miss aránya.

    De, kifejezetten annak. Mivel semmi más nem fut a gépen (főleg nem jelenik meg mérhetően). És amit az adott program a kernelből, bármiből alatta használ, az valójában az alkalmazás elválaszthatatlan része, ezért nem is lenne értelme máshogy mérni. A teljes képhez ezt bele kell venni a mérésbe.

    Másrészt 99.5% alatti hit/miss arány (ami látható a grafikonodon) az szörnyen rossz egy 64-bites szóhosszú és 4K-s lapméretű architektúrán, amin már egy sima lineáris olvasás is csak minden 512. alkalommal, tehát 0.195%-ban vezet miss-hez, ami 99.805%-os hit aránynak felel meg. 

    Amiről te komolysággal ki tudsz jelenteni bármit, hogy jó-e, vagy sem. Az alkalmazásról semmit nem ismerve. Ez ám a szakmai komolyság :) Az, hogy ahhoz, hogy a szekvenciális olvasás arányát egy alkalmazásban (nem egy adott algoritmusban) egyáltalán megközelítsd, az nagyon nem triviális, már csak egy másik dolog. Amellett, hogy arról semmit nem állítottam, hogy ez jó, vagy rossz arány-e szerintem :) Az első kép (amire hivatkozol) az egy benchmark a második képhez, amihez képest a második jelentős javulás mutat. Szemben a te korábbi eszmefuttatásoddal. Mert az alapján romlást kellett volna tapasztalni.

    Ez aztán meg végképp' totális hülyeség, de annyira, hogy most legszívesebben az arcomat kaparnám kínomban, hogy hogyan voltál képes ezt mondatot összeszenvedni és leírni úgy, hogy komolyan gondoltad, hogy bármi amit leírtál benne az azt bizonyítja amit állítasz, és pláne hogy cáfolja azt, amit én írtam. Komolyan mondom, ez olyan, mint amikor naponta nézi az ember, hogy a tiszticili nem tud nagyobb hülyeséget mondani, mint előző nap.... és mégis mindig sikerül neki, újra és újra.

    Ok, akkor jöhet a te értelmezésed konkrétumokkal. Mitől nő meg az L2 cache hit és csökken az LLC miss a megfigyelt mértékben az említett szituációban? A cache hit/miss ratio-nál lényegesen több CPU-n belüli metrikám van az említett futasról. Úgyhogy igen jó eséllyel meg fogom tudni mondani, hogy az van-e, amit te mondasz, vagy az, amit én. Mivel neked ez nem gugliból megy, nyilván tudod a választ, és még azt is tudod, hogy hogyan ellenőrizzem vissza. Szóval? :)
    Mutasd a teljes hozzászólást!
  • Ha fut azon a gépen a "műveleti kódon" kívül bármi, mondjuk egy kernel, akkor nem is lehet máshogy mérni

    Éppen ezért volt balgaság BlaZember részéről bedobni az állítólagos tesztjei által mutatott hit ratio, aminek ebben a formában, ahogy ő előadta kb. annyi relevanciája volt azzal, amire bedobta, mint a moszkvicsosztogatásnak a mercédeszosztogatáshoz.
    Mutasd a teljes hozzászólást!
  • Ezt szerinted bármi mellett vagy ellen is érv? Ha nem, akkor minek írod egyáltalán le? 

    Le lehet írni azt is, ami nem érv, jelen esetben például ismeretterjesztési szándékkal. 

    Ehhez képest azt, hogy a "követeli" és a "követelheti" 


    Nem minden deklaráció követeli meg a resolutiont, ezért írtam "követelheti" szót. De ha létezik egy olyan eset, amelyben "egy helyi változó, egy mező vagy egy paraméter deklarációja" az osztály betöltését vonja maga után, akkor az cáfolja, hogy "nem is követeli meg az osztály betöltését".

    nem érted mit jelent az a szó, hogy "deklaráció [..] önmagában"

    Oké, akkor nézhetünk egy olyan osztályt is, amiben kizárólag egy metódusdeklaráció van, melynek a paraméterének típusa okozza egy osztály betöltését: 

    abstract class A { public abstract boolean equals(B b); }
    Ugyanúgy NoClassDefFoundError, amikor töltené be az A osztályt.
    Mutasd a teljes hozzászólást!
  • Egyrészt ez nem kifejezetten a te alkalmazásod műveleti kódjának hit/miss aránya.

    Ha fut azon a gépen a "műveleti kódon" kívül bármi, mondjuk egy kernel, akkor nem is lehet máshogy mérni, egy interrupt miatti context switch is sokat ronthat a cache misseken. 

    Ez aztán meg végképp' totális hülyeség, de annyira, hogy most legszívesebben az arcomat kaparnám kínomban, hogy hogyan voltál képes ezt mondatot összeszenvedni és leírni úgy, hogy komolyan gondoltad, hogy bármi amit leírtál benne az azt bizonyítja amit állítasz, és pláne hogy cáfolja azt, amit én írtam. Komolyan mondom, ez olyan, mint amikor naponta nézi az ember, hogy a tiszticili nem tud nagyobb hülyeséget mondani, mint előző nap.... és mégis mindig sikerül neki, újra és újra.

    Mármint miért lenne hülyeség, amit ír?
    Mutasd a teljes hozzászólást!
  • Amit látsz rajtuk, az a memory load műveletek százalékos eloszlása attól függően, hogy honnan vannak kiszolgálva.

    Egyrészt ez nem kifejezetten a te alkalmazásod műveleti kódjának hit/miss aránya. Másrészt 99.5% alatti hit/miss arány (ami látható a grafikonodon) az szörnyen rossz egy 64-bites szóhosszú és 4K-s lapméretű architektúrán, amin már egy sima lineáris olvasás is csak minden 512. alkalommal, tehát 0.195%-ban vezet miss-hez, ami 99.805%-os hit aránynak felel meg. Persze te nyilván ezt se tudtad, ezt se számoltad ki, aztán most, amikor miután leírtam pár alap dolgot erről, és utánanéztél, és láttad a 99.x% százalékos értéket, megörültél, mint majom a farkának, hogy húdeklafa hit/miss arányod van, miközben persze dehogy. Ehhez képest az, hogy nem is (csak) a saját hit/miss arányodat mérted, mert hogy azt így nem is lehet, már csak bónusz.

    Amit érdemes észrevenned, az a sárga oszlopok méretének növekedése, vagyis az L2 cache hit hatékonyságának százalékos növekedése az entryk méretének 128B-ról 4K-ra emelésével (ami nem mellesleg egyébként közel 50%-kal nagyobb memóriahasználattal párosult (más az elemszám). Tehát íme a bizonyíték, hogy nem igaz az állításod, miszerint a nagyobb adatmennyiség ront a hatékonyságon.

    Ez aztán meg végképp' totális hülyeség, de annyira, hogy most legszívesebben az arcomat kaparnám kínomban, hogy hogyan voltál képes ezt mondatot összeszenvedni és leírni úgy, hogy komolyan gondoltad, hogy bármi amit leírtál benne az azt bizonyítja amit állítasz, és pláne hogy cáfolja azt, amit én írtam. Komolyan mondom, ez olyan, mint amikor naponta nézi az ember, hogy a tiszticili nem tud nagyobb hülyeséget mondani, mint előző nap.... és mégis mindig sikerül neki, újra és újra.
    Mutasd a teljes hozzászólást!
  • Legközelebb, ha okítani akarsz JVM működés témában, akkor ne egy (17 éves) Java-s alkalmazás specifikus classloader-ének dokumentációját linkeld be, hanem a JVM specifikációt: Chapter 5. Loading, Linking, and Initializing 

    Lásd amit előbb írtam! A JVM specifikáció pontosan ugyanazt írja.

    Konkrétan 0db említés van benne a diskre, és a file-ra is csak a class file formatnál, illetve egy példában.

    Tehát az is beszél róla. Nem mintha az általam beidézett részben szó lett volna "disk"-ről, vagy bárhol is a "disk" szó említésére épített volna a hozzászólásom. Ez egyszerűen csak értelemszerűen adódik abból, amikről egy osztályfájl betöltéséről beszélünk, hogy az végső soron valami háttértárról jön. Ezt csak nem érti, aki informatikából teljesen bugyi, és az kezd el vitatkozni rajta, aki betegesen nem akarja elismerni, hogy a másiknak már megint igaza volt.

    Akkor tisztelettel kérnélek, hogy a fenti linket olvasd. 

    Megkérsz, hogy a fenti linket olvassam el, miközben te magad nyilvánvalóan nem olvastad el. Lásd a korábban írtak!

    Hagyd már a disk cache-t me mindent, de tényleg. Mi van, ha generálom az osztályaimat on-the-fly? Vagy ha hálóról töltöm be? Vagy ha egy in-memory storage-ból veszem? Akkor hol van a disk művelet?

    Egyrészt ha erre még a kérdésre sem tudod a választ, akkor nem vagy kvalifikált nem, hogy ennek a vitának, de ennél sokkal alapvetőbb viták lefolytatására sem. Másrészt az, hogy milyen csatornán át töltöd be az osztályfájlt, illetve az azt tartalmazó jar állományt, semmit nem változtat sem azon, hogy az ezen folyamat során érintett gyorstárakra milyen hatással van, sem azon, hogy ezek és az osztályfájlt tartalmazó adathalmaz mérete önmagában is befolyással van a program "futási teljesítmény"-ére.

    Valóban létezik. Leírod, hogy Class.forName() és az adott osztály betöltődik. Nem nagy trükk. De ez egy alkalmazás feature, és nem JVM feature. És ez maga az a hivatkozás, amire fent hivatkoztam. 

    Nem, ez nem a hivatkozás, hanem ez már egy hívás, műveletvégzés. Lásd a korábbi példakód, amit hoat4-nek írtam! Ő egyébként nem a másodnikked? Csak azért kérdezem, mert hasonlóan látszotok abszolút nem érteni és tudni alapvető dolgokat és fogalmakat sem, nem csak a Java, a gyorstárak és a gép működésével kapcsolatban, de még azt sem, hogy mi egy deklaráció vagy mi egy hivatkozás, és mi nem.

    Minden kontextusban igazam van, lásd a hivatkozott Intel manual részletet. A cache hatékonysága mindig, minden körülmények között az algoritmusok és adatszerkezetek hatékonyságának a függvénye. Ez a software optimalizáció 101-ja.

    Nem. Ez egy nettó hülyeség. Elméletileg is, gyakorlatilag és a konkrét esetre vonatkoztatva meg pláne, mert míg a .java, .jar. stb. fájlok szerkezete fix és legkésőbb fordítási időben minden részletét tekintve rögzített, addig azok gépek, operációs rendszerek, stb. gyorstárai, pufferterületei, azok használatának költségei, késleltetései, stb. mind egymástól eltérőek és sokszor még a Java futtatókörnyezet számára sem megismerhetők.

    _Ez_ az optimalizáció 101-ja, és az, hogy ha nem ismered ezeket a paramétereket és azok nem rögzítettek, akkor nem tudsz optimalizálni rájuk. Nem mintha ennek megint bármi köze is lenne bármihez ami korábban felmerült - csak már rakjuk rendbe ezt is, ha már erről is sikerült valami orbitális hülyeséget leírnod.

    Sokat foglalkozhattál a témával...

    Hát, igen, én nem egy gyors Google keresésből tudtam meg azt, amit te igen.
    Mutasd a teljes hozzászólást!
  • Hát, ez egy 2003-ban készült Oracle alkalmazásszerver dokumentációja...

    És? Ezt szerinted bármi mellett vagy ellen is érv? Ha nem, akkor minek írod egyáltalán le? Ennyi erővel azt is megírhattad volna, hogy "hát, ezen fehér alapon feketével vannak írva a betűk", vagy "hát, ebben az oldalak meg vannak számozva". Ezek a megállapításoknak is kb. annyi érv-értéke és relevanciája lenne, mint az, hogy 2003-as a doksi.

    Hogy a JVM mit csinál, az a JVM specifikációban leírva: Chapter 5. Loading, Linking, and Initializing

    És ez gyakorlatilag pontosan ugyanazt írja le, mint amit az általam linkelt dokumentum is. Annyira, hogy még az általam külön kiemelt rész is benne van, csak egy némileg átfogalmazott, egyszerűsített formában:

    "If C is not an array class, it is created by loading a binary representation of C (§4 (The class File Format)) using a class loader. [..] For example, a class could be downloaded across a network, generated on the fly, or extracted from an encrypted file."

    Tehát még ez is kvázi a fizikai médiumról a Java osztályfájl betöltésével kezdi... mert hogy ez így működik, és ez ugyanúgy működik nem csak hogy 2003, de azóta, amióta a Java-t először kitalálták. És mert semmilyen más módon nem is működhet.

    "Főleg, hogy pl. egy helyi változó, egy mező vagy egy paraméter deklarációja is hivatkozhat egy osztályra, de az önmagában nem csak hogy szükségszerűen nem indítja el, de nem is követeli meg az osztály betöltését önmagában."
    Már hogyne követelhetné meg?
    [..]
    a = new B();

    Megállapítom, hogy nem érted mit jelent az a szó, hogy "deklaráció [..] önmagában". És így állsz le vitatkozni... Ehhez képest azt, hogy a "követeli" és a "követelheti" sem ugyanaz, te mégsem tudsz a jelek szerint különbséget tenni közöttük, már csak ráadás.

    Csak, hogy te is értsd, próbáld ki ezt helyette ugyanúgy a B.class törlésével, és láss csodát, illetve hibamentes futást! (És ebben nem csak, hogy deklaráció, de még műveletvégzés is van, legalábbis formálisan, a kérdéses helyi változón)

    class A { public static void main(String[] args) { B b = null; if (b == null) System.out.println("Itt biza nincs hiba"); } }
    Mutasd a teljes hozzászólást!
  • Külön hozzászólás, mert a megjelenítő az előzőnek lenyeli a végét.

    Íme 2 screenshot:
    128B: 128B - Image on Pasteboard
    4K: 4K - Image on Pasteboard

    Amit látsz rajtuk, az a memory load műveletek százalékos eloszlása attól függően, hogy honnan vannak kiszolgálva. Egy sokszálú, particionált, igen nagy méretű hash tábláról van szó, amit végigiterál az adott benchmark. A különbség a tárolt értékek mérete: 128B vs 4K, és az elemszám. Minden más (a kód) csontra ugyanaz. Ezt találtam most hirtelen elmentve, ez csak 10GB feletti adatmennyiség. De teljesen mindegy, mert messze, több nagyságrenddel nagyobb, mint az összes cache mérete együttvéve. Amit érdemes észrevenned, az a sárga oszlopok méretének növekedése, vagyis az L2 cache hit hatékonyságának százalékos növekedése az entryk méretének 128B-ról 4K-ra emelésével (ami nem mellesleg egyébként közel 50%-kal nagyobb memóriahasználattal párosult (más az elemszám). Tehát íme a bizonyíték, hogy nem igaz az állításod, miszerint a nagyobb adatmennyiség ront a hatékonyságon. Ebben a példában konkrétan javított a hatékonyságon, mert javította az access patternt. Mivel az adatok végigolvasása több szomszédos cache line-t érint, hirtelen az L2 cache ki tudja szolgálni a CPU-t... Már amellett, hogy igen túlnyomó részt az L1 szolgálja ki. És mindez a hardware prefetchernek az eredménye. Vagyis semmi köze a cache hatékonyságához a memóriából feldolgozott adat mennyiségének. Annak van köze, hogy milyen mintával olvasod a memóriát.
    Mutasd a teljes hozzászólást!
  • Legközelebb, ha okítani akarsz JVM működés témában, akkor ne egy (17 éves) Java-s alkalmazás specifikus classloader-ének dokumentációját linkeld be, hanem a JVM specifikációt: Chapter 5. Loading, Linking, and Initializing Konkrétan 0db említés van benne a diskre, és a file-ra is csak a class file formatnál, illetve egy példában. És továbbra is, egy percig nem mondtam, hogy (adott esetben) nem kell egy class-t diskről betölteni... A legközelebbi állításom az volt, hogy nem kell minden classt feldolgozni (még a bináris reprezentációját végigolvasni se) ahhoz, hogy a használt osztályokat betöltse a JVM.

    "Beleértve azt is, hogy az osztályok betöltése dinamikusan történik, és hogy a class definíció beolvasása akkor történik, amikor egy másik osztály az új, létrehozandó osztályt hivatkozza."
    Nem, és ez a mondat úgy nem igaz, ahogy van, és annyira, amennyire csak lehet.

    Akkor tisztelettel kérnélek, hogy a fenti linket olvasd. Ezeket a részeit főleg. Kiemelések tőlem.

    The Java Virtual Machine dynamically loads, links and initializes classes and interfaces. Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation.

    [...]

    Class or interface creation is triggered by another class or interface D, which references C through its run-time constant pool. Class or interface creation may also be triggered by D invoking methods in certain Java SE Platform class libraries (§2.12) such as reflection.

    Hagyd már a disk cache-t me mindent, de tényleg. Mi van, ha generálom az osztályaimat on-the-fly? Vagy ha hálóról töltöm be? Vagy ha egy in-memory storage-ból veszem? Akkor hol van a disk művelet?

    Egyébként pedig már nagyon régóta létezik számos Java alapú alkalmazásszerverben a kényszerített előtöltés lehetősége is, aminek pont az a lényege, hogy az első használat, "hivatkozás" előtt betöltet bizonyos osztályokat (meg persze azok függőségeit), azért, hogy annak kódja már azonnal készen álljon akkor, amikor ténylegesen szükség van rájuk.

    Valóban létezik. Leírod, hogy Class.forName() és az adott osztály betöltődik. Nem nagy trükk. De ez egy alkalmazás feature, és nem JVM feature. És ez maga az a hivatkozás, amire fent hivatkoztam. Hogy hivatkozod az osztályt, de egy darabig még utána nem használod (ez az AS előtöltés), teljesen irreleváns a class loading szempontjából. 

    Mindenki más meg igen, és érti, hogy a "disk alrendszer szokásai" (mint ahogy minden köztes "alrendszer szokásai" is) alapvető hatással vannak az egész folyamat sebességére, és hogy ennél fogva nagyon nem mindegy, hogy a lemezen hogyan és milyen szerkezetben elszórva helyezkednek el azok az állományok, amikben az osztályok Java kódja van.

    Leírjam huszonhatodszor is, hogy azt egy percig nem vitattam, hogy a disk szerepet játszhat ebben? Vagy ugorhatunk? Állításom lásd fent. 

    "A memory load műveleteket figyeli, és abban végez mintafelismerést."
    Nem, nem azt csinálja.

    De azt csinálja. Úgy hívják, hogy streamer prefetcher:

    Streamer: This prefetcher monitors read requests from the L1 cache for ascending and descending sequences of addresses. Monitored read requests include L1 DCache requests initiated by load and store operations and by the hardware prefetchers, and L1 ICache requests for code fetch. When a forward or backward stream of requests is detected, the anticipated cache lines are prefetched. Prefetched cache lines must be in the same 4K page.
    https://www.intel.com/content/dam/www/public/us/en/documents/manuals..
    60. oldal.

    És akkor most olvasd újra az eredeti hozzászólásom. 

    Ha utóbbi alatt a Java kódot tartalmazó fájl adatszerkezeteit és az azt generáló fordító algoritmusait érted, akkor igazad van. Ha nem, akkor ebben a kontextusban nincs.

    Minden kontextusban igazam van, lásd a hivatkozott Intel manual részletet. A cache hatékonysága mindig, minden körülmények között az algoritmusok és adatszerkezetek hatékonyságának a függvénye. Ez a software optimalizáció 101-ja. 

    Hát, nem. Nagyon, nagyon, de nagyon nem. És bármi, amit egy benchmarkolt programon át mérsz, abba beleszámít és abban benne van a gép minden komponense és tulajdonsága, ahogy a program szervezésének és kódjának minden sajátossága is. Amikből nem tudod mágikusan kiszűrni az L2 hit/miss arányát. Ahhoz azt külön kellene mérni, figyelni.

    [...]

    Azt kimutatni nem lehet, csak mérni, számolni. Ehhez képest az, hogy te azt állítottad, hogy már ezt megtetted, most meg azt mondod, hogy majd megteszed, csak ráadás.

    Sokat foglalkozhattál a témával...

    --------------------------------------------------------------------------------

    | MEM_LOAD_RETIRED | | Memory loads retired (Precise Event) | | :DTLB_MISS | | Retired loads that miss the DTLB (Precise Event) | | :HIT_LFB | | Retired loads that miss L1D and hit an previously allocated LFB (P| | recise Event) | | :L1D_HIT | | Retired loads that hit the L1 data cache (Precise Event) | | :L2_HIT | | Retired loads that hit the L2 cache (Precise Event) | | :L3_MISS | | Retired loads that miss the LLC cache (Precise Event) | | :LLC_MISS | | This is an alias for L3_MISS | | :L3_UNSHARED_HIT | | Retired loads that hit valid versions in the LLC cache (Precise Ev| | ent) | | :LLC_UNSHARED_HIT | | This is an alias for L3_UNSHARED_HIT | | :OTHER_CORE_L2_HIT_HITM | | Retired loads that hit sibling core's L2 in modified or unmodified| | states (Precise Event) | | :e=0 | | edge level (may require counter-mask >= 1) | | :i=0 | | invert | | :c=0 | | counter-mask in range [0-255] | | :t=0 | | measure any thread | | :u=0 | | monitor at user level | | :k=0 | | monitor at kernel level | | :period=0 | | sampling period | | :freq=0 | | sampling frequency (Hz) | | :precise=0 | | precise ip | | :excl=0 | | exclusive access | | :mg=0 | | monitor guest execution | | :mh=0 | | monitor host execution | | :cpu=0 | | CPU to program | | :pinned=0 | | pin event to counters | -
    Mutasd a teljes hozzászólást!
  • a vonatkozó Java dokumentációt

    Hát, ez egy 2003-ban készült Oracle alkalmazásszerver dokumentációja... Hogy a JVM mit csinál, az a JVM specifikációban leírva: Chapter 5. Loading, Linking, and Initializing

    Főleg, hogy pl. egy helyi változó, egy mező vagy egy paraméter deklarációja is hivatkozhat egy osztályra, de az önmagában nem csak hogy szükségszerűen nem indítja el, de nem is követeli meg az osztály betöltését önmagában.

    Már hogyne követelhetné meg?

    class A { private static int x = 0; public static void main(String[] args) { java.util.ArrayList a = null; if(x == 0) a = new java.util.ArrayList(); else a = new B(); } } class B extends java.util.ArrayList {}
    Ha ezt lefuttatjuk úgy, hogy a B osztály class file-ját kitöröljük:

    C:\Users\...\Documents\eagerloadtest>javac A.java & del B.class C:\Users\...\Documents\eagerloadtest>java A Error: Unable to initialize main class A Caused by: java.lang.NoClassDefFoundError: B
    Stack trace sincs, tehát láthatjuk, hogy még az A osztály verify-olásakor töltené be a B osztályt, a kódnak egyetlen sora sem futott le.
    Ez nem a referenciaimplementáció sajátossága, a JVM specifikációból is le lehet vezetni: a 4.10.1.4.-es szakaszban ("Stack Map Frames and Type Transitions") a "frameIsAssignable" predicate definíciója hivatkozik "isAssignable"-re, ami meg értelemszerűen igényli a másik classfile betöltését is.
    Mutasd a teljes hozzászólást!
  • Nem kell nekem nevet adni valaminek ("betöltés") ahhoz, hogy azt úgy hívják, ahogy. A JVM specifikáció hívja ezt annak,

    Nem, a JVM nem azt hívja betöltésnek, amit te hívsz annak, hanem az egész nagy folyamatot, aminek az amit te akarsz a betöltésnek titulálni, csak egy igen kis része, sőt, a végeredménye. És ami - annak ellenére, hogy ezt te tagadod - bizony azzal kezdődik, hogy "beolvasok X byte-ot", a Java bájtkódot tároló háttértárról vagy más, hasonló forrásból. Hogy magát a vonatkozó Java dokumentációt idézzem:

    "Let’s start with the basics. The term “class loading” refers to the process of locating
    the bytes for a given class name and converting them into a Java Class instance.
    [..]
    In a Java application, there are a number of different classloaders that use any
    number of different mechanisms to load classes. In addition to the CLASSPATH
    example above, classloaders can be designed such that classes are retrieved:
    • From a database. In this case configuration could consist of all the data
    needed to point at the correct table(s) in a specific database
    • From a remote server running a proprietary communications protocol.
    Configuration could consist of DNS names, ports, and other network
    information
    • From the file system, but with a special search order specified in a
    properties file
    • From sources defined within an XML file
    • From source code (*.java) files that must be compiled"

    Látod? Ma is tanultál valami (neked) tök újat.

    Beleértve azt is, hogy az osztályok betöltése dinamikusan történik, és hogy a class definíció beolvasása akkor történik, amikor egy másik osztály az új, létrehozandó osztályt hivatkozza.

    Nem, és ez a mondat úgy nem igaz, ahogy van, és annyira, amennyire csak lehet.

    Egyrészt kezdődik ott, hogy a betöltés nem "akkor" történik amikor "egy másik osztály az új, létrehozandó osztályt hivatkozza", hanem legfeljebb "akkor", amikor "egy másik osztály az új, létrehozandó osztályt először hivatkozza". Persze ez sem igaz, mert a másik osztály már megírásának pillanatától kezdve azon át, hogy ott fekszik tehetetlenül a lemezen folyamatosan "hivatkozza" az adott osztályt. A "hivatkozás" nem egy pillanatnyi elemi művelet, hanem egy folyamatos valami. Ami pillanatnyi, az legfeljebb pl. a végrehajtás elérkezése a hivatkozási ponthoz. Főleg, hogy pl. egy helyi változó, egy mező vagy egy paraméter deklarációja is hivatkozhat egy osztályra, de az önmagában nem csak hogy szükségszerűen nem indítja el, de nem is követeli meg az osztály betöltését önmagában.

    Másrészt - ahogy el lett már mondva - az kizárólag a mindekori Java futtatókörnyezet (alacsonyabb szinteken pedig az operációs rendszer, a merevlemez, illetve ezek gyorsítótárainak) előjoga, hogy eldöntse: mikor tölti be, majd értelmezi valamilyen módon és végez esetleg transzformációkat is egy Java osztály reprezentációján, beleértve akár a majdan végrehajtható tárgykód legenerálását. Ha ezt részben vagy teljesen előbb csinálja meg, az magára a Java alkalmazás működésére szemantikailag semmilyen hatással sincs, hiszen ebből az nem lát semmit. Ahogy abból sem, ha ez tényleg csak akkor történik meg, amikor először hivatkozza egy másik osztály.

    Pont ez az, ami miatt egyáltalán a Leyden létezhet, működhet, méghozzá teljesen transzparens módon is majd, minden olyan alkalmazásnál ami nem igényel ad hoc betöltést. Ezért lehet majd benne az osztálybetöltéssel összefüggésbe hozható értelmezési-feldolgozási műveletek egy részét fordítási időbe előre hozni anélkül, hogy ehhez magán a Java alkalmazáson forrás- és szemantikai szinten bármit is változtatni kellene. Mert hogy ti. ez, illetve ennek időbeni eloszlása egy, a működés szemantikája szempontjából teljesen lényegtelen és meghatározatlan részletkérdés.

    Egyébként pedig már nagyon régóta létezik számos Java alapú alkalmazásszerverben a kényszerített előtöltés lehetősége is, aminek pont az a lényege, hogy az első használat, "hivatkozás" előtt betöltet bizonyos osztályokat (meg persze azok függőségeit), azért, hogy annak kódja már azonnal készen álljon akkor, amikor ténylegesen szükség van rájuk.

    Amikor class loadingról beszélünk, ezért nem egyértelműen vesszük bele a disk alrendszer szokásait.

    Te nem. Mindenki más meg igen, és érti, hogy a "disk alrendszer szokásai" (mint ahogy minden köztes "alrendszer szokásai" is) alapvető hatással vannak az egész folyamat sebességére, és hogy ennél fogva nagyon nem mindegy, hogy a lemezen hogyan és milyen szerkezetben elszórva helyezkednek el azok az állományok, amikben az osztályok Java kódja van.

    Hozzáférési minta: Nem én hívom így. A memory access pattern egy a szakmában elég elfogadott elnevezés arra, hogy a program által használt adatok egymáshoz képest milyen (virtuális) címeken találhatóak. 

    Egyrészt amit mondani szerettél volna gondolom, az nem az volt, hogy te nem így hívod, hanem az, hogy nem csak te hívod így. Ami szép, csak nem tudom minek írod le, amikor senki nem mondta, hogy csak te hívod így. Mert, hogy a mondás ehelyett az volt, hogy "amit te itt mintának hívsz, az az adatmennyiség függvénye". Ezt pedig magad igazoltad most a fenti kijelentéssel - hiszen az, hogy "a program által használt adatok egymáshoz képest milyen (virtuális) címeken találhatóak" az nyilvánvalóan függvénye annak, hogy mekkora területen helyezkednek el és vannak szétszórva. QED.

    "De, te mondtad. Azt mondtad, hogy [...]"
    A memory load műveleteket figyeli, és abban végez mintafelismerést.

    Nem, nem azt csinálja. De ha azt csinálná se változtatni semmit azon, hogy te azt mondtad, hogy nem mondtál valamit, amit de, mondtál. Ezen semmi, amit most utólag leírsz, nem fog változtatni, akkor sem, ha az utólag leírt kijelentéseid esetleg helyesek lennének.

    "Ha a memória nem gyorstár is egyben, akkor semmi keresnivalója a gyorstárokról szóló okfejtésekben."
    Mit gondolsz akkor a diskről, amit te rángatsz elő mindig?

    Én nem "a disk"-et "rángatom elő mindig", hanem "a disk gyorstárát", és hogy "a disk" gyorstára milyen hatással van erre vagy arra. Tudom, te nem nagyon érted a különbséget ezek a dolgok (ti. "a disk" meg "a disk gyorstára") között, de ettől ezek még nem ekvivalens fogalmak.

    Amúgy a memória is lehet gyorstár is. 

    Rájöttél? Fantasztikus. Akkor már csak azt kell megértened, hogy az a mondat mit jelent, hogy "Ha a memória nem gyorstár is egyben, akkor semmi keresnivalója a gyorstárokról szóló okfejtésekben". Különösen az első fele, a feltétele.

    A memória egy absztrakt fogalom, ami fizikailag rétegzett, és aminek egyébként de, része a cache is.

    A Zacher-torta pedig egy sütemény, ami fizikailag rétegezett , és aminek egyébként de, része a csokibevonat is. Na, látod ennek a kijelentésnek is kb. akkora relevanciája van azt illetően, amiről szó van, mint annak, amit leírsz. Semmi. Egy önmagában igaz, de teljesen irreleváns kijelentés, amiről csak találgatni lehet, hogy azért írod le, mert neked újdonság.

    "Az, hogy "kiüt" valami valami mást a cache-ből, a te kitalációd, rajtad kívül senki nem írt ilyent."
    De, amikor azt írod, hogy a példámban nem 100% a hit, akkor pont ezt mondod.

    Nem, amikor valaki azt mondja, hogy "A" halmazban nem található meg egy másik, "B" halmaz minden eleme, az nem mond semmit arról, hogy "A" halmazban pontosan milyen elemek találhatók meg. Akkor sem, ha a halmaz esetleg időben változik és mi időben is vizsgáljuk ezt.

    "Arról beszélek, hogy amit te mintának hívsz, az az adatmennyiség függvénye."
    De nem annak a függvénye, hanem a használt algoritmusoknak, és adatszerkezeteknek.

    Ha utóbbi alatt a Java kódot tartalmazó fájl adatszerkezeteit és az azt generáló fordító algoritmusait érted, akkor igazad van. Ha nem, akkor ebben a kontextusban nincs.

    "Igen, kérlek küldj screenshotot arról, hogy megmérted mondjuk a processzorod L2 gyorstárának hit/miss arányát [..]"
    Oké, ha gép elé kerülök kicsit később, küldöm. Elöljáróban annyit, hogy az adott gép egy benchmarkolásra használt gép, amin az oprendszeren kívül semmi más nem fut, csak a benchmarkolt program, így gyakorlatilag szinte teljesen csak az adott feldolgozást méri.

    Hát, nem. Nagyon, nagyon, de nagyon nem. És bármi, amit egy benchmarkolt programon át mérsz, abba beleszámít és abban benne van a gép minden komponense és tulajdonsága, ahogy a program szervezésének és kódjának minden sajátossága is. Amikből nem tudod mágikusan kiszűrni az L2 hit/miss arányát. Ahhoz azt külön kellene mérni, figyelni.

    Azt fogod látni, hogy a memory loadok elhanyagolható része lesz LLC miss. Kimutatom belőle csak az L2 arányt is specifikusan, ahogy kérted.

    Azt kimutatni nem lehet, csak mérni, számolni. Ehhez képest az, hogy te azt állítottad, hogy már ezt megtetted, most meg azt mondod, hogy majd megteszed, csak ráadás.
    Mutasd a teljes hozzászólást!
  • Nem kell nekem nevet adni valaminek ("betöltés") ahhoz, hogy azt úgy hívják, ahogy. A JVM specifikáció hívja ezt annak, és specifikálja az általad leíráshoz képest máshogy ezt a folyamatot. És legszűkebben véve is erről szól a cikked valójában, ugyanis a Leyden ennek tervezi fordítási időbe bevinni bizonyos időigényes részeit, illetve kidobni a nem használt osztályokat. És igen, ezek betöltődhetnek diskről is (ahogy leírtam kb a második hozzászólásomban is). Ezen kár tovább pörögnöd. És betöltődhet a memóriából is. Pl mert soha nem is volt disken az adott class bináris, vagy akár az egész jar, vagy eleve (OS) cache-ben van a memóriában. Amikor class loadingról beszélünk, ezért nem egyértelműen vesszük bele a disk alrendszer szokásait. És a cikk kontextusában ez nem is nagyon lényeges. 

    Hozzáférési minta: Nem én hívom így. A memory access pattern egy a szakmában elég elfogadott elnevezés arra, hogy a program által használt adatok egymáshoz képest milyen (virtuális) címeken találhatóak. Ez az, ami alapvetően fogja meghatározni a cache/miss arányt, és nem az, hogy mekkora az adat. Ha van 1TB adatod a memóriában, azt szekvenciálisan vs random feldolgozod, nagyon más arányokat fogsz látni. Pedig ugyanaz az adatmennyiség.

    De, te mondtad. Azt mondtad, hogy "a CPU ugye figyeli is ezeket a hozzáférési mintákat, és ha felismert mintát talál, prefetcheli neked a prefetch algoritmus által definiált cache rétegbe". Mivel ugye hozzáférési műveletet csak a végrehajtásra kerülő kód végezhet, ezért de, te pontosan azt mondtad, hogy a CPU a végrehajtott kódot figyeli (ti. hogy mihez fér hozzá), és abban talált minták alapján tölt elő meg gyorstáraz. Ami persze nem igaz... de ettől még ezt mondtad.

    A memory load műveleteket figyeli, és abban végez mintafelismerést. Igen, ami függvénye a CPU által végrehajtott utasításoknak. És de, a hardware prefetcher pont az alapján dolgozik. Te magad linkelted be :)

    Ha a memória nem gyorstár is egyben, akkor semmi keresnivalója a gyorstárokról szóló okfejtésekben. 

    Mit gondolsz akkor a diskről, amit te rángatsz elő mindig? Amúgy a memória is lehet gyorstár is. Hardware szinten is. Az egész DRAM kapacitás L4 cache-ként működik egy Optane DCPMM előtt (memory mode-ban). A memória egy absztrakt fogalom, ami fizikailag rétegzett, és aminek egyébként de, része a cache is.

    Az, hogy "kiüt" valami valami mást a cache-ből, a te kitalációd, rajtad kívül senki nem írt ilyent.

    De, amikor azt írod, hogy a példámban nem 100% a hit, akkor pont ezt mondod. Ha ugyanis mindig ugyanazt (és csak azt) a címet hivatkozza a kódod (erre válaszoltál), és mégis miss van, akkor azt valami kiütötte a cacheből.

    Arról beszélek, hogy amit te mintának hívsz, az az adatmennyiség függvénye.

    De nem annak a függvénye, hanem a használt algoritmusoknak, és adatszerkezeteknek.

    Igen, kérlek küldj screenshotot arról, hogy megmérted mondjuk a processzorod L2 gyorstárának hit/miss arányát, ráadásul kizárólag csak a te programod és a 1TB-os adatfeldolgozásod vonatkozásában! Köszönöm.

    Oké, ha gép elé kerülök kicsit később, küldöm. Elöljáróban annyit, hogy az adott gép egy benchmarkolásra használt gép, amin az oprendszeren kívül semmi más nem fut, csak a benchmarkolt program, így gyakorlatilag szinte teljesen csak az adott feldolgozást méri. Azt fogod látni, hogy a memory loadok elhanyagolható része lesz LLC miss. Kimutatom belőle csak az L2 arányt is specifikusan, ahogy kérted.
    Mutasd a teljes hozzászólást!
  • A megfogalmazásomban 

    Itt jól elbeszéltél amellett amit beidéztél tőlem elé. Tehát arra effektív semmit nem tudtál mondani. Sejtettem.

    Az operációs rendszer, a háttértár stb nem töltheti be és nem töltheti elő. 

    De, egyrészt megteheti, és meg is teszi ha jónak látja, mert az ő dolga, és senkinek semmi köze hozzá. Amin az, hogy te erről nem tudsz, semmit nem változtat. Másrészt - ahogy el lett idáig kb. 5x magyarázva - itt nem célzott előtöltésről van szó, amire te nyilvánvalóan gondolsz, hanem arról, amit nem értesz meg, hogy egyszerűen behúzásra kerül elkerülhetetlenül más, célzottan betöltött adatokkal, megint csak a tárak és a gyorstárak sajátosságainak (ti. hogy fix méretű blokkokkal dolgoznak, és azon belül nem tudnak és akarnak megkülönböztetni entitásokat) köszönhetően.

    Az osztály betöltése ugyanis nem azt jelenti, hogy beolvasok X byte-ot. 

    De, az is az osztály betöltése. Sőt, ez az osztály valódi betöltése. Az meg, amit te a betöltésnek hívsz, az valójában értelmezés, hivatkozásfeloldás és kódgenerálás. Amit egyébként ettől függetlenül lehet "betöltés"-nek hívni konszenzusos alapon, de amin semmit nem változtat azon, hogy az osztály kódját, szimbólumait, stb. tartalmazó adathalmaz pl. a memóriába töltése is betöltés, illetve előbbi is része annak az összetett és soklépéses betöltési folyamatnak, aminek kulcslépéseit és sajátosságait te teljesen figyelmen kívül akarnád hagyni. Ezért értelmetlen amit mondtál. És ezért mondtam el korábban, hogy értelmetlen amit mondtál.

    Főleg, hogy a betöltésnek - bármelyik fajta betöltésre is gondolsz - semmi köze ahhoz a fajta futási sebességhez, amin te próbálnál lovagolni (ti. a már elkészült és készen álló tárgykód végrehajtási idejéhez). Ha pedig azt mondod, hogy de van, azzal az eredeti belekötésed is bukod, mert az azt jelenti, hogy az indulási idő csökkentése már önmagában is növeli a futási sebességet is. Szóval ebből nem tudsz jól kijönni.

    Igen. Azt mondtam, hogy a cikk címével és tartalmával ellentétben ez a javaslat nem fogja a Java alkalmazások vonatkozásában azt jelenteni, hogy azok "gyorsabban futhatnak". Hiszen ez az indulást és a betöltést fogja csak érinteni.

    De, ezt fogja jelenti. Lásd fent! Ehhez képest az, hogy a korábban a gyorstárak kapcsán elmagyarázott dolgok miatt még abban a szűk értelemben is gyorsítani fog a futási sebességen, amire te próbálod mesterségesen leszűkíteni ezt a fogalmat, csak ráadás.

    "Hogyan teheti meg, hogy "hozzá se nyúl", amikor egy fájlban van a többi osztállyal?"
    Úgy, hogy nem kell végigolvasni egy egész zip file-t ahhoz, hogy tudd milyen file-ok vannak benne...

    Zzzzz. Rossz válasz. Ettől ugyanis még nem fognak pontosan szektor-, lap-, stb. határra esni az osztályfájlok a jar fájlban. Így amikor beolvasásra kerül egy adott osztály, akkor szinte biztosan beolvasásra kerül vele együtt legalább egy része egy olyan osztálynak is, ami akkor és ott még nem kerül feldolgozásra - és lehet, hogy soha később sem. És ez végig igaz az egész gyorstárazási láncra is. Ezért (is) mondom, hogy teljesen értelmetlen a "betöltés"-en pörögnöd, mert persze, hogy betöltésre kerülnek részben a nem használt osztályok, és - ahogy írtam - legfeljebb csak a teljes (!) értelmezésük és a mögéjük történő kódgenerálás az, ami nem történik meg. Ami viszont aztán már nagyon más, mint a "betöltés".

    "Mert hiába dolgozol fel ugyanannyi adatot, ha az nagyobb területen van szétszórva, akkor megint a gyorstárazás sajátosságai miatt (ti. mert az és az is ahonnan behívja az adatokat tipikusan lapokra, szegmensekre, szektorokra, és más fix méretű, de az elemei adathozzáférés egységéhez képest nagy méretű blokkokra van bontva) romlani fog a hit/miss arány, ezzel pedig az effektív adatelérési és végrehajtási sebesség is."
    És ugye pont ez a jelentése a hozzáférési mintának.

    Nem, nem ez a jelentése, hanem utóbbi függ előbbitől. Ezért értelmetlen amikor azt mondod, hogy az adathalmaz méretétől nem, hanem az elérési mintától függ meghatározóan a gyorstár találati aránya. Aki ilyeneket mond az nem érti, hogy ez a két dolog nem egymástól független, sőt, az adarelérés mintáját (abban az értelemben ahogy te használod most ezt a kifejezést) alapvetően határozza meg az adathalmaz mérete is.

    Próbáld már ki :) Mégis mi ütné ki az adatot a cache-ből,

    Próbáld te ki egyszer, hogy egyrészt megérted azt amit leírok, másrészt hogy nem egy magad által gyártott szalmabábut püfölsz, hanem azt próbálod vitatni amit mondtam. Ha utóbbit tennéd, akkor nem jönnél azzal a "kérdéssel", hogy mégis mi ütné ki az adatot a cache-ből, ráadásul közvetlenül az után, hogy leírtam, hogy " igen, a hot code-ot az adat nem fogja kiütni a cache-ből pl egy ciklus közepén". Az, hogy "kiüt" valami valami mást a cache-ből, a te kitalációd, rajtad kívül senki nem írt ilyent. Olyant viszont igen, hogy a dolog eleve nem ott kezdődik, hogy valami már bent van a gyorstárban és onnan "kiütheti" valami, hanem sokkal előrébb és ott, hogy egyáltalán bele kell, hogy kerüljön először a különböző gyorstárakba. Ami annál nehezebb dolog, minél nagyobb a teljes adatmennyiség, ami potenciálisan belekerülhet abba.

    "Tehát abszolút nem érted mi a különbség a "gyorstár" és a "memória" fogalma között, és hogy ezek semmilyen szempontból nem ekvivalens fogalmak"
    A memória azt jelentette, hogy a memóriában van az 1TB+ adat.

    A gyorstár meg azt jelenti, hogy gyorstár, nem azt, hogy memória. Ezek nem ekvivalens és csereszabatos fogalmak. Attól, hogy valami a memóriában van, nem jelenti azt, hogy gyorstárban van vagy gyorstározásra került.

    Továbbá: Ha a memória nem gyorstár is egyben, akkor semmi keresnivalója a gyorstárokról szóló okfejtésekben. Ha pedig gyorstár, akkor rá is vonatkozik minden, ami a gyorstárakra vonatkozik. Egyszerű, nem?

    "Egyrészt nem, a processzor nem a végrehajtott kódban látott alapján tölti elő a gyorstárat"
    Szerencsére olyat senki nem is mondott, hogy a végrehajtott kódban látottak alapján tölt elő

    De, te mondtad. Azt mondtad, hogy "a CPU ugye figyeli is ezeket a hozzáférési mintákat, és ha felismert mintát talál, prefetcheli neked a prefetch algoritmus által definiált cache rétegbe". Mivel ugye hozzáférési műveletet csak a végrehajtásra kerülő kód végezhet, ezért de, te pontosan azt mondtad, hogy a CPU a végrehajtott kódot figyeli (ti. hogy mihez fér hozzá), és abban talált minták alapján tölt elő meg gyorstáraz. Ami persze nem igaz... de ettől még ezt mondtad.

    "Másrészt ez nem változtat azon semmit, hogy ha összességében nagyobb területen vannak elszórva az adatok és a kódok [..]"
    Megint mintáról beszélsz, nem adatmennyiségről...

    De, adatmennyiségről beszélek, és arról, hogy az milyen alapvető hatással van arra, amit te mintának próbálsz titulálni... de ami adott esetben végső soron nem más, mint a nagyobb adatmennyiség egy függvénye, eredménye.

    Ja, egy preemptív, nem realtime scheduler csodákra képes. De ennek mi köze ahhoz, amire válaszoltál?

    Miért kérdezed, hogy mi köze annak amiről beszéltem ahhoz, amiről sem én, sem te nem beszéltünk eddig (ti. a preemptív, nem realtime scheduler-hez)?

    De, natív binárisokkal dolgozik. Legalábbis a kód hot spotnak titulált részei azok(ká fordulnak idővel). 

    Nem, nem azzá fordulnak, hanem natív kóddá. Ami tök más, mint egy natív bináris, ami ugye egy fájlt jelent.

    Mintáról beszélsz, nem adatmennyiségről - csapó 3.

    Arról beszélek, hogy amit te mintának hívsz, az az adatmennyiség függvénye. Csapó 3.

    "hogy a hot code-od első műveletének végrehajtásához is először egészen a fizikai lemezig kell elmenni érte"
    A hot code jelentése pont az, hogy a processzor jelentős időt tölt annak a végrehajtásával. Tehát a hot code-ért nem megy már sehova, hiszen ponthogy épp végrehajtja. 

    És még mindig nem érted, hogy ahhoz, hogy valami egyáltalán "hot code" lehessen, ahhoz egy rakás megelőző lépésen kell átmennie. Többek között először be kell olvasni a lemezről azt a Java kódot, amiből majd valamikor, sokkal később, sok-sok lépés után a "hot code" legenerálásra kerülhet. És hogy ezzel összefüggésben értelmetlen azt tenni, amivel te próbálkozol, hogy onnan próbálod vizsgálni a gyorstár működését, hogy már van egy tárgyi, natív "hot code", ami már ráadásul bent is van még a legbelső gyorstárban is, és hogy onnan hogyan működik a végrehajtási sebesség. Mert hogy nem utóbbi a futási sebesség. Illetve, mert utóbbi sebességen (ti. hogy a processzor egy adott gépi kódú utasítást milyen gyorsan hajt végre) definíció szerint nem tud semmilyen Java technológia lassítani vagy gyorsítani, csak az, ha növeled vagy csökkented a processsor órajelét. Mert persze az, hogy milyen a gyorstárak hit/miss aránya. De ez ugye megint egy olyan kérdés amit nagyon nem értesz.

    Valóban nem. Rengeteg ciklus futtatásával töltik az idejüket. 

    Nem, az elemi ciklusok abszolút kisebbségben vannak. Tölts be egy tetszőleges hétköznapi programot egy disassembláló debuggerbe, és kezd el lépegetni benne. Nagyon, de nagyon sok lineáris, illetve hívó utasításon fogsz keresztülmenni mire egyáltalán egy-egy ciklushoz eljutsz benne - és annak iterációszáma is jellemzően minimális lesz, belseje pedig jó eséllyel szintén nagyon, de nagyon sok utasításból álló szubrutinok meghívásából fog állni, amik direktbe "telibevágják" maga az eredeti ciklus gyorstárazását.

    És pont arra való a cache, hogy ezek a ciklusok késleltetés nélkül tudjanak futni.

    Nem, a "cache" - pláne így általánosságban - nem erre való, és nem is tudja ezt biztosítani akkor ha a ciklusok magjában tőle távoli régiókba mutató hívások vannak, amik többek között pont a ciklus tartalmazó blokkot fogják potenciálisan kirúgni a gyorstárból. Ami bármilyen értelemben is kifejezetten a ciklusok valamiféle késleltetés néküli futását biztosítja az a prediktív végrehajtás.... ami megint egy olyan dolog, aminek köze nincs semmihez amiről eddig szó volt, de amit te ennek ellenére teljesen nyilvánvalóan össze-vissza keversz mindennel, meg nem értve, hogy miről is szól, vagy hogy mennyire semmi köze nincs semmiféle gyorstárhoz (vagy nem több, mint akármelyik elemi műveletnek).

    Forrás?

    A valóság. Amivel nem vagy tisztában. De megnézheted. Fent leírtam hogyan.

    Egyébként ha lineárisan fut, akkor javarészt cacheből dolgozik.

    Aminek semmi köze a ciklusokhoz.

    Ha ugrál távolságokra, akkor nem. És megint: minta...

    Ami a méret, a távolság egyenes függvénye. Csapó 4. És még mindig nem érted.

    Igen. Feltéve, hogy .

    Nem. Feltétlel nélkül.

    De megint nem tudom ennek mi köze ahhoz, hogy nem az adatmennyiség határozza meg a cache hatékonyságát.

    Az, hogy az adat- és kódmennyiség határozza meg a gyorstár hatékonyságát.

    Na ne viccelj :) Nézz már meg egy profilert...

    Nem viccelek. Pont azért, mert én már rengeteg kódot nézegettem.

    Ugyebár ezt írtam. Ez konkrétan egy ellenpéldának tűnik a te állításodra...

    Nem, nem az én állításomra írtad ellenpéldának (főleg, hogy nem is idéztél állítást tőlem az egész hozzászólásban, amiben leírtad), hanem a te általánosító állításod bizonyítására. 

    Már hogy a viharba ne mérném/mérhetném? Küldjek az eredményről screenshotot? :)

    Igen, kérlek küldj screenshotot arról, hogy megmérted mondjuk a processzorod L2 gyorstárának hit/miss arányát, ráadásul kizárólag csak a te programod és a 1TB-os adatfeldolgozásod vonatkozásában! Köszönöm.
    Mutasd a teljes hozzászólást!
  • Nem, egyrészt ez semmilyen szinten nem definiált, nem rögzített. Az, hogy egy osztályfájlt mikor tölt be és mikor generál kódot belőle, kizárólag mindenkori Java futtatókörnyezet (a te megfogalmazásodban: a "JVM") dolga és felelőssége, és bármikor is teszi azt meg, az szemantikailag az alkalmazás működésén nem változtat, nem változtathat - definíció szerint.

    A megfogalmazásomban JVM, hiszen így hívják. Ez a JVM feladata, amit a JVM specifikációja részletesen taglal. Beleértve azt is, hogy az osztályok betöltése dinamikusan történik, és hogy a class definíció beolvasása akkor történik, amikor egy másik osztály az új, létrehozandó osztályt hivatkozza. Nagyon tömören és röviden. Arról nem beszélve, hogy pont a cikk által hivatkozott - egyelőre csak brainstorming - pont ezen kíván változtatni. Vagyis hogy ne legyen dinamikus osztálybetöltés. És teszi ezt azért, hogy elvégezhesse azokat az analíziseket, amik alapján - szerinted - akár most is betöltheti az osztályokat előre. De persze ha minden classpathon lévő osztályt betölt, akkor igen, akkor betöltheti. Egyébként meg fogalma sincs mit kéne betölteni.

    Az operációs rendszer, a háttértár stb nem töltheti be és nem töltheti elő. Az osztály betöltése ugyanis nem azt jelenti, hogy beolvasok X byte-ot. Maga a jar bekerülhet a disk cache-be, igen, és ez felfogható úgy, hogy a JVM footprintje. Bár erősen hunyorogni kell hozzá, hogy így lássuk. De ezt írtam még egész az elején...

    Másrészt itt megint "betöltés"-t emlegetsz, miközben meg állítólag a futási, végrehajtási időkről akarsz valamit mondani - miközben a kettőnek nyilván (abban az értelemben ahogy te használod ezeket a fogalmakat) semmi köze nincs egymáshoz.

    Igen. Azt mondtam, hogy a cikk címével és tartalmával ellentétben ez a javaslat nem fogja a Java alkalmazások vonatkozásában azt jelenteni, hogy azok "gyorsabban futhatnak". Hiszen ez az indulást és a betöltést fogja csak érinteni.

    Hogyan teheti meg, hogy "hozzá se nyúl", amikor egy fájlban van a többi osztállyal?

    Úgy, hogy nem kell végigolvasni egy egész zip file-t ahhoz, hogy tudd milyen file-ok vannak benne... A többi kérdésre ugyanez a válasz. Kivéve az OS és a disk-kel kapcsolatos kérdések. De azokat meg én magam írtam le, még mielőtt megkérdezted volna...

    "Kb annyi, hogy ezek a fázisok nem vesznek el CPU időt az alkalmazás elől."De, elvesznek, még akkor is, ha sosem kerülnek meghívásra.

    Olvasd el mire válaszolsz. Pont azt mondtam, hogy a Leydennel ezek nem fognak elvenni időt, míg jelenleg elvesznek (azok a betöltési fázisok, amiket a Leydennel meg akarnak spórolni). Illetve hozzátettem, hogy ez (1-2 specifikus alkalmazást leszámítva) elég jelentéktelen idő az indulást leszámítva.

    Mert hiába dolgozol fel ugyanannyi adatot, ha az nagyobb területen van szétszórva, akkor megint a gyorstárazás sajátosságai miatt (ti. mert az és az is ahonnan behívja az adatokat tipikusan lapokra, szegmensekre, szektorokra, és más fix méretű, de az elemei adathozzáférés egységéhez képest nagy méretű blokkokra van bontva) romlani fog a hit/miss arány, ezzel pedig az effektív adatelérési és végrehajtási sebesség is.

    És ugye pont ez a jelentése a hozzáférési mintának. Ha ugyanannyi adatot dolgozol fel a memóriát szekvenciálisan, vagy random olvasva, nagyságrendbeli eltérés lesz a feldolgozási időben. És mindez pont azért, mert nem az adatmennyiség, hanem a hozzáférési minta határozza meg a cache hatékonyságát. 

    "Ha a memóriában tartom a világ összes adatát, de mindig ugyanazt használom fel belőle, a cache hit-em 100% lesz (az első miss után)."
    Nem, nem, és nem. Lásd fent! Egyszerűen alapvető dolgokat nem tudsz és értesz abból, hogy miként működik akár csak egyetlen elemi utasítás végrehajtása is a gépen belül, hogy ennek során hány különböző gyorstáron megy át mind az adott utasítás, mind az operandusai, illetve, hogy ez milyen hatással van a végrehajtás sebességére.

    Próbáld már ki :) Mégis mi ütné ki az adatot a cache-ből, ha semmi mást nem használ fel a program? A C leveleket most hagyjuk. 

    "Egyrészt tévedsz, másrészt ahogy írtam is, az egész adat a memóriában van. Igen, mind a több, mint 1TB."Tehát abszolút nem érted mi a különbség a "gyorstár" és a "memória" fogalma között, és hogy ezek semmilyen szempontból nem ekvivalens fogalmak. Hát, ez sok mindent megmagyaráz.

    :) A memória azt jelentette, hogy a memóriában van az 1TB+ adat. És ezt azért írtam, mert merevlemezről kezdtél beszélni. 

    Egyrészt nem, a processzor nem a végrehajtott kódban látott alapján tölti elő a gyorstárat

    Szerencsére olyat senki nem is mondott, hogy a végrehajtott kódban látottak alapján tölt elő (leszámítva az erre hivatott utasítást természetesen). A kód szekvenciálisan olvasásáról volt szó (4. sor a linkelt táblázatban).  

    Másrészt ez nem változtat azon semmit, hogy ha összességében nagyobb területen vannak elszórva az adatok és a kódok - pl. mert közbe vannak tűzdelve valójában nem használt elemekkel -, akkor a gyorstár hit/miss aránya rosszabb, a futás pedig végső soron lassabb lesz, még a natív és elemi kódok vonatkozásában is, pusztán annál fogva, hogy kevésbé lesz lineáris mind a kód, mind az adat elérése.

    Megint mintáról beszélsz, nem adatmennyiségről...

    Ez egyrészt - némi túlzással - kb. a huszonhatmilliomodik lépés a van egy Java alkalmazásom, és azt futtatom folyamatban, amit számtalan egyéb előz meg, amire a HotSpot JIT nincs és nem is tud hatással lenni, lévén a fordító, a háttértár, az operációs rendszer, stb. hatáskörébe tartozó dolgok, de amik mind befolyásolják a fent írtak mentén azt, hogy a programot felépítő egyes műveletek végrehajtása mikor kezdődik meg és mennyi idő alatt hajtódik végre, tehát hogy végső soron annak futása milyen gyors lesz.

    Ja, egy preemptív, nem realtime scheduler csodákra képes. De ennek mi köze ahhoz, amire válaszoltál? Vagyis hogy a HotSpot JIT (ami maga a fordító) szekvenciálisan fordít pont azért, hogy az előbb említett IP alapú prefetcherre támaszkodva javítsa a futási sebességet a cache missek arányának csökkentésével?

    Nem mintha Java esetében, ami ugye nem is natív binárisokkal dolgozik, értelmes lenne általánosságban megpróbálni különbséget tenni adat és kód között - hiszen esetében minden kód a futtatás és a végrehajtás bizonyos fázisban adat, legalábbis a processzor szempontjából mindenképpen.

    De, natív binárisokkal dolgozik. Legalábbis a kód hot spotnak titulált részei azok(ká fordulnak idővel). Pont ezért hívják HotSpot-nak...

    Márpedig azt, hogy az hogyan és mennyi idő alatt tud egyáltalán oda bekerülni vagy ott van -e, alapvetően meghatározza az, hogy akár a kódok, akár az adatok mekkora területen vannak szétszórva, és mennyire telítik a különböző gyorstárakat.

    Mintáról beszélsz, nem adatmennyiségről - csapó 3.

    hogy a hot code-od első műveletének végrehajtásához is először egészen a fizikai lemezig kell elmenni érte

    A hot code jelentése pont az, hogy a processzor jelentős időt tölt annak a végrehajtásával. Tehát a hot code-ért nem megy már sehova, hiszen ponthogy épp végrehajtja. De igen, egyszer be kell tölteni diskről, mielőtt először futtatná.

    a leleslegszámításintenzívebb, de egyben legelemibb, nem-interaktív, egyszálú és I/O-szegény programokat leszámítva (tehát kb. 99.99999%-ban) semelyik program nem tölti, nem hogy a döntő, de egyáltalán akár csak jelentékeny részét is egy-egy ciklus futtatásával.

    Valóban nem. Rengeteg ciklus futtatásával töltik az idejüket. És pont arra való a cache, hogy ezek a ciklusok késleltetés nélkül tudjanak futni. 

    A valóságban persze a legtöbb program az ideje legnagyobb részében vagy lineárisan fut vagy ugrál kisebb-nagyobb távolságokra (de nem ciklikusan)

    Forrás? Egyébként ha lineárisan fut, akkor javarészt cacheből dolgozik. Ha ugrál távolságokra, akkor nem. És megint: minta...

    És amik mellesleg modern hardveren és modern operációs rendszereken kontextusváltásokat hajtanak végre, szinte számolatlanul, ami önmagában "telibevág" minden L1 szintű megfontolást a köztük futtatott kód vonatkozásában, nem csak az L1 gyorstárra gyakorolt hatása, de puszta időigénye folytán is.

    Igen. Feltéve, hogy kontextusváltás során pl nem tölti elő a cache-ekbe a program switchelés előtti állapotát. De megint nem tudom ennek mi köze ahhoz, hogy nem az adatmennyiség határozza meg a cache hatékonyságát.

    viszont egyrészt egy-egy kimazsolázott ciklus semmilyen meghatározó hatással nem lesz a program futtatási sebességére,

    Na ne viccelj :) Nézz már meg egy profilert...

    Nem. Te "a mostanában 1TB feletti (memóriában tárolt) adatmennyiséggel végzett tesztjeim" során állítólag tapasztaltakkal próbáltad bizonyítani azon kijelentésed, hogy "nem a cache-elendő adatmennyiséggel változik elsősorban a cache/miss ratio". Tehát - ahogy mondtam - egyetlen példával egy általános érvényű kijelentést próbáltál igazolni. Ami ugye eleve logikailag hibás szerkezet. Amihez képest az, hogy "a cache/miss ratio"-idat valójában nyilván nem mérted és nem is mérhetted (pusztán fizikai korlátoknál fogva sem), tehát hogy még az egyetlen példád sem volt tényszerűnek és helytállónak tekinthető, már csak ráadás.

    Ugyebár ezt írtam. Ez konkrétan egy ellenpéldának tűnik a te állításodra...

    Ha úgy lenne igaz, ahogy mondod, akkor a mostanában 1TB feletti (memóriában tárolt) adatmennyiséggel végzett tesztjeim pocsék hit ratiot mutatnának. De hát nem azt mutatnak...

    Amihez képest az, hogy "a cache/miss ratio"-idat valójában nyilván nem mérted és nem is mérhetted (pusztán fizikai korlátoknál fogva sem), tehát hogy még az egyetlen példád sem volt tényszerűnek és helytállónak tekinthető, már csak ráadás.

    Már hogy a viharba ne mérném/mérhetném? Küldjek az eredményről screenshotot? :)
    Mutasd a teljes hozzászólást!
  • Az, hogy a JVM hogyan tölti be az osztályokat, mikor, milyen lépésekben, az elég jól definiált.

    Nem, egyrészt ez semmilyen szinten nem definiált, nem rögzített. Az, hogy egy osztályfájlt mikor tölt be és mikor generál kódot belőle, kizárólag mindenkori Java futtatókörnyezet (a te megfogalmazásodban: a "JVM") dolga és felelőssége, és bármikor is teszi azt meg, az szemantikailag az alkalmazás működésén nem változtat, nem változtathat - definíció szerint. Utóbbi ami definiált, nem az, hogy mikor és hogyan történik az osztály betöltése, ami ráadásul nem is csak a Java futtatókörnyezeten múlik. Mert hogy az operációs rendszer, a háttértár, stb. mind betöltheti vagy előtöltheti azt a saját gyorstárazási stratégiája részeként. (Ezért is értelmetlen az önmagában semmitmondó "betöltés" fogalom használata részedről.)

    Másrészt itt megint "betöltés"-t emlegetsz, miközben meg állítólag a futási, végrehajtási időkről akarsz valamit mondani - miközben a kettőnek nyilván (abban az értelemben ahogy te használod ezeket a fogalmakat) semmi köze nincs egymáshoz. Tehát eleve egy olyan dolgon pörögsz, aminek akkor se lehetne (megint csak definíció szerint) érv abban a témában amibe bele próbálod keverni, ha önmagukban amúgy helyesek lennének a vele kapcsolatos állításaid. Az, hogy nem is azok, már csak ráadás.

    Az, hogy a JVM hogyan tölti be az osztályokat, mikor, milyen lépésekben, az elég jól definiált. Ami a téma szempontjából lényeges, hogy a jar file egy zip archive, ami .class fájlokat tartalmaz jól definiált struktúrában. Amikhez hozzá se nyúl, ha nem hivatkozzák az adott class-t. 

    Hogyan teheti meg, hogy "hozzá se nyúl", amikor egy fájlban van a többi osztállyal? Hogyan teheti meg a háttértár, hogy nem küldi el annak az osztálynak is legalább egyes részeit felé, ha az a többivel közös szektor(ok)ban van? Hogyan teheti meg az operációs rendszer memóriamenedzsere, gyorstára, hogy nem lapozza ki vagy be annak az osztálynak legalább egyes részeit is, amikor a többi osztállyal közös memórialapon van? Hogyan teheti meg a processzor, hogy nem tölti be a gyorstárába annak az osztálynak legalább egyes részeit is, amikor annak leíró bájtjai is a többi osztályt reprezentáló bájtok között vannak? Honnan tudja a JVM, hogy azzal az osztállyal egyelőre semmit nem kell kezdenie (ha egyáltalán tényleg nem akar vele kezdeni semmit), ha nem dolgozta fel a jar teljes egészét, benne az adott osztályt (és minden másikat) leíró bájtokat is?

    Kezd már leesni mennyire alapvető dolgokat sem látsz át, veszel észre és figyelembe?

     Kb annyi, hogy ezek a fázisok nem vesznek el CPU időt az alkalmazás elől. 

    De, elvesznek, még akkor is, ha sosem kerülnek meghívásra. El lett mondva miért (ti. a gyorstárak sajátosságai és korlátossága, és az ebből eredő hit/miss arány rontása miatt). Amin az, hogy te ezt sem érted, nem változtat semmit.

    Nem a gyorstárazandó adatmennyiség befolyásolja ezt, hanem az az adatmennyiség, ami konkrétan feldolgozásra kerül. 

    És ebben is tévedsz. Mert hiába dolgozol fel ugyanannyi adatot, ha az nagyobb területen van szétszórva, akkor megint a gyorstárazás sajátosságai miatt (ti. mert az és az is ahonnan behívja az adatokat tipikusan lapokra, szegmensekre, szektorokra, és más fix méretű, de az elemei adathozzáférés egységéhez képest nagy méretű blokkokra van bontva) romlani fog a hit/miss arány, ezzel pedig az effektív adatelérési és végrehajtási sebesség is.

    Ha a memóriában tartom a világ összes adatát, de mindig ugyanazt használom fel belőle, a cache hit-em 100% lesz (az első miss után).

    Nem, nem, és nem. Lásd fent! Egyszerűen alapvető dolgokat nem tudsz és értesz abból, hogy miként működik akár csak egyetlen elemi utasítás végrehajtása is a gépen belül, hogy ennek során hány különböző gyorstáron megy át mind az adott utasítás, mind az operandusai, illetve, hogy ez milyen hatással van a végrehajtás sebességére.

    Egészen biztos vagyok, hogy a 1 TB feletti adatmennyiséggel végzett tesztjeid pocsék hit ratio-t mutatnak pl. a processzor néhány tíz MB-os, a merevlemez néhány száz MB-os, de még az operációs rendszer és a virtuális memóriakezelő néhány GB-os gyorstárának szintjén is. Egyrészt tévedsz, másrészt ahogy írtam is, az egész adat a memóriában van. Igen, mind a több, mint 1TB.

    Tehát abszolút nem érted mi a különbség a "gyorstár" és a "memória" fogalma között, és hogy ezek semmilyen szempontból nem ekvivalens fogalmak. Hát, ez sok mindent megmagyaráz.

    Itt két dologban tévedsz. Az egyik, hogy ahogy már írtam, a CPU sok esetben előre a cache-be prefetcheli az adatokat, ha megfelelő mintát lát. 

    Egyrészt nem, a processzor nem a végrehajtott kódban látott alapján tölti elő a gyorstárat, hanem attól teljesen független, általános megfontolások mentén (amik ezzel összefüggésben mellesleg éppen annyira ronthatják is, mint amennyire javíthatják a gyorstár hatékonyságát, attól függően, hogy mennyire helyesek a processzor feltételezései), amik ráadásul elsősorban a végrehajtás és a feldolgozás linearitására épülnek. Másrészt ez nem változtat azon semmit, hogy ha összességében nagyobb területen vannak elszórva az adatok és a kódok - pl. mert közbe vannak tűzdelve valójában nem használt elemekkel -, akkor a gyorstár hit/miss aránya rosszabb, a futás pedig végső soron lassabb lesz, még a natív és elemi kódok vonatkozásában is, pusztán annál fogva, hogy kevésbé lesz lineáris mind a kód, mind az adat elérése.

    Nem véletlenül generál a HotSpot JIT-je (és kb minden fordító) szekvenciális kódot, ahol csak tud. Ide értve a morphic hívásokat is. A kivételes esetben ugrik el, és a tipikus eset utasításai szekvenciálisan követik egymást a memóriában. 

    Ez egyrészt - némi túlzással - kb. a huszonhatmilliomodik lépés a van egy Java alkalmazásom, és azt futtatom folyamatban, amit számtalan egyéb előz meg, amire a HotSpot JIT nincs és nem is tud hatással lenni, lévén a fordító, a háttértár, az operációs rendszer, stb. hatáskörébe tartozó dolgok, de amik mind befolyásolják a fent írtak mentén azt, hogy a programot felépítő egyes műveletek végrehajtása mikor kezdődik meg és mennyi idő alatt hajtódik végre, tehát hogy végső soron annak futása milyen gyors lesz. Másrészt a HotSpot JIT is csak egy logikai leképezését látja csak a memóriának és csak abba dolgozik, ami mögött azonban a fizikai leképezés teljesen más; ami a logikai memóriában lineáris, az a fizikai nem hogy szükségszerűen nem az, de jellemzően nem az; és azt, hogy mennyire nem az, mennyire töredezett megint csak a processzor, memória, a háttértár, stb. szervezésétől és szervezési egységeitől, valamint az ezekkel összefüggésbe hozható gyorstárak szervezésétől és működésétől függ.

    A másik dolog, hogy pont ezért van 2db L1 cache a prociban. Külön van L1D (adat) és L1I (utasítás) cache.

    És van benne L2, sőt, L3 gyorstár is, ami már abszolút nem dedikált, és amiben már az adat és az utasítások is versengenek egymással. És ez még csak a processzor - mert aztán az operációs rendszer, a háttértár, stb. gyorstárai meg aztán abszolút nem tudnak még ennyire se különbséget tenni kód és adat között, és azokban aztán pláne képes az adat a kódot kiszorítani. Nem mintha Java esetében, ami ugye nem is natív binárisokkal dolgozik, értelmes lenne általánosságban megpróbálni különbséget tenni adat és kód között - hiszen esetében minden kód a futtatás és a végrehajtás bizonyos fázisban adat, legalábbis a processzor szempontjából mindenképpen.

    Így a hot code-ot az adat nem fogja kiütni a cache-ből pl egy ciklus közepén.

    Egyrészt itt már megint a sorban ~huszonhatezredik lépésnél kezded a gondolatmenetet, teljesen figyelmen kívül hagyva az előtte lévőket, és azt, hogy először még a "hot code"-nak is valahogy oda kell kerülnie valahogy még az L1i gyorstárba is. Márpedig azt, hogy az hogyan és mennyi idő alatt tud egyáltalán oda bekerülni vagy ott van -e, alapvetően meghatározza az, hogy akár a kódok, akár az adatok mekkora területen vannak szétszórva, és mennyire telítik a különböző gyorstárakat.

    Ha nagyon (ti. nagyon szét vannak szórva és/vagy nagyon telítik nagy mennyiségüknél fogva), akkor lehet, hogy a hot code-od első műveletének végrehajtásához is először egészen a fizikai lemezig kell elmenni érte (mármint magáért a hot code-ért), és amely művelet milliószor, milliárdszor lassabb folyamat lehet önmagában, mint amennyi ideig aztán majd a hot code összesen fut majd, és amik mind hozzáadódnak pusztán ennek csak az önmagában aprócska és akár eleminek is tekinthető hot code végrehajtási idejéhez is.

    Tehát eleve balgaság azt gondolni, hogy azért, mert L1-ben különválik a műveleti és az adatgyorstár, azért az adatok mérete és a gyorstárakra gyakorolt hatása nem lehet hatással a kódvégrehajtás sebességére, akár elemi szinten is. Mert dehogynem, sőt, meghatározó hatással tud lenni rá.

    Másrészt megpróbálod a vizsgálatod mazsolázgatással leszűkíteni egy rendkívül speciális esetre és helyzetre, egy tipikus program kódjának és futási idejének elenyésző részére, egy aprócska, az L1-be is beférő ciklusocska végrehajtására leszűkíteni, és ebből valamiféle következtetéseket levonni - miközben megpróbálod teljesen ignorálni mind a program maradék részét, mind azt, hogy a leleslegszámításintenzívebb, de egyben legelemibb, nem-interaktív, egyszálú és I/O-szegény programokat leszámítva (tehát kb. 99.99999%-ban) semelyik program nem tölti, nem hogy a döntő, de egyáltalán akár csak jelentékeny részét is egy-egy ciklus futtatásával.

    A valóságban persze a legtöbb program az ideje legnagyobb részében vagy lineárisan fut vagy ugrál kisebb-nagyobb távolságokra (de nem ciklikusan), de leginkább olyan kódoknak adja át a vezérlést, amik linearitásáról, ciklikusságáról vagy bármilyen működési sajátosságáról semmit sem tudhat és amire semmilyen hatással nem lehet, mert azt a futtatóplatform, az operációs rendszer, a meghajtóprogramok, stb. biztosítják számára. És amik mellesleg modern hardveren és modern operációs rendszereken kontextusváltásokat hajtanak végre, szinte számolatlanul, ami önmagában "telibevág" minden L1 szintű megfontolást a köztük futtatott kód vonatkozásában, nem csak az L1 gyorstárra gyakorolt hatása, de puszta időigénye folytán is.

    Szóval igen, bár "a hot code-ot az adat nem fogja kiütni a cache-ből pl egy ciklus közepén" (legalábbis ha "cache" alatt kizárólag és csak az "L1i" gyorstárat értjük, ami persze már eleve más, mint ami a mondatdban van; és amely állításról - függetlenül attól, hogy mit értünk "cache" alatt - kijelenthetjük, hogy rajtad kívül senki fel sem vetette, hogy ti. ezt tenné), viszont egyrészt egy-egy kimazsolázott ciklus semmilyen meghatározó hatással nem lesz a program futtatási sebességére, másrészt viszont a kód és az adat abszolút mennyisége alapvetően fogja befolyásolni azt, hogy akár még a kimazsolázott ciklusodból is mikor fog nem hogy az utolsó, de akár csak az első utasítás is végrehajtódni, illetve hogy a ciklusban feldolgozott adatok milyen késleltetések és sebességek mellett lesz elérhető, és hogy ezen keresztül végső soron akár csak a picike kimazsolázott ciklus végrehajtása is mennyi időbe fog ténylegesen telni.

    "Meg azzal, hogy azt is komolyan gondolod, hogy egyetlen példával lehet egy általános jellegű kijelentést igazolni." Nem igazoltam vele semmilyen kijelentésemet. A te állításodat cáfoltam

    Nem. Te "a mostanában 1TB feletti (memóriában tárolt) adatmennyiséggel végzett tesztjeim" során állítólag tapasztaltakkal próbáltad bizonyítani azon kijelentésed, hogy "nem a cache-elendő adatmennyiséggel változik elsősorban a cache/miss ratio". Tehát - ahogy mondtam - egyetlen példával egy általános érvényű kijelentést próbáltál igazolni. Ami ugye eleve logikailag hibás szerkezet. Amihez képest az, hogy "a cache/miss ratio"-idat valójában nyilván nem mérted és nem is mérhetted (pusztán fizikai korlátoknál fogva sem), tehát hogy még az egyetlen példád sem volt tényszerűnek és helytállónak tekinthető, már csak ráadás.
    Mutasd a teljes hozzászólást!
  • Az, hogy a JVM hogyan tölti be az osztályokat, mikor, milyen lépésekben, az elég jól definiált. Ami a téma szempontjából lényeges, hogy a jar file egy zip archive, ami .class fájlokat tartalmaz jól definiált struktúrában. Amikhez hozzá se nyúl, ha nem hivatkozzák az adott class-t. Ezeket a nem hivatkozott classokat nem töltötte be eddig se. Konkrétan a class definícióval sem találkozik addig, amíg nem hivatkozzák azt. Pont. Megint írtad a litániát a semmiről, meg a ki mit tudról feleslegesen (nem csak hogy tudom ezt, de még monitorozom is). De ennek nagyon érintőlegesen van csak köze a "gyorsabban futhat"-hoz, amire én reagáltam. Kb annyi, hogy ezek a fázisok nem vesznek el CPU időt az alkalmazás elől. Ami pont az induláskor számottevő. 

    A gyorstárazandó adatmennyiség alapvetően befolyásolja egy adott méretű gyorstár hit/miss arányát, pusztán azon okból kifolyólag, hogy ez alapvetően befolyásolja azt is, hogy hányszor kell kidobálni a gyorstárból a már bent lévő szegmenseket/adatelemeket

    Nem a gyorstárazandó adatmennyiség befolyásolja ezt, hanem az az adatmennyiség, ami konkrétan feldolgozásra kerül. Ha a memóriában tartom a világ összes adatát, de mindig ugyanazt használom fel belőle, a cache hit-em 100% lesz (az első miss után). 

    Az egy elég közismert tény, hogy a cache hatékonysága elsősorban a hozzáférési mintától függ. Szemben a cache-elt adat méretétől. Ez elég logikus is, hiszen a cache hit definíciója pont az, hogy már benne van a cache-ben. Vagyis ha a minta olyan, hogy jellemzően a cache-be már töltött adatokan dolgozik, akkor a cache hit aránya magas lesz akkor is, ha csillió TB a cache-elt adatmennyiség. Emellé a CPU ugye figyeli is ezeket a hozzáférési mintákat, és ha felismert mintát talál, prefetcheli neked a prefetch algoritmus által definiált cache rétegbe. Ezért ha pl szekvenciálisan dolgozol fel 1TB adatot, akkor a cache hited aránya nagyon magas lesz, és a CPU minimális időt fog várakozással tölteni (pláne, hogy még reordering is létezik). 

    Továbbá a teljesen random minta esetén (ami a CPU cache ellensége) a cache miss esélye az adatmennyiség függvényében nem lineárisan nő, vagyis bizonyos méret felett a görbe ellaposodik. Ezért egy adott ponton túl a cache-elt adat mennyiségének növelése már nem jár a cache romlásával. Ezért nincs értelme a CPU-ban az L3 cache méretét az égbe növelni (amíg nagyságrendbeli a különbség a cache és a memória mérete között): ha nem felismerhető a minta, jó eséllyel úgyis miss lesz. Akkor is, ha 10x akkora a cache, hiszen a memória mérete annak is sokszorosa (szerintem te erre gondolsz egyébként). És pont ez a cáfolata is annak, hogy a cache hatékonyságát alapvetően befolyásolná az adatmennyiség. Ha így lenne, a CPU cache teljesen haszontalan lenne. De ezt tudjuk, hogy nem így van, így biztosan más tulajdonság határozza meg a hatékonyságot. Ami ugyebár a minta.

    Egészen biztos vagyok, hogy a 1 TB feletti adatmennyiséggel végzett tesztjeid pocsék hit ratio-t mutatnak pl. a processzor néhány tíz MB-os, a merevlemez néhány száz MB-os, de még az operációs rendszer és a virtuális memóriakezelő néhány GB-os gyorstárának szintjén is.

    Egyrészt tévedsz, másrészt ahogy írtam is, az egész adat a memóriában van. Igen, mind a több, mint 1TB.

    Sőt, ez az irtózatos mennyiség még a kódod nettó végrehajtási sebességét is biztosan csökkenti, pusztán azon keresztül, hogy annak a gyorstárazása elől is elvesz gyorstárat, és annak (ti. magának a kódnak) a hit/miss arányát is rontja.

    Itt két dologban tévedsz. Az egyik, hogy ahogy már írtam, a CPU sok esetben előre a cache-be prefetcheli az adatokat, ha megfelelő mintát lát. Pl szekvenciális olvasást. Nem véletlenül generál a HotSpot JIT-je (és kb minden fordító) szekvenciális kódot, ahol csak tud. Ide értve a morphic hívásokat is. A kivételes esetben ugrik el, és a tipikus eset utasításai szekvenciálisan követik egymást a memóriában. És (egyebek mellett) ezért is az inline-ing az egyes számú optimalizációja a fordítóknak. A másik dolog, hogy pont ezért van 2db L1 cache a prociban. Külön van L1D (adat) és L1I (utasítás) cache. Így a hot code-ot az adat nem fogja kiütni a cache-ből pl egy ciklus közepén. Ha kíváncsi vagy, megnézem, hogy az említett tesztben konkrétan a code read-nek milyen hit ratio-ja van (igen, ezt is mérem).

    Meg azzal, hogy azt is komolyan gondolod, hogy egyetlen példával lehet egy általános jellegű kijelentést igazolni.

    Nem igazoltam vele semmilyen kijelentésemet. A te állításodat cáfoltam (te magad másoltad be). Azt meg tudjuk mit jelent az, hogy "ellentmondásra jutottunk"...
    Mutasd a teljes hozzászólást!
  • Jah. A szokásos bullshit storm, a végén a "nem válaszolok egyenesen a kérdésedre, de azért te hülye vagy, én meg okos" "válasszal".

    Jah. A szokásos besértődök és eljátszom a mártírt bullshit storm (és azt mondom a másikra, hogy nem válaszolt egyenesen, mikor litániákat írt, szájbarágósan elmagyarázva mindent), mert rájöttem, hogy már megint nem volt igazam, és kár volt ebbe is belekötnöm, amikor alapfogalmakkal sem vagyok tisztában dolog.

    A végén az okfejtéssel, ami csak az alapjaiban rossz. Ugyanis - ahogy már mondtam - a nem használt osztályok sose voltak betöltve. Tehát ebben nincs változás.

    De, a háttértár, az operációs rendszer, sőt, még a Java futtatókörnyezet bizonyos része szempontjából is be voltak töltve, az őket tartalmazó .jar részeként/révén. Legfeljebb kód nem került még generálásra mögéjük, meg egyes szibóluminformációk nem lettek feldolgozva, feloldva - bár igazából ezt se veheted készpénznek, mert ezek már mind olyan dolgok, amiket a Java futtatókörnyezet saját hatáskörben végez el, és akár szépen a háttérben meg is csinálhatja akkor is, kvázi előre dologzva is, ha az osztály amúgy ténylegesen sosem kerül felhasználásra a program futása során.

    És amit viszont biztosan nem csinál meg a korábban felsoroltak egyike sem akkor ha az osztály bájtkódja már eleve benne sincs a képfájlban (mert így nincs miből dolgozniuk, ugye), mert már fordítási időben ki lehetett szórni, illetve mert eleve nem elvárás, hogy utólag be lehessen tölteni plusz osztályt, ami felé ezeket biztosítani kellene. Sőt, mivel a képfájlon belül hivatkozásokat eleve előre fel lehet oldani, és mivel kifelé szimbóluminformációt nem kell biztosítani, ezért lehet, hogy már eleve ezeket sem kell belepakolni a képfájlba, amikkel így még tovább lehet csökkenteni a betöltendő és feldolgozandó adat, illetve kód mennyiségét.

    Szóval, de, van változás, rengeteg. Csak akinek gőze sincs arról, hogy belül hogyan működnek a dolgok, az ezekről mit sem tud.

     Ergo a nem megváltozott működés nem fog teljesítményjavuláshoz vezetni.

    Hamis premisszimákból csak hamis következtetésre lehet jutni. Íme az ékes példa rá.

    Ha meg már megint cache-elünk, akkor érdemes azt is hozzávenni, hogy ugye nem a cache-elendő adatmennyiséggel változik elsősorban a cache/miss ratio, hanem a hozzáférési mintától

    Ami persze nem igaz. A gyorstárazandó adatmennyiség alapvetően befolyásolja egy adott méretű gyorstár hit/miss arányát, pusztán azon okból kifolyólag, hogy ez alapvetően befolyásolja azt is, hogy hányszor kell kidobálni a gyorstárból a már bent lévő szegmenseket/adatelemeket, és a lassabb háttértárból / következő szintű gyorstársból betölteni egy másik szegmenst/adatelemeket, majd aztán újra esetleg a korábban már ott lévőt, csak időközben kipakoltat. Amin persze túl más szintű hozzáférési minták is befolyásolhatják a hatékonyságot, de azt mondani, hogy az adatmennyiség ne befolyásolná meghatározóan és alapvetően, az egyértelműen hülyeség. Egy alapvetően ugyanolyan hozzáférési minta mellett elért, de mondjuk 2x, 10x vagy 100x akkora adathalmaz hit/miss aránya ugyanabban a gyorstárban ugyanarra az adategységre vonatkoztatva mindig rosszabb lesz. Egyetlen kivétel persze az, ha a hit arány már eleve nulla, mert annál rosszabb nyilván nem lesz - de ekkor meg nincs is értelme a gyorstár használatának, létezésének.

    Úgyhogy az az összefüggés sem áll (illetve nem úgy). 

    Tökéletesen áll. Ami nem áll, azok a premisszimiád, amikből kiindulva abszolút téves következtetésekre jutsz. Úgy is mondhatnám, hogy ami itt a baj, hogy a szóban forgó dolgoknak a belső működését alapvetően nem érted, csak a felszínt kapargatod - csak erre megint megsértődnél és mártítkodnál.

    Ha úgy lenne igaz, ahogy mondod, akkor a mostanában 1TB feletti (memóriában tárolt) adatmennyiséggel végzett tesztjeim pocsék hit ratiot mutatnának. De hát nem azt mutatnak...

    Egészen biztos vagyok, hogy a 1 TB feletti adatmennyiséggel végzett tesztjeid pocsék hit ratio-t mutatnak pl. a processzor néhány tíz MB-os, a merevlemez néhány száz MB-os, de még az operációs rendszer és a virtuális memóriakezelő néhány GB-os gyorstárának szintjén is. Sőt, ez az irtózatos mennyiség még a kódod nettó végrehajtási sebességét is biztosan csökkenti, pusztán azon keresztül, hogy annak a gyorstárazása elől is elvesz gyorstárat, és annak (ti. magának a kódnak) a hit/miss arányát is rontja. Csak te erről nem tudsz. Na, ez utóbbival van itt a valódi baj. Meg azzal, hogy azt is komolyan gondolod, hogy egyetlen példával lehet egy általános jellegű kijelentést igazolni. Hogy csak a legnyilvánvalóbb hibákra mutassak rá az érvelésedben.
    Mutasd a teljes hozzászólást!
  • Jah. A szokásos bullshit storm, a végén a "nem válaszolok egyenesen a kérdésedre, de azért te hülye vagy, én meg okos" "válasszal". 

    A végén az okfejtéssel, ami csak az alapjaiban rossz. Ugyanis - ahogy már mondtam - a nem használt osztályok sose voltak betöltve. Tehát ebben nincs változás. Ergo a nem megváltozott működés nem fog teljesítményjavuláshoz vezetni. Kizárólag az indulás és a warmup fog változni, ami cloudban pl igen fontos. Pont ezért szóltam hozzá, mert a cikk következtetése (ahogy a mások értik/érthetik), nem volt teljesen helyes.

    Ha meg már megint cache-elünk, akkor érdemes azt is hozzávenni, hogy ugye nem a cache-elendő adatmennyiséggel változik elsősorban a cache/miss ratio, hanem a hozzáférési mintától, ami azért többnyire jól megjósolható kód esetében, a JVM fordítója nem keveset dolgozik ezen. Úgyhogy az az összefüggés sem áll (illetve nem úgy). Ha úgy lenne igaz, ahogy mondod, akkor a mostanában 1TB feletti (memóriában tárolt) adatmennyiséggel végzett tesztjeim pocsék hit ratiot mutatnának. De hát nem azt mutatnak...
    Mutasd a teljes hozzászólást!
  • A "gyorsabban futhat" helyes értelmezésére viszont én azért kíváncsi lennék, ha az nem a jobb futásteljesítményt jelenti (akár throughput, akár latency).

    Ez attól kérdezd meg, akitől azt hallottad, hogy ezek egyik sem! Mert ugye valójában ezek megint teljesen új fogalmak, amiket itt eddig senki sem használt, és amikről ezzel összefüggésben itt senki sem mondott semmit. És amik nem ekvivalensek egyik olyan fogalommal sem, amikről lett ténylegesen is mondva valami. Ehhez képest az, hogy önmagukban ezek is gumifogalmak, és ha akarom ezt jelenti, ha akarom meg azt (hiszen még pontosan az sincs megjelölve, hogy minek a késleltetése meg áteresztőképessége), már csak ráadás.

    Ahogy az is (csak ráadás), hogy ha valaki nem érti, hogy attól, hogy kisebb területen helyezkedik a kód és/vagy az adat (pl. mert a nem használt osztályok kódja eleve nem kerül betöltésre, sőt, belefordításra sem a képfájlba), vagy hogy az osztályinicializációk már fordítási időben végrehajtásra kerülhetnek (amely két fejlesztés is egyértelműen deklarált része a Leyden technológiának), már önmagában növekedhet a legszigorúbb értelemben vett tárgykód legszigorúbb értelemben vett végrehajtási sebessége (a "latency" és "throughput" is, sőt, még a "peak performance" is, még a processzor szintjén is, pusztán a gyorstárak működési sajátosságai és a hit/miss arány változásai miatt), akkor az eleve nem kvalifikált egy ilyen vitában történő részvételre.

    Más jelentését én ugyanis még nem nagyon hallottam...

    Ez nem az adott fogalomról mond el valamit.
    Mutasd a teljes hozzászólást!
  • A "gyorsabban futhat" helyes értelmezésére viszont én azért kíváncsi lennék, ha az nem a jobb futásteljesítményt jelenti (akár throughput, akár latency). Más jelentését én ugyanis még nem nagyon hallottam...
    Mutasd a teljes hozzászólást!
  • Akkor másképp megfogalmazva:
    Az emberek jelentős része, ha meglát egy ilyen szöveget, hogy "gyorsabban futhat" egy program az adott platformon, arra gondol, hogy egy újabb optimalizációt vezettek a fordítóban, amitől a peak performance / csúcsteljesítmény lesz jobb.
    Mutasd a teljes hozzászólást!
  • Tehát a program sokkal gyorsabban indulhat és futhat.

    A korábbi warmup ideje alatt igen. Utána meg ugyanazt tudja. Tehát egy AWS lambdát valóban gyorsítani fog. Egy klasszikus szerver alkalmazást csak nagyon rövid időre.

    A "large footprint" (nagy lábnyom) egyértelműen a memóriára vonatkozik.

    Ez a project az alkalmazás méretét (jar) csökkenti a nem használt osztályok kidobásával. Itt lesz egy masszív csökkenés (disk és főleg hálózat). A JVM-en belül a használt osztályok 2 területből foglalnak memóriát: a compressed class space és a code cache. Mindkettő mérete a betöltött osztályok számának függvénye, ami nem változik. A nem használt osztályokat eddig se töltötte be. Úgyhogy ha a memóriára gondolt, akkor kíváncsi leszek hol talál nagyságrendi csökkentési lehetőséget. Persze a jarok maguk valóban bekerülnek a memóriába (disk cache, vagy buffer, ha hálóval lett olvasva), úgyhogy itt lehet spórolni, és ez nevezhető memóriával spórolásnak. De ez nagyságrendet nem fog változtatni, mivel a heap a domináns.
    Mutasd a teljes hozzászólást!
  • "Futási teljesítmény" alatt peak performance-t szoktuk érteni.

    Nem, nem szoktuk azt érteni alatta. A "peak performance" eleve nem a "futási teljesítmény"-t hanem a "csúcsteljesítmény"-t jelenti. Azt a sebességet, amire a kód maximálisan képes, tipikusan a sokadik iterációban, amikor már minden körülmény ideális ehhez.

    A "futási teljesítmény" viszont ennél sokkal tágabb dolog, amit ráadásul rendkívül sok másik faktor befolyásol, magán a kód generálási és futási sebességén kívül is. Pl. még a memóriahasználat mértéke és az operatív memória mennyisége is. És ami így eleve nem értelmezhető csak a szigorúan vett kód futási sebességére.

    Ráadásul - mint már megírtam - a "futási teljesítmény" kifejezést nem is használta a cikk, hanem csak BlaZember. Tehát legjobb esetben is saját magát cáfolta.

    A cikkben is benne van, hogy "sokkal gyorsabban [...] futhat az eddigieknél". Ezért valóban megtévesztő a cikk és bevezetője.

    Annak aki képtelen annak érteni a szavakat amit azok valóban jelentenek, minden és bármilyen szöveg az.
    Mutasd a teljes hozzászólást!
  • "Futási teljesítmény" alatt peak performance-t szoktuk érteni. A Leyden ezzel szemben a startup és warm-up time-ról, valamint footprintről (~ memóriahasználat) szól.

    "futási teljesítményt" (ami egyébként a te kifejezésed)

    A cikkben is benne van, hogy "sokkal gyorsabban [...] futhat az eddigieknél". Ezért valóban megtévesztő a cikk és bevezetője.
    Mutasd a teljes hozzászólást!
  • "Az új eszköz a programokból egyetlen, statikus képállományt készít majd, ami sokkal gyorsabban indulhat és futhat "
    A futási teljesítményt ez nem fogja érinteni [..]. Amit a teljesítményen segíteni fog tudni ez a project, az a JVM warm-up (jelentős részének) kiküszöbölése

    Tehát a program "sokkal gyorsabban indulhat és futhat". És még a "futási teljesítményt" (ami egyébként a te kifejezésed) is érinteni fogja.

    ha egyáltalán, memóriáról nem ír semmit Reinhold

    De. Azt mondja, hogy a projekt a "large footprint"-en is fog segíteni, ami egyértelműen a memóriára vonatkozik: "I hereby invite discussion of a new Project, Leyden, whose primary goal will be to address the long-term pain points of Java’s slow startup time, slow time to peak performance, and large footprint".
    Mutasd a teljes hozzászólást!
  • Az új eszköz a programokból egyetlen, statikus képállományt készít majd, ami sokkal gyorsabban indulhat és futhat az eddigieknél, sőt, még memóriahasználata is jelentős csökkenhet a hagyományos módon fordított társához képest.

    A futási teljesítményt ez nem fogja érinteni (ilyet nem is írt), és az alkalmazás memóriahasználatát is csak részben (ha egyáltalán, memóriáról nem ír semmit Reinhold), tekintve, hogy a szemétgyűjtés megmarad, ami (heap) a memóriahasználat jellemzően túlnyomó részét teszi ki. Amit a teljesítményen segíteni fog tudni ez a project, az a JVM warm-up (jelentős részének) kiküszöbölése, ami az időigényes, futásidejű statisztika alapú optimalizálás mellékhatása. De a JIT compiler leváltásáról nincs szó. Nem is nyilvánvaló, hogy az jó ötlet lenne. Az AOT lényege itt az interpretált, és a kezdetlegesen optimalizált fázisok kihagyása. Amik (lokálisan) egy deoptimalizálás során vissza tudnak térni persze.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd