Auf der Suche nach einer Erklärung für das Leistungsproblem der Thread-Synchronisierung

9

Gibt es bei der Verwendung von Kernel-Objekten zur Synchronisierung von Threads, die auf verschiedenen CPUs ausgeführt werden, möglicherweise zusätzliche Laufzeitkosten, wenn Windows Server 2008 R2 relativ zu anderen Betriebssystemen verwendet wird?

Bearbeiten: Und wie über die Antwort herausgefunden, sollte die Frage auch den Ausdruck "bei niedriger CPU-Auslastung" enthalten. Ich habe mehr Informationen in meine eigene Antwort auf diese Frage aufgenommen.

Hintergrund

Ich arbeite an einem Produkt, das gemeinsamen Speicher und Semaphoren für die Kommunikation zwischen Prozessen verwendet (wenn die beiden Prozesse auf demselben Computer ausgeführt werden). Berichte von Leistungsproblemen auf Windows Server 2008 R2 (die ich nachher auf Win2008R2 verkürze) führten mich zu der Feststellung, dass die gemeinsame Nutzung eines Semaphors zwischen zwei Threads auf Win2008R2 im Vergleich zu anderen Betriebssystemen relativ langsam war.

Reproduziert es

Ich konnte es reproduzieren, indem ich den folgenden Bitcode gleichzeitig für zwei Threads ausführte:

%Vor%

Beim Testen mit einer Maschine, die in Windows Server 2003 R2 SP2 und Windows Server 2008 R2 gestartet wird, würde das obige Snippet auf der Win2003R2-Maschine etwa sieben Mal schneller als die Win2008R2 ( 3 Sekunden für Win2003R2 und 21 Sekunden) für Win2008R2 ).

Einfache Version des Tests

Das Folgende ist die Vollversion des oben genannten Tests:

%Vor%

Weitere Details

Ich habe den Test aktualisiert, um die Threads zum Ausführen einer einzelnen Iteration zu erzwingen und einen Wechsel zum nächsten Thread in jeder Schleife zu erzwingen. Jeder Thread signalisiert dem nächsten Thread, dass er am Ende jeder Schleife ausgeführt wird (Round-Robin-Stil). Und ich habe es auch aktualisiert, um einen Spinlock als Alternative zum Semaphor zu verwenden (was ein Kernel-Objekt ist).

Alle Maschinen, an denen ich getestet habe, waren 64-Bit-Maschinen. Ich habe den Test meist als 32-Bit kompiliert. Wenn es als 64-Bit erstellt wurde, lief es insgesamt etwas schneller und änderte die Verhältnisse etwas, aber das Endergebnis war dasselbe. Neben Win2008R2 habe ich auch Windows 7 Enterprise SP 1, Windows Server 2003 R2 Standard SP 2, Windows Server 2008 (nicht R2) und Windows Server 2012 Standard ausgeführt.

  • Der Test auf einer einzelnen CPU wurde wesentlich schneller ausgeführt ("erzwungen", indem die Thread-Affinität mit SetThreadAffinityMask und überprüft mit GetCurrentProcessorNumber ). Es war nicht überraschend, dass es auf allen Betriebssystemen schneller war, wenn eine einzelne CPU verwendet wurde, aber das Verhältnis zwischen Multi-CPU und Single-CPU mit der Kernel-Objekt-Synchronisation war auf Win2008R2 viel höher. Das typische Verhältnis für alle Maschinen außer Win2008R2 war 2x bis 4x (das Laufen auf mehreren CPUs dauerte 2 bis 4 mal länger). Aber auf Win2008R2 war das Verhältnis 9x.
  • Allerdings ... konnte ich die Verlangsamung auf allen Win2008R2-Rechnern nicht reproduzieren. Ich habe auf 4 getestet, und es zeigte sich auf 3 von ihnen. Daher kann ich nicht umhin, mich zu fragen, ob es irgendeine Art von Konfigurationseinstellung oder Leistungsoptimierung gibt, die dies beeinflussen könnte. Ich habe Leistungsoptimierungshandbücher gelesen, verschiedene Einstellungen durchgesehen und verschiedene Einstellungen (z. B. Hintergrunddienst vs. Vordergrundanwendung) ohne Unterschied im Verhalten geändert.
  • Es scheint nicht notwendig zu sein, zwischen physischen Kernen zu wechseln. Ich vermutete ursprünglich, dass es irgendwie mit den Kosten für den Zugriff auf globale Daten auf verschiedenen Kernen verbunden war. Aber wenn eine Testversion ausgeführt wird, die einen einfachen Spinlock für die Synchronisation verwendet (kein Kernel-Objekt), war die Ausführung der einzelnen Threads auf verschiedenen CPUs bei allen Betriebssystemtypen ziemlich schnell. Das Verhältnis zwischen dem Multi-CPU-Semaphor-Synchronisationstest und dem Multi-CPU-Spinlock-Test betrug typischerweise 10x bis 15x. Aber für die Win2008R2 Standard Edition Maschinen war das Verhältnis 30x.

