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