Új hozzászólás Aktív témák
-
P.H.
senior tag
Azért, hogy ne legyen ilyen töredezett a társalgás, legyen egyben az egész.
8.1.1 bekezdés
Az első a bekezdés igazából nem közöl érdemleges információt, csak a sorok között. És kizárólag a tárolási műveletekről szól (MOV mem,reg FST(P) mem FIST(P) mem MOVQ mem,mmreg). A 486-os esetén minden kiírt byte bitjei egyszerre jelennek meg a kiírva, továbbá minden 16 bites adaté, ha az páros memóriacímre lett kiírva és minden 32 bites adaté, ha az 4-gyel osztható címre; Pentium 1-nél továbbá minden 64 bites (=MMX, itt jelent meg) adaté, ha az 8-cal osztható címre.
Ehhez képest a P6 family (Pentium Pro, Pentium 2 és Pentium III) esetén ez lecserélődik arra, hogy bármely 2-, 4- és 8-byte méretű adat bitjei egyszerre jelennek meg kiírva, ha az befér a - az akkor még 32 byte-os - befoglaló cache line-ba, azon belül bárhova (pl. 0x07 címre) írva. Ez a csere a Pentium Pro-val jelent meg, amelyet az Intel az első valóban több CPU-s rendszerekre szánt (aztán a Pentium II sorozatban megjelent a Xeon márkanév), ennyit arról, hogy olyasmivel kell kompatibilisnek lenni, ami még messze nem volt több CPU-s rendszer; technikailag több egymagos CPU és egy többmagos CPU kezelése nem sokban különbözik.
- azaz ha egy másik mag/CPU ráolvas a változóra, vagy a régi, vagy az új értéket fogja látni, fals értéket nem; és ehhez nem kell külön szinkronizálás
- magon belül is fontos ez, mert ez teszi lehetővé a store-to-load-forwarding-ot is a magon belül (azaz ha ugyanaz a mag/CPU olvassa vissza a változót), mert a Pentium Pro az Intel első OoO felépítése.Ez a szabály azt mondja ki, hogy ha pl. 32 bites single precision lebegőpontos változóban pl. 1.1x2^2 érték van jelenleg és kiírunk oda mondjuk 1.5x2^4 értéket, akkor nem lesz olyan órajel/pillanat, amelyben a változó köztes adatot tartalmazna olyan értelemben, hogy pár bit - monjuk a kitevő byte-ja - már megérkezett, a többi még nem, pl. 1.1x2^4 érték lenne a változóban.
Persze ettől eltérően ki lehetne írni nem egyben is, csak az még lassabb is lenne. Ez amúgy nem jelentős kitétel, mert a fordítóprogramok már több évtizede gondoskodnak arról, hogy a változók jól legyenek align-olva akár stack-ben vannak, akár globális változók vagy foglalt (malloc) memóriában vannak: pl. egy byte méretű változónak pl. 4 byte-ot foglalnak le, ha utána közvetlenül uint van, vagy az említett extended precision 10 byte-os számnak 16 byte-ot, a rendszer által adott lefoglalt memória pedig NT 3.1 óta 4-byte aligned, Windows Vista óta pedig 32-es címre van igazítva.Továbbá megfigyelhető, hogy a szabály nem vonatkozik (a 10 byte-os extended precision mellett) a 128 bites (=SSE) adatokra, pedig az a Pentium III-ban jelent meg. Ennek két praktikus oka van, amit nem itt kell keresni:
- egyrészt ekkoriban (a Pentium III-ban, a Pentium M-ben és a Pentium 4-ben is) 64 bites végrehajtókon hajtották végre a 128 bites utasításokat, így a tárolásokat is, így garantálni és garantáltatni sem lehetett, hogy a 128 bites adat teljes egésze egyszerre jelenik meg a külvilág számára
- másrészt az SSE utasítások, legyenek azok load, load-op vagy store jellegűek (load-op-store nincs SSE-ben, sem MMX-ben, sem AVX-ben, legfejlebb non-temporal, de az más téma), per definition megkövetelik, hogy a megadott memóriacím 16-byte aligned legyen. Ellenkező esetben le se futnak, #invalid address (a.k.a. "runtime error 216" vagy "access violation error..." hibát dobnak; erről a programozónak kell gondoskodni (ez nem nehéz, mert a virtuális és a lefordított fizikai memóriacím 4 KB-os lapnál a 12. bittól felfele különbözik csak, tehát programíráskor látható az igazítás).Az SSE utasítások a Core 2-ben kaptak natív 128 bites végrehajtókat és hamarosan (vagy a Westmere-ben, vagy a Nehalem-ben; AMD-nél a K10-ben) eltörölték a 16 byte-aligned memóriacím követelményt, a 128 bites adatokra vonatkozó kitétel mégse jelent meg a szabályban ("elfogyott"). Ahogy a 256 bites AVX sem. Pedig kaphatott volna. Hogy bonyolultabb legyen a kép. Vagy elavultabb?
A tárolás időigénye a fentiek miatt attól függ, hogy hol van az a cache line, amire tárolunk, mivel a tárolás maga csakis az L1-be történhet (hacsak nem non-temporal, akkor meg nem függ attól, hogy van), ezért az L1-be kell hozni az adott cache line-t. Ha legrosszabb esetben RAM-ban van és nincs meg egyetlen közelebbi cache szinten se, akkor sok-sok órajelbe kerülhet. Szerencsére Intel-nél Core2 óta, AMD-nél K10 óta out-of-order a tárolás is (gondolom a store queue, teljes nevén Store Queue for L1-miss Stores szólíthatjuk, mint CPU építőelem ismerős) és mérete szokás szerint nő generációról generációra, közben az utasításvégrehajtás kedvére folytatóthat. (persze ha betelik a retirement window, azaz a ROB közben, akkor van baj, dehát azért optimalizálunk, hogy az L1-hit 95% felett legyen, bár a nagy részben megoldják a hardware prefetch-erek.
A második bekezdés már igenis hordoz lényegi információt. A fordítók készítői számára.
Mégpedig azt, hogy a tárolás nem fér fele 1 cache line-ba, akkor a fenti nem igaz, ez az eset két db tárolási műveletként van implementálva, fele ide, fele oda, a rendszer semmilyen törekvést nem tesz arra, hogy kívülről egyszerre lehessen látni a teljes adatot. Emiatt a programozónak kell gondoskodnia arról, hogy ha az adott adatra ráolvas másik mag/CPU, egy - mostmár 64 byte-os - cache-egységen belül legyen, de mint említettem, a fordítóprogramok ezt elvégzik. Persze szorgos munkával meg lehet ezt kerülni, szorosan típusos nyelvekben mondjuk nem, C-ben hosszadalmas és jól látható pointer+typecasting-gel, vagy ASM-ben pl. megnöveled a stack pointer-t eggyel, de ugye ez mind proaktív dolog.
Amúgy a Bulldozer esetében az AMD valószínűleg pont ezt tolta túl és lett 20+ órajel egy 256 bites store, mert a 256 bites AVX tárolásokra egy modulban egyetlen 128 bites FSTORE tároló végrehajtási egysége van a megosztott FPU-ban, viszont a write-through L1D cache miatt az L2-be kell átvinni az adatot és a Write Coleascing Cache-ben megpróbálták egyesíteni a két felet. Aztán a Kaveri-vel vissza is léptek ettől, mert a szabály ezt nem írja elő; más kérdés, hogy az Intel az AVX-et tudó processzorait eleve 256 bites tárolóporttal szerelte fel.
8.1.2 bekezdés
Tehát a fentiek a store illetve a másik mag/CPU által kiadott load vagy load-op kapcsolatát írják le. Van még egy eset: van egy változó, legyen VAR, ami kezdetben 0; a feladatot elosztottuk két szálra, amelyek növelik ennek értékét (pl. számolnak valamit). Ha mindkét szál lefuttatja az ADD [VAR],1 utasítást mint load-op-store műveletet, akkor nem garantált, hogy nem fog előfordulni, hogy - mivel az újabb CPU belül több mikroműveletre bontotta az utasítást, régi in-order CPU pedig a futószalag elején beolvas, közepén módosít, a végén ér), hogy beolvasva az érték 0, növelve 1, kiírva 1 lesz: azaz 2 helyett 1 lesz az eredmény.
Ezen az utasítások elé lehet kitenni a LOCK prefix-et, azaz LOCK ADD [VAR],1 lesz írva mindkét szál kódjába.
Csak ezen load-op-store utasítások elé, store vagy load-op elé nem lehet, különben jön az #UD, és csak a felsoroltak elé, tehát nincs shift vagy ROR forgatás.A rendszer garantálja, hogy ha azonos órajelben indul el mindkét utasítás, akkor is lesz egy sorrend, amelyben az egyik beolvassa-megnöveli-kiírja (az első snoopable szintre, L1 vagy Bulldozernél és Pentium 4-nél L2) az 1 értéket, majd ezt kapja meg a másik szál utasítása, növeli és kiírja a 2-t.
Amíg le nem fut az ilyen LOCK prefix-szel megjelölt utasítás, addig az adott mag/CPU nem dekódol több utasítást; ez az első magnál lehet gond, mert lehet, hogy neki kell (ha kell) beolvasni RAM-ból az adatot (load-op-store, tehát kell a forrásadat is), eredményét az L1-ből vagy L2-ből közvetlenül megkapja a másik mag/CPU. De hogy ne kelljen RAM-olvasás, van L3; vagy ha Broadwell-t veszel, akkor méretes L4 is.Az egyetlen utasítás, ami elé nem kell kiírni a LOCK-ot, az XCHG mem,reg, mert - ahogy a fejezet is említi -, a CPU automatikusan odagondolja.
Ezek által lehet kezelni a szinkronizációs változókat.
Meglehetősen nehéz kimérni egy memóriaoperandusú utasítás végrehajtását (meg amúgy életszerűtlen), ha az L1-hozzáférés időigényét nem számolod hozzá... De ha sűrűn módosítod a változót, megtalálod az L2-ban vagy az L3-ban (adj a kiírt órajelhez ~15 vagy ~25 órajelet Intel-nél); ha meg nem, akkor 600 órajel se tétel.
8.2.2 bekezdés
Ennek felelnek meg teljes egészében a leírtak. Hogy konkretizáljam:
- az LFENCE, MFENCE, SFENCE, MOVNTxx non-temporal utasítások, külön faj (a lényegük, hogy semmilyen konzisztenciát nem biztosítanak, a tárolt adat semelyik cache-ben nem jelenik meg, egy átmeneti pufferből azonnal a RAM-ba kerül, jelentősen gyorsabb így nagy mennyiségű adat kezelése, mintha cache-be tennék az eredményt, és a cache tartalma is megőrizhető. Az MOVNT-csoport ír, a FENCE-csoport puffert ürít).
- a CLFLUSH a Cache Line Flush to RAM, pl. ha laptáblát módosítasz (pár bitenként egyszerre, mint hozzáférési jogok, címrész) és végül globálisan láthatóvá akarod tenni.
- az I/O műveletek (IN és OUT egy megadott portra) ugyanúgy viselkednek, mint a LOCKED prefix-es utasítások, addig nem dekódol a CPU, amíg ez véget nem ért."Reads may be reordered with older writes to different locations but not with older writes to the same location.[I/]"
Ha ez nem így van bármely CPU-t, a teljes integritást veszélyezteti."Writes are not reordered with older reads."
Szintúgy."The only enhancements in the Pentium 4, Intel Xeon, and P6 family processors are "
"• Added support for speculative reads, while still adhering to the ordering principles above."
Ez tisztán hardware-es. Nagyrészt kiüti "Reads are not reordered with other reads." kitételt, látszólagos megfelelőséget biztosít neki; továbbá az előző pontot is spekulatívvá teszi, nem kell tudni előre, hogy a korábbi tárolás milyen címre történik; ha kiderül később, hogy azonosra, újraindítja a pipeline-t, mint egy sima branch misprediction-nál. Memory Disambiguation a neve."• Store-buffer forwarding, when a read passes a write to the same memory location."
Ezt említettem fejlebb, a load vagy load-op utasítás a store queue-ből veszi a kiírt adatot, nem az L1-ből.A képen látható bal "Writes are in order with respect to individual processes." és a jobb "Writes from all processors are not guaranteed to occur in a particular order." pedig magáért beszél.
-
P.H.
senior tag
8.1.1 Guaranteed Atomic Operations
The Intel486 processor (and newer processors since) guarantees that the following basic memory operations will always be carried out atomically:
• Reading or writing a byte
• Reading or writing a word aligned on a 16-bit boundary
• Reading or writing a doubleword aligned on a 32-bit boundaryThe Pentium processor (and newer processors since) guarantees that the following additional memory operations will always be carried out atomically:
• Reading or writing a quadword aligned on a 64-bit boundary
• 16-bit accesses to uncached memory locations that fit within a 32-bit data busThe P6 family processors (and newer processors since) guarantee that the following additional memory operation will always be carried out atomically:
• Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit within a cache lineCore 2-re elfogyott.
Accesses to cacheable memory that are split across cache lines and page boundaries are not guaranteed to be atomic by the Intel Core 2 Duo, Intel® Atom™, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, P6 family, Pentium, and Intel486 processors. The Intel Core 2 Duo, Intel Atom, Intel Core Duo, Pentium M, Pentium 4, Intel Xeon, and P6 family processors provide bus control signals that permit external memory subsystems to make split accesses atomic; however, nonaligned data accesses will seriously impact the performance of the processor and should be avoided.
An x87 instruction or an SSE instructions that accesses data larger than a quadword may be implemented using multiple memory accesses. If such an instruction stores to memory (pl. az FTS(P) tword - azaz 80 bites extended precision tárolás - ilyen) , some of the accesses may complete (writing to memory) while another causes the operation to fault for architectural reasons (e.g. due an page-table entry that is marked “not present”). In this case, the effects of the completed accesses may be visible to software even though the overall instruction caused a fault. If TLB invalidation has been delayed (see Section 4.10.4.4), such page faults may occur even if all accesses are to the same page.
Erre a fejezetre gondolsz?
-
P.H.
senior tag
Egyszerűbb lenne, ha egyszerűen beidéznéd a vonatkozó részeket, mert én nem azt látom benne, amit leírtál, hanem ezt:
8.1.2 Bus Locking
"Intel 64 and IA-32 processors provide a LOCK# signal that is asserted automatically during certain critical memory operations to lock the system bus or equivalent link. While this output signal is asserted, requests from other processors or bus agents for control of the bus are blocked. Software can specify other occasions when the LOCK semantics are to be followed by prepending the LOCK prefix to an instruction."
8.1.2.2 Software Controlled Bus Locking
"To explicitly force the LOCK semantics, software can use the LOCK prefix with the following instructions when they are used to modify a memory location. An invalid-opcode exception (#UD) is generated when the LOCK prefix is used with any other instruction or when no write operation is made to memory (that is, when the destination operand is in a register)."
"• The bit test and modify instructions (BTS, BTR, and BTC)."
(bit test&set utasítások)"• The exchange instructions (XADD, CMPXCHG, and CMPXCHG8B)."
(compare&exchange utasítások)"• The LOCK prefix is automatically assumed for XCHG instruction."
(exchange reg<->mem)"• The following single-operand arithmetic and logical instructions: INC, DEC, NOT, and NEG."
(logikai utasítások)"• The following two-operand arithmetic and logical instructions: ADD, ADC, SUB, SBB, AND, OR, and XOR."
(logikai és +/- utasítások)Mely eset maradt ki, amikor életbe lép a 8.1.2 fejezet?
"A locked instruction is guaranteed to lock only the area of memory defined by the destination operand, but may be interpreted by the system as a lock for a larger memory area."
"Software should access semaphores (shared memory used for signalling between multiple processors) using identical addresses and operand lengths. For example, if one processor accesses a semaphore using a word access, other processors should not access the semaphore using a byte access."Alapszabály, hogy aligned cache line-ra nem teszünk egyszerre szinkronizációs változót és adatot. Ezt már ~20 éve tudják a fordítóprogramok. (Persze nyilván meg lehet kerülni; milyen keyword-del tudatod tetszőleges nyelvben, hogy az adott változó módosítása elé tegyen LOCK-ot?
És milyen eljáráshívással? SetEvent, ResetEvent, WaitForSingleObject, ...)A idézetből következik, hogy a fenti utasítások nem zárolják a teljes buszt, hanem csak adott memóriaterületet (ami nagyobb lehet, mint a ténylegesen módosított, praktikusan egy 64 byte-os teljes cache line, hiszen az Intel, az AMD vagy a VIA sem a maga ellensége). Ettől még a többi mag korlátozás nélkül végezheti az utasításvégrehajtást.
Ha másért nem is egyértelmű ez, az SSE3-ban (Prescott) bevezetett MONITOR és MWAIT utasítások létezése indokolja ilyen belső hardver létezését.De megnézhetjük, mennyi is egy-egy locked utasítás végrehajtási ideje: naprakész hardvereken ebből a táblázatból is kinézhető http://agner.org/optimize/instruction_tables.pdf, vagy akár AIDA64-ben az Instruction Latency Dump is megadja LOCK ADD és XCHG mem,reg utasítások futási idejét, amelyen lefuttatjuk.
K10: XCHG 21 órajel
Nehalem: XCHG 20 órajel
Sandy B. XCHG 25 órajel
Ivy B. XCHG 25 órajel LOCK ADD: 22 órajel
Haswell: XCHG 21 órajel LOCK ADD: 19 órajel
Bulldozer: XCHG ~50 órajel LOCK ADD: ~55 órajel
Piledriver: XCHG ~40 órajel LOCK ADD: ~40 órajel
Steamroller: XCHG ~38 órajel LOCK ADD: ~39 órajel
(Nem csak a PCLMULQDQ-ról lehet olvasni általánosan a sajtóanyagokban, hanem a locked műveletek gyorsabb és gyorsabb végrehajtásáról is.)Gyakorlatilag magszinten a LOCK-prefixes művelet végrehajtása annyit jelent manapság, hogy amikor találkozik ilyennel a dekóder, akkor addig újabb utasítást nem dekódol, amíg ez végig nem ért a végrehajtási futószalagon és ki nem írta az eredményét egy rendszerszinten látható (=snoopable cache) memóriába (ez általában az L1D, a Bulldozer-család esetében az L2, ezért a nagy időigény).
A többi mag nyugodtan hajthat végre utasításokat, azokat nem befolyásolja (egy utasítást egy mag hajt végre), mert ha ott is van ugyanerrea memóriaterületre vonatkozó locked módosítás, akkor legfejlebb az nyer...; és nem mondom tovább, tudod.
Persze ebből össze lehet hozni az adott magon több száz órajeles időidényt, ha a forrásadatot RAM-ból kell beolvasni, de erre - azaz több mag által frekventáltan módosított adatterületek tárolására - vannak kitalálva alapvetően a nagyméretű L3 cache-ek. A TSX teljesen másra való. -
hugo chávez
aktív tag
Na ez az! Szerverprociknál és pláne multiprocesszoros környezetben elhiszem, hogy gond lehet az x86 memóriamodellje (elvileg pont emiatt szívás a MIC az Intelnek), de otthoni környezetben már nem annyira. Mert nincs is igény a nagyon sok "valódi procimagra", nem lehetne kihasználni őket észszerűen. És valószínűleg nem is lesz... Amdahl törvénye, "Dark Silicon", stb...
Nehéz... Ha lenne értelme (szigorúan PC környezetben, ott, ahol valószínű, hogy nem is nyernének túl sokat az általában 4-8 nagy(obb) teljesítményű magnál többet nem igénylő programok miatt) egyáltalán, akkor melyik érné meg jobban? Megpróbálni a nehézségekkel együtt, vagy bevállalni egy totális ISA váltást, annak minden hátrányával (elsősorban a kompatibilitás elvesztése)?
Nem is konkrétan a memóriamodellre gondoltam, hanem úgy általánosságban összehasonlítva a többi uarch-kal, persze skálázódási szempontból is. Nem nagyon értek ilyen mélységekben ehhez, pont ezért is kérdeztem a véleményed.
Szóval azt mondod, hogy ez végül is a VLIW-EPIC -hez hasonló, de talán továbbgondolt megközelítés? És a TRIPS-nél valamilyen szinten próbálták hardveresen megoldani azt, amit az Itanium "hiányossága" volt?
-
P.H.
senior tag
Ezt meg én nem értem: "x86-ban gyakorlatilag minden utasítás load/store utasítás, ha az első operandus memóriacím", nem locked, ha nem XCHG vagy CMPXCHG. Ha el van látva LOCK prefix-szel, akkor lesz atomi, alapesetben nem az az összes többi load-op-store utasítás. Mit korlátoz ez multiprocesszoros környezetben?
-
hugo chávez
aktív tag
Oké, ez világos. Na de ha szigorúan a PC és mobil vonalat nézzük, ott 8-16 magnál többnek lenne gyakorlati értelme bármilyen memóriamodellel is? Ha valahová nagyon sok szál kell, akkor nem jobb a lebutított apró CPU-származékok helyett egy külön, IGP-szerű tömb, aminek úgy is saját ISA-ja lehet-van, aztán a közös virtuális memórián keresztül meg pofáznak egymással (HSA)? Vagyis nem látom értelmét otthoni felhasználásra olyan CPU-nak, aminél korlátozó lehetne az x86 memóriamodellje azért, mert annyira tele lesz majd apró magokkal (amiknek egy szálon hurka a teljesítményük, ha meg kifejezetten "throughput optimized multicore" tömbként nézzük, arra már most ott van az IGP).
És egy láma kérdés. Nem lehet az x86 memóriamodelljét "kiegészíteni"? A visszafelé kompatibilitás megtartásával. Akár úgy, hogy a régi modell utána már csak "legacy-ben" lenne elérhető?
Még valami: [link], [link] Már régóta semmi nem történik ott, de azért úgy évente ránézek nosztalgiából, hátha... Mi a véleményed, mennyire lenne-lehetne jó ez a cucc a jelenlegiekhez (x86, ARM és társai) képest?
-
Abu85
HÁZIGAZDA
Igen, az Itanium memóriamodellje tényleg szépen ki volt gyúrva a skálázhatóságra. De az x86-tól sokat nem lehet elvárni. Amikor tervezték, akkor szó sem volt róla, hogy egynél több mag lesz a lapkákban. Ennek következtében nem is merült fel a skálázhatóság mint igény. Akármelyik ISA-val így jártunk volna.
Az ARM egy kicsit más tészta szerintem. Az új ISA-val nekik tényleg megvan a lehetőségük jól skálázható alapot csinálni a megfelelő CCI interfésszel, de ők nem úgy gondolkodnak, mint az Intel, hogy CPU kell mindenhova, mert nekik eleve nem olyan kritikus hozzáláncolni egy piacot az ARMv8 ISA-hoz. A piac hozzáláncolja magát lényegi alternatíva hiányában. Ez megadja az ARM-nak a lehetőséget, hogy modernebb konstrukciókban is gondolkodjanak, amire már gyúrják is ki a következő Mali-t.
Új hozzászólás Aktív témák
Hirdetés
- 134 - Lenovo Legion Pro 7 (16IRX8H) - Intel Core i9-13900HX, RTX 4090
- Felújított számítógépek/merevlemezek Számlával, garanciával! Ingyen Foxpost!
- Telefon felvásárlás!! iPhone 12 Mini/iPhone 12/iPhone 12 Pro/iPhone 12 Pro Max
- Bomba ár! HP Elitebook 8570W - i7-QM I 16GB I 750GB I 15,6" HD+/FHD I Nvidia I W10 I Garancia
- Bomba ár! Dell Latitude E7250 - i5-5GEN I 8GB I 256SSD I 12,5" HD I HDMI I Cam I W10 I Garancia!
Állásajánlatok
Cég: Promenade Publishing House Kft.
Város: Budapest
Cég: PCMENTOR SZERVIZ KFT.
Város: Budapest