Hier sind einige aktuelle Zahlen aus dem aktualisierten Test (Zeiten sind in Millisekunden):

%Vor%

Jeder der 2 Threads im Test hat 1 Million Iterationen ausgeführt. Diese Hoden wurden alle auf identischen Maschinen ausgeführt. Die Win Server 2008- und Server 2003-Nummern stammen von einem Dual-Boot-Computer. Die Win 7-Maschine hat genau die gleichen Spezifikationen, war aber eine andere physische Maschine. Die Maschine ist in diesem Fall ein Lenovo T420 Laptop mit Core i5-2520M 2.5GHz. Offensichtlich keine Server-Klasse-Maschine, aber ich bekomme ein ähnliches Ergebnis auf echter Server-Klasse-Hardware. Die Zahlen in Klammern sind das Verhältnis der ersten Spalte zur angegebenen Spalte.

Jede Erklärung, warum dieses eine OS zusätzliche Kosten für die Kernel-Level-Synchronisation über die CPUs bringen würde? Oder kennen Sie einen Konfigurations- / Tuning-Parameter, der dies beeinflussen könnte?

Obwohl es diesen äußerst ausführlichen und langen Beitrag länger machen würde, könnte ich die verbesserte Version des Testcodes, von der die obigen Zahlen kommen, veröffentlichen, wenn jemand es möchte. Das würde die Durchsetzung der Round-Robin-Logik und der Spinlock-Version des Tests anzeigen.

Erweiterter Hintergrund

Um zu versuchen, einige der unvermeidlichen Fragen zu beantworten, warum Dinge so gemacht werden. Und ich bin genauso ... wenn ich einen Beitrag lese, frage ich mich oft, warum ich überhaupt frage. Also hier sind einige Versuche zu klären:

  • Was ist die Anwendung? Es ist ein Datenbankserver. In einigen Situationen führen Kunden die Clientanwendung auf demselben Computer wie den Server aus. In diesem Fall ist es schneller, gemeinsam genutzten Speicher für die Kommunikation zu verwenden (im Gegensatz zu Sockets). Diese Frage bezieht sich auf den gemeinsamen Speicher comm.
  • Ist die Arbeitsbelastung wirklich abhängig von Ereignissen? Nun ... die gemeinsame Speicherkommunikation wird unter Verwendung von benannten Semaphoren implementiert. Der Client signalisiert einen Semaphor, der Server liest die Daten, der Server signalisiert dem Kunden ein Semaphor, wenn die Antwort bereit ist. In anderen Plattformen blendet es blitzschnell. Auf Win2008R2 ist es nicht. Es ist auch sehr abhängig von der Kundenanwendung. Wenn sie es mit vielen kleinen Anfragen an den Server schreiben, dann gibt es eine Menge Kommunikation zwischen den beiden Prozessen.
  • Kann ein leichtes Schloss verwendet werden? Möglicherweise. Ich sehe das schon. Aber es ist unabhängig von der ursprünglichen Frage.
Mark Wilkins 18.01.2013, 17:42
quelle

4 Antworten

3

Von den Kommentaren in eine Antwort gezogen:

Vielleicht ist der Server nicht auf den Hochleistungs-Energiesparplan eingestellt? Win2k8 hat möglicherweise einen anderen Standard. Viele Server sind nicht standardmäßig, was die Leistung sehr stark beeinträchtigt.

Das OP hat dies als Hauptursache bestätigt.

Dies ist ein lustiger Grund für dieses Verhalten. Die Idee blitzte in meinem Kopf auf, während ich etwas völlig anderes machte.

    
usr 21.01.2013, 23:46
quelle
0

Es kann durchaus sein, dass die OS-Installationskonfiguration variiert. Möglicherweise ist das langsame System so konfiguriert, dass mehrere Threads aus Ihrem Prozess nicht gleichzeitig geplant werden. Wenn ein anderer Prozess mit hoher Priorität immer (oder meistens) zur Ausführung bereit ist, besteht die einzige Alternative darin, dass die Threads sequenziell und nicht parallel ausgeführt werden.

    
wallyk 18.01.2013 17:51
quelle
0

Ich füge diese zusätzlichen "Antwort" Informationen hier hinzu, anstatt sie in meinem überlangen OP zu vergraben. @usr hat mich mit dem Vorschlag zur Energieverwaltung auf die richtige Richtung gebracht. Der erfundene Test im OP sowie das ursprüngliche Problem beinhalten eine Menge Handshake zwischen verschiedenen Threads. Der Handshake in der Real-World-App erfolgte über verschiedene Prozesse hinweg, aber Tests zeigten, dass sich die Ergebnisse nicht unterscheiden, wenn es Threads oder Prozesse sind, die das Handshake durchführen. Die Freigabe des Semaphors (Kernel-Sync-Objekt) über die CPUs hinweg scheint in Windows Server 2008 R2 durch die Energieeinstellungen stark beeinträchtigt zu sein, wenn sie bei niedriger (z. B. 5% bis 10%) CPU ausgeführt wird. Mein Verständnis davon basiert an dieser Stelle rein auf Mess- und Timing-Anwendungen.

