Wenn in Umgebungen mit gemeinsam genutztem Speicher (z. B. Threading über OpenMP, Pthreads oder TBB) Berechnungen mit begrenzter Speicherbandbreite durchgeführt werden, besteht ein Dilemma dahingehend, wie sichergestellt werden kann, dass der Speicher korrekt auf den physischen Speicher verteilt wird, sodass jeder Thread hauptsächlich auf einen Speicher zugreift "lokaler" Speicherbus. Obwohl die Schnittstellen nicht portabel sind, haben die meisten Betriebssysteme Möglichkeiten, die Thread-Affinität festzulegen (z. B. pthread_setaffinity_np()
auf vielen POSIX-Systemen, sched_setaffinity()
unter Linux, SetThreadAffinityMask()
unter Windows). Es gibt auch Bibliotheken wie hwloc zum Bestimmen der Speicherhierarchie, aber leider bieten die meisten Betriebssysteme noch keine Möglichkeiten zum Festlegen von NUMA-Speicherrichtlinien. Linux ist mit libnuma eine bemerkenswerte AusnahmeErmöglichen, dass die Anwendung die Speicherrichtlinie und die Seitenmigration mit der Seitengranularität manipuliert (seit 2004 in der Hauptzeile, daher weit verbreitet). Andere Betriebssysteme erwarten, dass Benutzer eine implizite "First Touch" -Richtlinie einhalten.
Das Arbeiten mit einer "First Touch" -Richtlinie bedeutet, dass der Aufrufer Threads mit der Affinität erstellen und verteilen soll, die er später beim ersten Schreiben in den neu zugewiesenen Speicher verwenden möchte. (Nur sehr wenige Systeme sind so konfiguriert, dass sie malloc()
tatsächlich Seiten finden. Es wird lediglich versprochen, sie zu finden, wenn sie tatsächlich fehlerhaft sind, möglicherweise durch verschiedene Threads.) Dies impliziert, dass die Zuweisung mit calloc()
oder die sofortige Initialisierung des Speichers nach der Zuweisung mit memset()
schädlich ist, da dies zu Fehlern führen kann Der gesamte Speicher auf dem Speicherbus des Kerns, auf dem der Zuordnungsthread ausgeführt wird, führt zu einer Speicherbandbreite im ungünstigsten Fall, wenn auf den Speicher von mehreren Threads aus zugegriffen wird. Gleiches gilt für den C ++ - new
Operator, der darauf besteht, viele neue Zuordnungen zu initialisieren (zstd::complex
). Einige Beobachtungen zu dieser Umgebung:
- Die Zuweisung kann als "Thread-Kollektiv" erfolgen, aber die Zuweisung wird nun in das Threading-Modell gemischt, was für Bibliotheken unerwünscht ist, die mit Clients unter Verwendung verschiedener Threading-Modelle interagieren müssen (möglicherweise mit jeweils eigenen Thread-Pools).
- RAII wird als wichtiger Bestandteil von idiomatischem C ++ angesehen, scheint jedoch die Speicherleistung in einer NUMA-Umgebung aktiv zu beeinträchtigen. Die Platzierung
new
kann mit dem übermalloc()
oder von zugewiesenen Speicher verwendet werdenlibnuma
, dies ändert jedoch den Zuweisungsprozess (was ich für notwendig halte). - BEARBEITEN: Meine frühere Aussage zum Operator
new
war falsch, er kann mehrere Argumente unterstützen, siehe Chetans Antwort. Ich glaube, es gibt immer noch Bedenken, Bibliotheken oder STL-Container dazu zu bringen, eine bestimmte Affinität zu verwenden. Es können mehrere Felder gepackt sein, und es kann unpraktisch sein, sicherzustellen, dass z. B. einestd::vector
Neuzuweisung mit dem richtigen aktiven Kontextmanager erfolgt. - Jeder Thread kann seinen eigenen privaten Speicher zuordnen und fehlerhaft behandeln, aber dann ist die Indizierung in benachbarte Regionen komplizierter. (Betrachten Sie ein dünn besetztes Matrixvektorprodukt mit einer Zeilenpartition der Matrix und der Vektoren. Die Indizierung des nicht besetzten Teils von x erfordert eine kompliziertere Datenstruktur, wenn x im virtuellen Speicher nicht zusammenhängend ist.)
Werden Lösungen für die NUMA-Zuweisung / -Initialisierung als idiomatisch betrachtet? Habe ich andere kritische Fallstricke ausgelassen?
(Ich meine nicht, dass meine C ++ - Beispiele eine Betonung dieser Sprache implizieren, jedoch codiert die C ++ - Sprache einige Entscheidungen über die Speicherverwaltung, die eine Sprache wie C nicht enthält. Daher besteht tendenziell ein größerer Widerstand, wenn vorgeschlagen wird, dass C ++ - Programmierer diese ausführen Dinge anders.)