Hallo,
Wenn ich einen Sechs-Core-Prozessor habe, erscheint
dieser im System
als 12 CPUs, in Tools wie htop auch als 12 ganz unabhängige Einheiten.
Tatsächlich sind das aber *sechs* unabhängige Teile, die jeweils zwei
Threads verwalten können, richtig?
Wenn man es hinreichend low-level betrachtet, ja.
Der CPU-Core hat bei HT/SMT den Registersatz und Teile des Steuerwerks
doppelt. Das Rechenwerk und die I/O Leitungen sind aber nur einmal
vorhanden. Im wesentlichen führt HT/SMT dazu, dass der eine Thread rechnen
kann, während der andere auf I/O (RAM bzw. 3rd Level Cache Zugriffe) wartet.
Nicht ganz klar ist mir hier das Verhältnis von
"echten" Cores und
Threads.
Ich stelle mir vor, dass ein Core eine Möglichkeit hat, zwei Prozesse
effizienter zu verwalten als wenn er nicht diese Thread-Unterstützung
hat.
Ja. Dadurch, dass der Registersatz doppelt vorhanden ist, muss bei einem
"Wechsel" müssen bei einem Wechsel zwischen den beiden Threads nicht erst
die Register auf dem Stack gesichert werden, wie das bei einem Multitasking
auf einem System mit nur einem Thread nötig wäre.
Aber *ein* Prozess, der einen Core zu 100% in Beschlag
nimmt,
müsste doch effizienter sein als *zwei* Prozesse, die sich diesen Core
"teilen" und ständig hin- und her wechseln müssen?
Nein. Denn erstens kostet das "Hin und her wechseln" keine Zeit, die CPU
macht das automatisch ohne Zutun des Betriebssystems. Und zweitens warten
die meisten Prozesse zu einem gewissen zeitlichen Anteil auf Zugriffe auf
das RAM bzw. den L3 Cache. In diesen Zeiten ist das Rechenwerk ungenutzt. HT
sorgt dafür, dass dann ein anderer Thread diese Ressource nutzen kann.
Wie viel das tatsächlich bringt, hängt vom Anwendungsfall ab. Das eine
Extrem wäre ein Prozess, der in einem eng begrenztem Adressbereich laufend
FPU Berechnungen ausführt; z.B. das Berechnen von Fraktalen. Dieser lastet
das Rechenwerk zu nahezu 100% aus und wartet selten auf das RAM. Das andere
Extrem ist ein Prozess, der über einen großen Speicherbereich iteriert und
darin keine aufwändigen Operationen macht; z.B. eine Stringsuche in einem
großen Text. Dieser wartet ständig auf RAM-Zugriffe, so dass das Rechenwerk
oft brach liegt.
Prozesse dieser beiden Bauarten lassen sich gut mit HT auf einem Core
kombinieren. In der Realität sind die Workloads nicht so extrem, aber das
Prinzip bleibt das gleiche.
Meine Frage bezieht sich letztlich auf die Aufgabe,
mehrere Compiler-
Prozesse parallel laufen zu lassen. Compiler wollen ja immer die ganze
Rechenleistung haben, je mehr sie davon haben, desto schneller werden
sie fertig (anders als z.B. User Interfaces, wo man sich gerade das
nimmt, was gerade gebraucht wird und dann wartet, bis der Nutzer mal
wieder wo drauf klickt).
Wenn ich also das Beispiel aus meiner anderen Frage nehme und sehr
viele Compiler-Prozesse starten will, dann müsste das doch eigentlich
am allerschnellsten gehen, wenn jeder Compiler-Prozess *eine* Core zu
100% beansprucht. Wenn ich also idealisiert sagen könnte: Starte vier
Compiler und nutze dafür vier Cores, dann sollte das besser sein als:
Starte acht Compiler und nutze die acht Threads von vier Cores.? Mir
ist klar, dass das OS (zumindest von selbst) die Hunderte oder Tausende
Prozesse, mit denen es sonst noch beschäftigt ist, sowohl auf die
verbleibenden zwei Cores verteilt und bestimmt auch noch Zyklen von
"meinen" vier Cores abzweigt.
Ob das so stimmt, hängt von der Programmiersprache und dem verwendeten
Compiler ab. Bei C/C++ und dem GCC ist es typischerweise so, dass es am
schnellsten geht, wenn man die vorhandenen Threads zu ca. 50% überbucht,
d.h. in deinem Fall 12 parallele Tasks startet. Der Grund ist, dass GCC
viele Zwischenergebnisse in temporären Dateien speichert und damit die
einzelnen Tasks zu einem gewissen Grad auf File-I/O warten. Das genaue
Optimum hängt aber von sehr vielen Parametern ab, wie dem genutzten
Datenspeicher, dem vorhandenen RAM, der Geschwindigkeit des RAM-Zugriffs,
der GCC-Version und der verwendeten Optimierungen. Daher hilft letztlich
nur ausprobieren, um den optimalen Wert zu finden.
Andere Compiler (z.B. Java oder Go) arbeiten mit wesentlich weniger File-I/O
und performen daher besser mit weniger Tasks.
Gruß, Harald