Wie macht man dem Speicher Beine?
Ich denke es ist mal wieder an der Zeit einen Nicht-Raumfahrtblog einzuschieben. Im Prinzip ist das was ich schreibe nichts Neues, steht sogar viel ausführlicher auf der Webseite, doch ich weiß auch das es nicht jeder gerne lange Aufsätze liest. Warum geht es? Es ist das Problem das der Speicher bei Computern zu langsam ist, und es schon immer war.
Das Problem entsteht eigentlich dadurch, dass Speicher billig sein muss. Die größten CPUs und GPUs haben über 1 Milliarde Transistoren entsprechend liegen solche Grafikkarten und CPU im hohen dreistelligen Euro-Bereich. Würde man pro Transistor ein Bit speichern, dann würde das für gerade mal 128 MByte Speicher reichen, der nur einige Euro kostet.
Speicher musste also billig sein. Der erste Speicher war sogar mechanisch. Schallwellen in Quecksilber wurden als Speichermedium genutzt, später magnetisch beschichtete Trommeln. Das war schon langsam gegenüber Röhrenrechnern. Für zwei Jahrzehnte war der Standardspeicher der Ringkernspeicher, bei dem kleine Eisenringe magnetisiert wurden. Auch Ringkernspeicher war immer langsamer als die Logik, auch wenn die Zugriffszeit von Millisekunden der mechanischen Speicher auf Millisekunden fiel. Ende der Sechziger Jahre war die Technologie soweit, das man signifikante Datenmengen auf IC speichern konnte. Damit eröffnete sich das Potenzial, das der Speicher genauso schnell ist wie die Logik. Doch es kam nicht so. Es gab zwei Gründe. Das eine war, das wenn man ein Bit so speichert wie im Prozessor, man 4 Transistoren braucht. Könnte man die Zahl reduzieren so bekommt man mehr Bits pro Speicherchip. Das zweite war das eine neue Technologie versprach den Platzbedarf pro Transistor zu reduzieren. Das zweite war der Übergang von der Bipolar auf die noch heute verbreitete MOS-Feldeffekt Technologie. Aus Bipolar-Transistoren, bzw. dessen Abkömmling ECL basierte die Logik der Computer. Sie schaltete schnell, da ein Transistor nie den Sättigungszustand erreichte, verbrauchte aber viel Energie und damit war ein Transistor auch recht groß. Die MOS-FET versprach viermal kleinere Strukturen, aber schaltete viel langsamer als Bipolar-Technologie. Intels erster Speicherchip hatte 64 Bit in Bipolartechnologie, der zweite 256 Bit in MOS-FET. Er war trotz vierfacher Kapazität billiger.
Das zweite war das man einen Weg fand, ein Bit in nur einem Kondensator zu speichern und man nur einen Transistor als Auslasstor brauchte, anstatt vier bei der Verwendung eines Flip-Flops die man in der CPU nützte, um Bits zu speichern. Das DRAM war dann nochmals viermal billiger pro Bit.
Damit war RAM aber wieder langsam. Die ersten D-RAMS die Anfang der Siebziger Jahre auf den Markt kamen, hatten Zugriffszeiten von 250 bis 300 ns. Die Zugriffszeit ist die Zeit, die ein Speicher braucht, bis er nach einer Anforderung durch die CPU die Daten herausrückt. Es gibt dann noch die Zykluszeit – meistens kann man nach dem Zugriff nicht sofort den nächsten starten, sondern der Speicher muss die Informationen wieder schrieben, da das Auslesen sie vernichtet. (Heute wird das ganze noch granulärer angegeben wie Zugriffszeit pro Reihe/Spalte etc.)
Als einfacher Richtwert kann gelten: Braucht eine CPU einen Takt für einen Zugriff, so beträgt die maximale Taktfrequenz ohne das sie auf Daten warten muss, den Kehrwert der Zugriffszeit, bei 250 ns also 4 MHz. 10 Jahre später hatte sich die Zugriffszeit verdoppelt, zwanzig Jahre später nochmals verdoppelt. Im gleichen Zeitraum hatten sich bei Prozessoren die Taktfrequenzen aber um den Faktor 20 erhöht und anstatt 4 Takten für einen Speicherzugriff brauchte der Prozessor nur noch einen. Speicher wurde also immer langsamer, verglichen mit dem Prozessor. Das ist bis heute so.
Schon früher hat man also nach Wegen gesucht, die Langsamkeit zu Kaschieren. Alle Versuche basieren auf einer Tatsache: sowohl Computercode, wie auch Daten sind sehr lokal. Sprich: braucht man den Wert einer Speicherzelle so ist es sehr wahrscheinlich, das der nächste Zugriff auf die nächste Speicherzelle geht, weil Code linear ausgeführt wird und Variablen hintereinander im Speicher stehen.
Die erste Lösung ist es, einen schnellen Speicher lokal verfügbar zu halten. Die einfachste Lösung war ein Befehlspuffer, der die nächsten und letzten Befehle speicherte. So was hatten viele Großcomputer in den Sechzigern. Er bestand aus schnellem Speicher und die Logik war oft sehr einfach – es flogen immer die Daten raus dem Buffer die am weisesten von der aktuellen Position des Befehlszeigers entfernt waren. Dafür musste der Prozessor vorausschauen lesen, im Fachjargon Prefetch. In der x86-Linie wurde das schon beim 8086 eingeführt.
Für Daten, die ja auch abgespeichert werden müssen, war die Lösung es viele Register einzusetzen. Ein Compiler konnte so möglichst viele Register für das Programm nutzen und die Speicherzugriffe minimieren. Das gipfelte schließlich in Vektorregistern, die 64 bis 1024 Zahlen aufnahmen. Bei Intel ist das in der AVX/SSD Technologie implementiert. Anstatt die Zahl der Register zu vergrößern fassen die dafür bis zu 512 Bit, was bis zu 16 einfach genauen Zahlen entspricht.
Die zweite Möglichkeit einen lokalen Speicher einzusetzen ist der Cache. Es ist ein kleiner Speicher der in einzelne Bereiche, Cachelines unterteilt ist. Eine Logik speichert immer die zuletzt gebrauchten Daten im Cache. Es gibt mehrere Technologien der Verwaltung. Das Problem ist, das das Verwalten des Caches auch Zeit benötigt, z.b. zum Durchsuchen. Das darf nicht zu lange dauern. Heute haben alle größeren Prozessoren Caches, meist sogar mehrere gestufte, z. B. einen kleinen, schnellen und einen größeren langsameren.
Die zweite Möglichkeit ist es Langsamkeit durch Bandbreite zu ersetzen. Ein Prozessor der nur 32 Bit verarbeitet, ruft z. B. 256 Bit vom Speicher ab. Das sind dann die nächsten 8 Speicherzellen. Die hat er dann schon und muss sie nicht abrufen. Mit großer Bandbreite arbeiten heute Grafikkarten, früher Großrechner. Bei austauschbaren Modulen bekommt man meist die vielen Leistungen dafür nicht unter. So arbeitet DDR-RAM nur mit 64 Bit.
Die dritte Möglichkeit ist das vorausschauende Lesen. Wenn man weiß, das man die nächsten Daten bald braucht, dann kann der Speicher intern sie schon mal auslesen und in einen schnellen Zwischenspeicher ablegen. So arbeiteten viele Speicherbänke für Großcomputer, die mindestens das nächste Wort so voraussehend lasen. Eine Variation des Prinzips ist DDR-RAM. Hier überträgt das RAM automatisch die nächsten 64 Bit bei dem nächsten Flankenwechsel, insgesamt 8-mal, das ist angepasst an die 64 Byte großen Cacheslines heutiger Prozessoren. Nur für diesen Modus gilt die Datenübertragungsrate, die ausgewiesen ist.
Bei heutigen Rechnern unüblich, aber früher bei Großrechnern verbreitet, war das verteilte Lesen. Ein heutiger PC kommt mit einem Speichermodul aus, bis zu vier passen in normale PC-Boards. Bei Servern sind es mehr. Dabei geht jeweils ein Zugriff auf die erste Bank, der nächste auf die zweite usw. Zwischen den Zugriffen kann die Bank sich erholen (Zykluszeit > Zugriffszeit) und sie kann auch vorausschauend lesen. Die Technik ist nützlich, wenn eine hohe Linearität vorliegt. Bei Supercomputern von Cray die große Arrays verarbeiteten, war dies gegeben. Diese hatten bis zu 256 Speicherbänke. Bei einem PC liegt dagegen der Geschwindigkeitsvorteil dagegen im einstelligen Prozentbereich.
Insgesamt ist die Technik die ja heute kombiniert eingesetzt wird, sehr erfolgreich. Seit etwa 15 Jahren ist die Zugriffszeit von Speicherbausteinen kaum gesunken. Sie liegt heute bei 7 bis 10 ns, was für Taktzyklen von 100 bis 150 MHz, nicht aber viele GHz ausreicht. Durch Caches und vorausschauendes Lesen merkt man davon fast nie etwas. Findet am die Information aber nicht im Cache so kann es sogar noch länger dauern als die Zugriffszeit des Rams beträgt. Die typische Latenz eines Speichers beträgt heute 80 bis 100 ns. Das ist 10-mal langsamer als der Speicher selbst. Das Problem: Auch wenn man nur ein Byte braucht, werden 64 Byte in 8 Zyklen über DDR-RAM gelesen. Dann wandert die Information durch die Caches, die ebenfalls Verzögerungen haben bis zu 40 Takte beim L3-Cache. Wer programmieren kann, kann sich mal an folgendem versuchen:
- Dimensionieren Sie ein Array das signifikant größer als die Caches des Prozessors ist, aber noch deutlich kleiner als der Arbeitsspeicher des Computers, bei 4 GB Arbeitsspeicher z. B. 1 GByte groß.
- Füllen Sie es mit Werten. Nun rufen sie die Werte ab:
- a.) einmal sequentiell
- b.) einmal indem der Index per Zufallszahl ausgewählt wird. (vorher für den Vergleich bestimmen wie lange das Ziehen der Zufallszahl dauert und den Wert später abziehen.).
- Stoppen sie jeweils die Zeit.
Bei der zweiten Methode werden Caches ausgetrickst, die Geschwindigkeit kann um den Faktor 100 einbrechen.
Wenn man es so betrachten will, ist Speicher auch heute noch teilweise magnetisch: Dann nämlich, wenn nach Registern, Cache und RAM die nächstgrößere und nächstlangsamere Stufe des Speicherns erreicht wird, beim Auslagern auf die Festplatte (so es denn keine SSD ist).
Das aktuelle Thema gefällt mir übrigens nicht besonders, ich finde es etwas zu verspielt. Noch ist mein Favorit das Ursprüngliche, gefolgt von dem ersten Neuen, das Du ausprobiert hattest.
Mir gefällt das aktuelle Thema auch nicht.
Das ursprüngliche war ebenfalls mein Favorit.
Lud schnell, auch bei schlechter Mobilfunk Anbindung.
Auf dem aktuellen Thema kann ich auch keine Artikel öffnen.
Android mit Chrome Browser.
Bin jetzt den Umweg unten über „letzte Kommentare“ gegangen.
Auch mir gefällt das Original am besten