Sind Spinlocks eine gute Wahl für einen Speicherzuordner?

8

Ich habe den Betreuern der D-Programmiersprachen-Laufzeit ein paar Mal vorgeschlagen, dass der Speicherzuordner / Speicherbereiniger Spinlocks anstelle von regulären Betriebssystem-kritischen Abschnitten verwenden sollte. Das hat sich nicht wirklich durchgesetzt. Hier sind die Gründe, warum Spinlocks besser wären:

  1. Zumindest in den synthetischen Benchmarks, die ich gemacht habe, ist es einige Male schneller als die kritischen Abschnitte des Betriebssystems, wenn es um den Speicherzuordner / die GC-Sperre geht. Bearbeiten: Empirisch, Spinlocks verwendet hatte nicht einmal messbare Overhead in einer Single-Core-Umgebung, wahrscheinlich, weil Sperren für eine so kurze Zeit in einem Speicherzuordner gehalten werden müssen.
  2. Speicherzuordnungen und ähnliche Operationen benötigen normalerweise nur einen kleinen Bruchteil einer Zeitscheibe und sogar einen kleinen Bruchteil der Zeit, die ein Kontextwechsel benötigt, wodurch es im Falle einer Konkurrenz zum Kontextwechsel albern wird.
  3. Eine Garbage Collection in der fraglichen Implementierung stoppt die Welt irgendwie. Während einer Sammlung dreht sich nichts.

Gibt es irgendwelche guten Gründe, nicht Spinlocks in einer Speicherzuordner / Garbage-Collector-Implementierung zu verwenden?

    
dsimcha 15.12.2009, 21:46
quelle

6 Antworten

2

Unter Windows haben kritische Objektbereiche bereits die Möglichkeit, dies zu tun ( Ссылка ) :

  

Ein Thread verwendet die Funktion InitializeCriticalSectionAndSpinCount oder SetCriticalSectionSpinCount, um eine Anzahl von Drehungen für das Objekt des kritischen Abschnitts anzugeben. Drehen bedeutet, dass der Thread in eine Schleife wechselt, wenn ein Thread versucht, einen kritischen Abschnitt zu erhalten, der gesperrt ist, und überprüft, ob die Sperre aufgehoben ist. Wenn die Sperre nicht aufgehoben wird, wechselt der Thread in den Ruhezustand. Bei Einzelprozessorsystemen wird die Anzahl der Drehungen ignoriert und die Drehzahl der kritischen Abschnitte wird auf 0 (Null) gesetzt. Wenn der kritische Abschnitt auf Multiprozessorsystemen nicht verfügbar ist, spinnt der aufrufende Thread dwSpinCount-Zeiten, bevor eine Warteoperation für ein Semaphor ausgeführt wird, das dem kritischen Abschnitt zugeordnet ist. Wenn der kritische Abschnitt während der Drehoperation frei wird, vermeidet der aufrufende Thread die Warteoperation.

Hoffentlich werden andere Plattformen folgen, wenn sie es nicht schon tun.

    
Michael Burr 15.12.2009, 21:56
quelle
3
  1. Offensichtlich ist das Worst-Case-Verhalten eines Spinlocks schrecklich (der OS-Scheduler sieht nur 30 CPU-gebundene Threads, also versucht er ihnen alle CPU-Zeit zu geben; 29 von ihnen drehen sich wie verrückt, während der Thread das hält das Schloss schlafen), also sollten Sie sie meiden, wenn Sie können. Viele Leute, die klüger sind als ich, behaupten, Spinlocks hätten no Anwendungsfälle für den Benutzerbereich.

  2. System-Mutexe sollten sich ein wenig drehen, bevor sie den Thread in den Ruhezustand versetzen (oder tatsächlich irgendeinen Systemaufruf machen), so dass sie manchmal genau das gleiche wie Spinlocks ausführen können, selbst wenn es Konflikte gibt.

  3. Ein Zuweiser kann Sperrenkonflikte häufig praktisch eliminieren, indem er die Sperre nur zum Zuweisen von Seiten zu Threads verwendet. Jeder Thread ist dann verantwortlich für die Partitionierung seiner eigenen Seiten. Sie erhalten die Sperre nur einmal für alle N Zuordnungen, und Sie können N so konfigurieren, wie Sie möchten.

