hmm: Prüfungsforbereitung: von Neumann Architektur

Hi Leute,

ich muss mich auf eine Prüfung vorbereiten die u.a. die Themen mit einschließt:

  1. Basic principles of the von Neumann Architecture for sequential processors

  2. Memory Hierarchy and Cache

  3. Working cycle with compiled languages

Jeden dieser Punkte müsste ich etwas erläutern können, leider hilft mir das Skript an dieser stelle kaum weiter.

Bei der von Neumannarchitektur habe ich ein CPU das aus einem ALU, Register und Cache besteht, außerdem habe ich ein Bussystem, ein Ein- und Ausgabewerk und ein Speicherwerk.

Eingabe -> das Steuerwerk im CPU packt diese in den Speicher und sorgt dafür, dass ein entsprechendes Programm aus dem Speicherwerk mit der Eingabe ausgeführt wird -> im Anschluss wird die Ausgabe an das Ausgabewerk weitergeleitet... für was sind Register und Cache da? passt diese Beschreibung als Antwort auf nr. 1 oder geht es besser?

was muss ich für 2. und 3. wissen? ich hab da nur ein fotos von einer "Modern CPU" im Skript wo mehrere Core, ein Shared L3 Cache, ein Memory Controller und ein "Queue, Uncore & I/O" eingetragen ist.

akzeptierte Antworten

  1. Lieber hmm,

    du wirst hier kein prüfungsfestes Essay über diese Themen erwarten können. Das ist zu viel Arbeit.

    Zur von Neumann-Architektur findest Du z.B. auch einen guten Artikel in der Wikipedia - Kernpunkte der Neumann-Architektor sind die Idee, Daten und Programm im gleichen Speicher zu halten und der von Neumann-Zyklus: Befehl aus der Adresse lesen auf die der Befehlszähler zeigt, Befehlszähler um Befehlslänge erhöhen, Befehl ausführen (und dabei ggf. den Befehlszähler modifizieren = Sprungbefehl), nächster Zyklus

    Der Prozessor hat als Grundbausteine das Steuerwerk, das den von Neumann-Zyklus abarbeitet, und die ALU, die für die Rechenoperationen zuständig ist. Das Ganze ist gekoppelt per Adress- und Datenbus mit dem "Speicherwerk" - also dem RAM mit ggf. vorgelagertem Cache, und dem Ein-/Ausgabewerk, das für die Kommunikation mit der Peripherie zuständig ist. In einem PC könnte man den USB-Bus, die PCIe-Slots oder die SATA Konnektoren zum Ein-/Ausgabewerk zählen.

    Register sind in der CPU meistens zu finden, sind aber eigentlich eine Sonderform von Cache. Man braucht sie nicht zwingend (z.B. mein TI-99 von 1983 hatte keine Register), es ist nur arg lahm, wenn man für jeden Operanden aus dem Speicher lesen und das Ergebnis wieder dorthin schreiben muss.

    Die Befehlsausführung besteht ebenfalls aus mehreren Schritten - die nicht alle stattfinden müssen.

    • Operanden aus Speicher lesen
    • Operanden an ALU übermitteln (aus Speicher oder Registern)
    • Operation ausführen
    • Ergebnis speichern (in Register oder im Speicher)

    Alte Prozessoren konnten nur zwichen Speicher und Register übertragen und die ALU nur mit Registerwerten bestücken, neuere können auch direkt zwischen Speicher und ALU übertragen. Oft ist es aber so, dass nur ein Operand im Speicher liegen kann und der andere ein Register sein muss.

    Die Konkurrenz zwischen Befehlszyklus und Datenausführung führt zum "von Neumann Flaschenhals": die beiden Aktivitäten stören sich gegenseitig beim Speicherzugriff.

    Um das zu lösen, gibt's die Memory-Hierarchie: ganz unten der riesige RAM, dann immer kleiner und schneller werdende Caches. Die Caches, die der CPU am nächsten sind, können ggf. auch die von Neumann-Architektur verlassen (d.h. es gibt getrennte Caches für Daten und Befehle). Wie Caches arbeiten und welche Strategien es gibt, die benötigten Daten möglichst effizient bereitzustellen, dazu kann man Bücher schreiben. Wenn Du keins hast: Wikipedia, Stichwort Cache.

    Der dritte Punkt ist dann etwas ganz anderes - glaube ich 😀. Wer mit einer Compilersprache programmiert, ist in einem bestimmten Arbeitszyklus unterwegs, der prinzipiell aus Editieren - Übersetzen - Ausführen besteht. Editieren ist klar - du bearbeitest den Quellcode und speicherst ihn ab. Übersetzen besteht aus den Teilschritten Compilieren und Linken; wie das genau aussieht, hängt von der verwendeten Entwicklungsumgebung ab. Im einfachsten Fall passiert alles in einem Schritt (Turbo-Pascal), im komplexen Fall hast Du einen oder mehrere Pre-Compiler, den eigentlichen Sprach-Compiler, Object-Linker und Executable-Linker. Wenn Du nur ein Stichwort dazu abgeben musst, reicht der Hinweis auf die Trennung Compiler und Linker. Der Compiler erzeugt aus einem Quellcode-Modul ein Objekt-Modul, der Linker setzt alle Objekt-Module zum ausführbaren Programm zusammen.

    Die Ausführung trennt sich in Laden und Starten - Laden bedeutet, die ausführbare Datei in den Speicher zu holen und dann die Adressverweise zu korrigieren (Relocating). Grund dafür ist, dass der Linker nicht weiß, wohin das Betriebssystem das Programm laden wird. Er speichert daher nur "das 4711-te Byte ab Programmanfang" und trägt in einer Tabelle ein, dass an der Stelle X im Programm ein solcher Verweis zu finden ist. Der Lader geht diese Tabelle durch, er weiß, dass das Programm an Adresse 10000 im Speicher liegt, und macht deshalb aus der 4711 die 14711. Danach kann die Programmausführung an der vom Linker definierten Startadresse begonnen werden.

    Das Ganze wird verkompliziert durch dynamische Ladebibliotheken (DLLs), die dazu führen, dass ein Teil der Linker-Arbeit vom Lader übernommen werden muss.

    Ein Entwickler, der in seinem Programm Fehler sucht, wird von diesem Zyklus arg gestresst. IDEs versuchen daher, zumindest in der DEBUG-Phase diese Schritte zu verkürzen, auf Kosten der Ausführungseffizienz (die man beim Debuggen auch nicht braucht). Das geht dann bis hin zum Edit-And-Continue, wo auf Statement-Ebene compiliert wird und dadurch während des Debuggens der Code geändert werden kann. Das fühlt sich dann an, als würde man mit einer Interpretersprache arbeiten.

    Rolf

    1. hamma! danke für die antworten ich denke das reicht für die prüfung! eventuell stell ich in ein paar tagen noch eine rückfrage