Eine verwandte Frage zu Serverfault spricht auch davon .

Die Testeinstellungen

Einstellungen für die Energieeinstellungen des Betriebssystems Der standardmäßige Energiesparplan für Windows Server 2008 R2 lautet "Ausgewogen". Durch die Umstellung auf die "High Performance" -Option wurde die Leistung dieses Tests erheblich verbessert. Insbesondere scheint eine bestimmte Einstellung unter "Erweiterte Einstellungen ändern" kritisch zu sein. Die erweiterten Einstellungen haben eine Option unter Prozessor-Energieverwaltung mit dem Namen Minimaler Prozessorstatus . Der Standardwert dafür unter dem Balanced-Plan scheint 5% zu sein. Es war der Schlüssel, dies in meinem Test auf 100% zu setzen.

BIOS-Einstellung Außerdem hat eine BIOS-Einstellung diesen Test stark beeinflusst. Ich bin mir sicher, dass dies in der Hardware sehr unterschiedlich ist, aber die primäre Maschine, auf der ich getestet habe, hat eine Einstellung namens "CPU Power Management". Die Beschreibung der BIOS-Einstellung lautet, "Aktiviert oder deaktiviert die Energiesparfunktion, die die Mikroprozessoruhr automatisch stoppt, wenn keine Systemaktivitäten stattfinden." Ich habe diese Option auf "Deaktiviert" geändert.

Empirische Ergebnisse

Die zwei gezeigten Testfälle sind:

  • (a) Einfach. Eine modifizierte Version des im OP enthaltenen. Dieser einfache Test erzwang Round-Robin-Switching bei jeder Iteration zwischen zwei Threads auf zwei CPUs. Jeder Thread lief 1 Million Iterationen (also gab es 2 Millionen Kontextwechsel zwischen den CPUs).
  • (b) Wirkliche Welt. Der echte Client / Server-Test, bei dem ein Client viele "kleine" Anfragen des Servers über Shared Memory abgab und mit globalen benannten Semaphoren synchronisierte.

Die drei Testszenarien sind:

  • (i) Ausgeglichen. Standardinstallation von Windows Server 2008 R2, die den Energiesparplan Balanced verwendet.
  • (ii) HighPerf. Ich habe die Energieoption von "Balanced" zu "High Performance" geändert. Gleichermaßen traten die gleichen Ergebnisse auf, indem die CPU-Option "Minimum Processor State" wie oben beschrieben auf 100% (von 5%) gesetzt wurde.
  • (iii) BIOS. Ich habe die CPU-Power-Management-BIOS-Option wie oben beschrieben deaktiviert und auch die Option High Performance power ausgewählt.

Die angegebenen Zeiten sind in Sekunden:

%Vor%

Nachdem beide Änderungen vorgenommen wurden (OS und BIOS), liefen sowohl der reale Test als auch der künstliche Test ungefähr 5 mal schneller als unter der Standardinstallation und den Standard-BIOS-Einstellungen.

Während ich diese Fälle getestet habe, bin ich manchmal auf ein Ergebnis gestoßen, das ich nicht erklären konnte. Wenn die CPU beschäftigt war (ein Hintergrundprozess würde anspringen), würde der Test schneller laufen. Ich würde es in meinem Kopf ablegen und für eine Weile verwirrt sein. Aber jetzt macht es Sinn. Wenn ein anderer Prozess ausgeführt würde, würde dies die CPU-Nutzung über den Schwellenwert hinaus erhöhen, der benötigt wurde, um es in einem Zustand hoher Leistung zu halten, und die Kontextwechsel würden schnell sein. Ich weiß immer noch nicht, welcher Aspekt langsam ist (die primären Kosten sind im WaitForSingleObject-Aufruf begraben), aber die Endergebnisse sind jetzt alle irgendwie sinnvoll.

    
Mark Wilkins 22.01.2013 00:57
quelle
-3

Das ist kein vernünftiger Benchmark, Ihre Semaphore werden immer im gleichen Prozess (und damit vermutlich auf derselben CPU / demselben Kern) ausgetobt. Ein wichtiger Teil der Kosten der Sperrung in realen Fällen sind die Speicherzugriffe, die beteiligt sind, wenn verschiedene CPUs / Kerne um exklusiven Zugriff auf den Speicherbereich kämpfen (der zwischen Caches hin und her springt). Suchen Sie nach mehr realen Benchmarks (sorry, nicht mein Bereich), o (noch besser) messen Sie Ihre Anwendung mit (gekünstelten, aber realistischen) Testdaten (eine etwas reduzierte Version von).

[Testdaten für Benchmarks sollten nie für Testzwecke oder Regressionstests sein: die späteren Stocherkästen bei (wahrscheinlich selten genutzten) Eckfällen, Sie wollen "typische" Läufe für Benchmarks.]

    
vonbrand 20.01.2013 01:38
quelle