Ich halte 2 und 3 für starke Argumente, die mit synthetischen Benchmarks nicht wirksam bekämpft werden können. Sie müssten zeigen, dass die Leistung eines realen Programms leidet.

    
Jason Orendorff 15.12.2009 22:05
quelle
2

Spinlocks sind absolut wertlos auf Systemen mit nur einer CPU / Kern oder - allgemeiner - in Situationen mit hoher Konkurrenz (wenn viele Threads auf die Sperre warten).

    
Vladimir Panteleev 15.12.2009 21:49
quelle
2
  

Gibt es gute Gründe, Spinlocks in einer Speicherzuordner / Garbage-Collector-Implementierung nicht zu verwenden?

Wenn einige Threads compute-bound (CPU-gebunden) sind und andere Threads speicherzuordnergebunden sind, benötigt die Verwendung von Spinlocks CPU-Zyklen, die ansonsten entweder von den compute-bound-Threads und / oder von threads verwendet werden könnten gehören zu anderen Prozessen.

    
ChrisW 15.12.2009 22:12
quelle
0

Nicht sicher, ob ich zustimme, da Speicherzuweisungen CAN eine sehr lange Zeit brauchen (die einzige Möglichkeit nicht, wenn Sie den gesamten Speicher vorreservieren und dann wieder ausgeben). Sie müssen wirklich die gleichen Zuordnungen und Freigaben mit multi versuchen Gig-Heap-Größen mit Millionen von Einträgen, wobei viele Anwendungen den zuweisungskritischen Abschnitt (Anm. Anm. statt Threads beachten) und das Entfernen / Auslagern von Festplatten aus zu wenig Speicher belegen. Sie können auch Datenträgerwechselprobleme während der Zuweisung erhalten, und eine Drehsperre zu machen, die auf eine Datenträgeranforderung wartet, ist sicherlich nicht angemessen.

Und wie CyberShadow auf einer Single-Thread-CPU erwähnt, enden Sie mit einem Overhead in einer normalen Sperre. Jetzt kann eine Sprache auf vielen eingebetteten CPUS ausgeführt werden, die alle single-threaded sind.

Auch wenn Sie mit einem vertauschten Austausch davonkommen können, ist das das Beste (da es zwar lockless ist, aber trotzdem die CPU anhält und LOCK # für Multi-Core-Speicher auslöst), verwenden die meisten Locks das trotzdem (müssen aber mehr tun). Die Struktur eines Heaps bedeutet jedoch normalerweise, dass ein verzahnter Austausch nicht ausreicht, und Sie erstellen einen kritischen Abschnitt. Beachten Sie, dass es in einem (generischen) Mark Sweep Nursery mit einem GC möglich ist, Zuweisungen als einen verknüpften Vergleich vorzunehmen und den Zeiger hinzuzufügen. Ich mache das für den Cosmos C # OS GC und es macht Stack-Speed-Allokationen.

    
ben 10.01.2010 08:30
quelle
0

Einer der Perf-Bugs im Garbage Haskell Compiler ist so nervig, dass er einen Namen hat, den " letzte Kernverlangsamung ". Dies ist eine direkte Konsequenz ihrer unangemessenen Verwendung von Spinlocks in ihrem GC und wird auf Linux aufgrund seines Schedulers unterdrückt, aber der Effekt kann beobachtet werden, wenn andere Programme um CPU-Zeit konkurrieren.

Der Effekt ist auf der zweiten Grafik hier klar und kann Auswirkungen auf mehr als nur den letzten Kern hier , wo das Haskell-Programm Leistungseinbußen hinnehmen muss darüber hinaus nur 5 Kerne.

    
Jon Harrop 11.06.2010 23:54
quelle