Multithreading, volatile, Cache usw.



  • hustbaer schrieb:

    Ich kenne keinen der "tatsache. ist ja ein ding." im Ernst sagt (und erst recht nicht schreibt)

    Doch, mich. 😉



  • Dann hab ich es falsch verstanden, bitte um Verzeihung!



  • Aber warum ist das schneller?

    Warum funktioniert es nicht mit einem Cache an den x-Prozessoren angeschlossen sind?
    Klar, weil man die dann gegeneinander Synchronisieren muss, aber das kann doch nicht unmöglich sein, dass das nur dann passiert, wenn die auf die gleichen Speicherbereiche zugreifen.

    "Tatsache. Ist ja ein Ding." sollte wirklich nicht schnippisch oder so gemeint sein. Ich wollte einfach nur ausdrücken, dass ich gegoogelt habe, das gefunden habe und es mich überrascht hat.

    jenz



  • Weil der Cache der Grund ist, warum Prozessoren überhaupt noch so schnell sein können. Da RAM-Zugriffe so langsam sind, brauchen die Prozessoren einen kleinen Speicherbereich in dem sie Werte zwischenspeichern können, die bald wieder gebraucht werden.

    Der Fall, dass zwei Prozessoren auf den selben Daten arbeiten ist nicht der Normalfall. Eher ist das so, dass einfach unterschiedliche Software auf unterschiedlichen Kernen mit unterschiedlichen Daten werkelt.

    Wenn die sich jetzt aber den Cache teilen, überschreiben sie sich ständig gegenseitig den Cache-Inhalt (der L1-Cache ist ziemlich klein, also werden bereits durch eine Anwendung alleine permanent Daten rein geladen oder raus geworfen). Womit der Nutzen eines Cache ziemlich exakt 0 ist.



  • EDIT: Blödsinn.



  • man müsste den cache natürlich ein bisschen anpassen.
    zum beispiel

    a) cachegröße = x-prozessoren*normale cachegröße
    b) jeder prozessor darf nur maximal normale cachegröße (+vielleicht etwas mehr) an daten im cache haben

    man hätte also einen gemeinsamen größeren cache der von x-prozessoren gleichzeitig genutzt wird der nie komplett von einem prozessor benutzt wird.

    was spricht dagegen?



  • Was spricht denn dafür, wenn für einen Kern kein Mehrwert entsteht? Du hast dann lediglich längere Leitungen vom Kern zum Cache, aber keinen Vorteil.

    Wenn jeder Kern etwas mehr im gemeinsamen Cache benutzen darf, musst du wieder eine Verwaltung einführen, die sich merkt, welcher Bereich von welchem Kern benutzt wird. Dafür geht dann wieder Speicher und vor allem Zeit drauf. Das ist natürlich kein Ding der Unmöglichkeit (der L3-Cache ist ja ein gemeinsam verwendeter Cache), aber es ist schneller, wenn jeder Kern erstmal seinen eigenen Cache nur für sich alleine hat.



  • der mehrwert wäre, dass man den cache nie an die anderen prozessoren mitteilen muss. diese zeit würde man also sparen.

    okay, wenn man mehr als nur seinen xten teil nutzen können soll, dann wird die verwaltung aufwendiger. dann sollte man den cache doch besser in gleiche teile aufteilen auf denen immer nur ein prozessor die hoheit hat.

    jenz



  • jenz schrieb:

    der mehrwert wäre, dass man den cache nie an die anderen prozessoren mitteilen muss. diese zeit würde man also sparen.

    Würde man nicht. Angenommen du hast eine Variable x. Kern 1 benutzt x in seinem Cacheteil C1, Kern 2 benutzt x in seinem Cacheteil C2. Wenn Kern 1 den Wert von x in C1 verändert, bekommt Kern 2 das nicht mit, weil in C2 nichts geändert wird. Du müsstest also die entsprechenden Speicherstellen in C1 und C2 miteinander verschränken, d.h. synchronisieren. Die Alternative wäre, dass es für jede gemeinsam verwendete Variable eine Lookup-Tabelle gibt, die für jeden Kern die Speicherstelle in seinem jeweiligen Cacheteil angibt. Dann müsste jeder Kern jede Speicherstelle aus der Lookup-Tabelle aktualisieren. Dabei musst du dann wieder sicherstellen, dass keine zwei Kerne das gleichzeitig machen etc.

    Edit: Edit weggemacht.



  • ich stelle mir das so vor:
    lesen/schreiben darf jeder prozessor auf den ganzen cache

    ein- und auslagern darf immer nur der prozessor mit "hoheit" für den cachebereich

    dann braucht man nichts verschränken.

    könnte sogar die cachehits verbessern



  • So, hab mich jetzt selbst mal ein bisschen informiert. Bei der Verknüpfung der Byteadressen mit ihrer Bedeutung dürfte es tatsächlich keine Probleme geben, weil sich darum die MMU kümmert. Dafür ist bei Shared Caches die Latenz viel größer. Siehe z.B. http://people.engr.ncsu.edu/efg/506/s01/lectures/notes/lec16.html oder http://realworldtech.com/page.cfm?ArticleID=RWT101405234615&p=2



  • Ah, danke.

    Du meinst das hier:
    Latency. Switch logic will now need to be interposed between the processor and the cache, adding latency to each reference.
    Oder?

    Das verstehe ich so, dass immer nur ein Prozessor mit dem Cache "verbunden" ist.
    Man könnte doch auch einfach x-Leitungen legen und jeder Prozessor kann einfach zugreifen.
    Das würde auch gleich das "Bandwidth"-Problem lösen.

    Das hier
    "Destructive interference—the converse of overlapping working sets"
    haben wir ja schon gelöst 😉

    Wahrscheinlich scheitert es dann aber an den ganzen Leitungen und dem verfügbaren Platz und der nötigen Länge der Leitung, wodurch es dann wieder langsamer wird.



  • Es gibt viele Cachearten, aber der große Vorteil ist der konstante Speicherzugriff auf den Cache. Manche Caches lösen lediglich den virtuellen Adressraum zur physikalischen Adresse auf (z.B Software: Paging des Betriebsystems), andere speichern Daten (z.B Hardwarecache). Deine Idee, den Cache zu sharen bringt einfach das Problem mit sich, dass der Zugriff auf gecachte Daten synchronisiert werden muss und länger braucht. Der besteht aus sehr vielen gleichen E-Schaltkreisen die echt-parallel zum Ergebnis kommen: "Hier ist der Wert" bzw. "Keiner hat den Wert". worst-case, eine echte RAM Anfrage, die je nach RAM-Timings (wobei man hier nicht 1:1 die Timings auswerten kann) 10 oder mehr Zyklen braucht. Und selbst da darf man nicht zu naiv werden. Auf primitiver Assemblerebene ist die Nebenläufigkeit von so vielen Anweisungen so hoch, dass eine RAM Anfrage geschickt wird und dann wird i=5*3, m=999/34 oder sonst was ausgeführt und irgendwann kommt der erfolgreiche Fetch. Schau dir mal eine Pipeline an. Was der L1,2,3 Cache macht (inklusiv vs. exklusiv). Was direkte Abbildung, assoziativ und mengenassoziativ bedeutet. Caches halten ihre Daten nach Hit-Rates etc. es ist verdammt gut optimiert!

    Ich denke dass die Halbleiterindustrie sich täglich etliche Male den Kopf zerbrochen und nachgemessen hat und so ist es am schnellsten. Und wenn du meist, dass sich da noch was rausholen lässt, dann schau die Mal virtuelle Speicheradressen und Paging an. Das ist alles auf OS-Ebene fern von Hardware und es wird geschaut, wie optimiert wird.



  • PhilippHToner schrieb:

    Deine Idee, den Cache zu sharen bringt einfach das Problem mit sich, dass der Zugriff auf gecachte Daten synchronisiert werden muss und länger braucht.

    was genau muss sychronisiert werden?
    bzw. wieso muss das vom cache synchronisiert werden?

    wenn auf gleiche daten zugegriffen werden soll, dann muss das doch von der software synchronisiert werden.



  • jenz schrieb:

    Man könnte doch auch einfach x-Leitungen legen und jeder Prozessor kann einfach zugreifen.

    🤡 🤡 🤡 🤡 🤡 🤡 🤡 🤡 🤡 🤡

    Man betone "einfach". Also sei ma ned böse, aber du hast ja mal gar keine Vorstellung von dem Inhalt einer CPU, geschweige denn, wass das Ding in kürzester Zeit verrichtet! Lass das Thema lieber bevor, du dich hier mehr blamierst!



  • naja, es geht nur um speicher bzw. cache zugriff.

    klar kann x nicht beliebig groß werden.
    aber x = 4 sollte das doch machbar sein.

    und ich glaube, ich habe mehr ahnung als du vermutest.

    vermutungen müssen wir aber nicht anstellen, ich will das doch nur mal durchdiskutieren und verstehen, wo die grenzen liegen bzw. wo die grenzen herkommen.



  • jenz schrieb:

    PhilippHToner schrieb:

    Deine Idee, den Cache zu sharen bringt einfach das Problem mit sich, dass der Zugriff auf gecachte Daten synchronisiert werden muss und länger braucht.

    was genau muss sychronisiert werden?
    bzw. wieso muss das vom cache synchronisiert werden?

    wenn auf gleiche daten zugegriffen werden soll, dann muss das doch von der software synchronisiert werden.

    Stell Dir das so vor. Im Gegensatz zu Intel und AMD sind wird kleine Sesselfurzer, die einfach coden. Wir machen uns nicht über alles Sachen Gedanken, die Architektur spezifisch sind.

    Hier ein MUsterbeispiel, dass 100000000 läuft und einmal abstürzt mit Pseudecode

    RAM g = 0 // befindet sich im RAM
    
    Thread A führt Block A aus
    Thread B führt Block B aus
    
    Block A
    Warte 10 Sekunden
    g = 5
    Blockende
    
    Block B
    Warte 20 Sekunden
    
    // Was für Wert ist in g?
    
    Blockende
    

    Schau die den Code an. Ich synchronisiere hier über die Zeit, aber was ist, wenn g noch im Cache ist und das g im RAM noch wie vor 0 ist!?!?!

    Deshalb Synchronisierungsverfahren, die die Cores dazu bewegt ihren Abgleich bzgl. RAM durchzuführen!
    DIe besten Sync-Verfahren dich ich gesehen habe war sowas wie:

    if(millisecs % Threadanzahl == threadid)
    // dann darf ich was machen
    endif;

    😃 NEVER!



  • PhilippHToner schrieb:

    Im Gegensatz zu Intel und AMD sind wird kleine Sesselfurzer, die einfach coden. Wir machen uns nicht über alles Sachen Gedanken, die Architektur spezifisch sind.

    Trotzdem wird man sich doch wohl mal Gedanken dazu machen dürfen, oder?

    Dein anschließendes Beispiel hat nichts mit Shared Caches zu tun.



  • jenz schrieb:

    was genau muss sychronisiert werden?
    bzw. wieso muss das vom cache synchronisiert werden?

    Ja weil du noch Register hast!
    Register <-> Cache <-> RAM

    Prozessor P1 holt sich aus dem gemeinsamen Cache die Daten D1 in Register R1.
    Prozessor P1 rechnet: R1 = R1 + R1
    Prozessor P2 holt sich aus dem gemeinsamen Cache die Daten D1, die eigentlich D1 = R1 entsprechen müssten, tun sie aber nicht, weil im Register von P1.

    Wenn du in c++ im selben Thread mit der selben Variable rechnest bekommst du versprochen, dass du mit dem richtigen Wert arbeitest. Dir wird doch ständig verschleiert woher deine Daten kommen. Es kann (unwahrscheinlich, aber theoretisch) sein, dass dein "int i" auf der Festplatte flackt! Weil du es nie gebraucht hast und dein RAM so zugemüllt ist, dass das OS i einfach auf die Festplatte gespeichert hat. Es ist jetzt sehr übertrieben, aber überleg mal, was wir eigentlich für ein gechilltes Leben haben! Das OS supported uns und die CPU supported das OS.



  • Michael E. schrieb:

    PhilippHToner schrieb:

    Im Gegensatz zu Intel und AMD sind wird kleine Sesselfurzer, die einfach coden. Wir machen uns nicht über alles Sachen Gedanken, die Architektur spezifisch sind.

    Trotzdem wird man sich doch wohl mal Gedanken dazu machen dürfen, oder?

    Dein anschließendes Beispiel hat nichts mit Shared Caches zu tun.

    Klar kann man sich Gedanken machen, aber es haben jetzt 100 Leute gesagt, dass auf der low-low-low-Levelebene nicht mehr synchronisiert werden soll, weil das der Flaschenhals wird! Schaut Euch eure Programm an. Die meisten Aufgaben sind so beschränkt auf ein paar Daten. Und deshalb die Aufteilung in zeitliche Lokalität und räumliche Lokalität. Wenn ich schon länger etwas nicht mehr brauche, dann sinkt mit zunehmender Zeit, dass ich es wieder brauche (HitRates). Beim Abarbeiten entsteht die zeitliche Lokalität und beim allokieren meistens die räumliche Lokalität. Es ist aber theoretisch möglich, dass der Cache kein bisschen Zeit einspart, aber diesem Problem versucht auch der Compiler vorzubeugen und schiebt ähnliche Sachen zusammen!

    Speicher allgemein muss bei einem Zugriff von mehreren Parteien mit den erforderlichen Maßnahmen synchronisiert werden! Es ist Wurst ob über das Netzwerk eine Datei geöffnet geändert und gespeichert wird, ob im Arbeitsspeicher, im Cache oder bei den Registern! Macht Euch einfach Gedanken wie ihr gewährleistet, dass der Programmierer, wenn er mit int i arbeitet immer sein richtiges i hat, auch wenn es nach China gepaged wurde, weil Deutschland keinen Speicherplatz mehr hat. Es gibt nur eine Hand voll atomarer Codepassagen (locken und unlocken von threadsync) und der Rest ist nie atomar: ++i auch nicht!!!!


Anmelden zum Antworten