C # Leistung variiert aufgrund des Speichers

8

Ich hoffe, dies ist ein gültiger Beitrag hier, es ist eine Kombination aus C # -Ausgaben und Hardware.

Ich benchmarkiere unseren Server, weil wir Probleme mit der Leistung unserer quant-Bibliothek (geschrieben in C #) gefunden haben. Ich habe die gleichen Performance-Probleme mit einigen einfachen C # -Code simuliert - Durchführung sehr hoher Speicherverbrauch.

Der folgende Code ist in einer Funktion, die aus einem Threadpool hervorgeht, bis zu einem Maximum von 32 Threads (weil unser Server 4x CPUs x 8 Kerne hat).

Dies alles ist auf .Net 3.5

Das Problem ist, dass wir sehr unterschiedliche Leistungen bekommen. Ich führe die unten stehende Funktion 1000 mal aus. Die durchschnittliche Zeit, die für die Ausführung des Codes benötigt wird, kann 3,5 Sekunden betragen, aber die schnellste Zeit beträgt nur 1,2 Sekunden und die langsamste Zeit beträgt 7 Sekunden - für die exakt gleiche Funktion!

Ich habe den Speicherverbrauch gegenüber den Zeitangaben grafisch dargestellt, und es scheint keine Korrelation mit dem GC-Kicking zu geben.

Eine Sache, die ich bemerkt habe, ist, dass wenn man in einem einzigen Thread läuft, die Timings identisch sind und es keine wilde Abweichung gibt. Ich habe auch CPU-gebundene Algorithmen getestet und die Timings sind auch identisch. Das hat uns dazu gebracht, uns zu fragen, ob der Speicherbus es einfach nicht schafft.

Ich frage mich, ob das ein weiteres .net- oder C # -Problem sein könnte, oder ist es etwas mit unserer Hardware zu tun? Wäre das die gleiche Erfahrung, wenn ich C ++ oder Java benutzt hätte ?? Wir verwenden 4x Intel x7550 mit 32 GB RAM. Gibt es überhaupt eine Lösung für dieses Problem?

%Vor%

(der Code soll nur die Erinnerung betonen)

Ich würde den Threadpool-Code einschließen, aber wir haben eine nicht standardmäßige Threadpool-Bibliothek verwendet.

EDIT: Ich habe "size1" auf 100000 reduziert, was im Grunde nicht viel Speicher benötigt und ich bekomme immer noch viel Jitter. Dies deutet darauf hin, dass es nicht die Menge an Speicher ist, die übertragen wird, sondern die Häufigkeit des Speicherzugriffs?

    
mezamorphic 03.04.2012, 16:15
quelle

6 Antworten

4

Es ist nicht genug, um weiter zu gehen, aber hier sind einige Bereiche, die Sie suchen sollten:

  • Die Variabilität ist das Ergebnis des internen GC-Zustands. Der GC verwaltet dynamisch die Größen der verschiedenen Pools. Wenn Sie mit unterschiedlichen Poolgrößen beginnen, erhalten Sie während der Läufe ein anderes GC-Verhalten.
  • Moiré-Muster in der Thread-Planung. Abhängig von zufälligen Variationen in der Sequenzierung der Threads könnten Sie mehr oder weniger günstige Konkurrenzmuster haben. Wenn es eine Periodizität gibt, kann dies zu einem verstärkten Effekt führen, der einer konstruktiven Interferenz ähnelt.
  • Falsche Freigabe Wenn Sie zwei Threads haben, die beide Speicheradressen erreichen, die nahe genug sind, um im Prozessor-Cache gespeichert zu werden, werden Sie eine merkliche Leistungsminderung feststellen, da die Prozessoren viel Zeit damit verbringen müssen, ihre Caches neu zu synchronisieren. Abhängig davon, wie Sie Ihre Daten organisieren und Threads zuordnen, um sie zu verarbeiten, können Sie auf der Basis von Variationen am Anfang Muster in der falschen Freigabe erhalten.
  • Ein anderer Prozess im System beansprucht Prozessorzeit. Möglicherweise möchten Sie eine Zeit für den Prozessbenutzermodus anstelle der Wandzeit verwenden. (Es gibt irgendwo einen Accessor in der Process-Klasse).
  • Der Computer läuft nahe an seinem vollen physischen Speicherlimit. Der Wechsel zur Festplatte erfolgt mit mehr oder weniger zufälligen Mustern.
Kennet Belenky 03.04.2012 17:04
quelle
1

Sie treffen hier ziemlich grundlegende Einschränkungen der Maschine. Sie haben viele Kerne, aber es gibt immer noch nur einen Speicherbus. Wenn Ihre Threads also viele Daten mischen, werden sie wahrscheinlich durch die Bandbreite dieses einzelnen Busses gedrosselt. Das ist Amdahls Gesetz bei der Arbeit.

Es gibt eine mögliche Optimierung, die von der Art des Betriebssystems abhängt, das diese Maschine ausführt. Dies ist Server-Hardware, aber wenn Sie eine Nicht-Server-Version von Windows haben, wird der Garbage Collector im Workstation-Modus ausgeführt. Sie können dann das Element <gcServer> in der Datei .config der Anwendung verwenden, um nach der Serverversion des Collectors zu fragen. Es verwendet mehrere Heaps, so dass die Threads nicht so oft um die GC-Heap-Sperre kämpfen, wenn sie Speicher reservieren. Ymmv.

    
Hans Passant 03.04.2012 16:39
quelle
0

List verwendet Arrays intern zum Speichern. Ich glaube, es wird versuchen, die Größe des Arrays jedes Mal zu verdoppeln, wenn es die Grenze des freien Speicherplatzes in der Liste erreicht.

Wenn Sie in die Schleife gehen, werden größere und größere zusammenhängende Speicherblöcke benötigt, um die neuen Arrays zuzuweisen, wenn die Liste wächst. Mit einem Thread ist das ziemlich einfach. Mit 2+ Threads konkurrieren Sie um große Teile zusammenhängender Speicher. Es würde den GC zu zufälligen Zeiten auslösen, da die Arrays größer wurden und zusammenhängender Speicher schwerer zu finden war.

    
Bill Crim 03.04.2012 16:31
quelle
0

Stellen Sie sicher, dass die Laufzeitkonfiguration gcserver = true

hat     
Shay 03.04.2012 16:40
quelle
0

An diesem Punkt scheint es, als wäre das Raten einfach eine Vermutung. Wirklich, was Sie brauchen, sind mehr Informationen.

Ich würde einen Profiler anschließen oder einige Windows-Leistungsindikatoren einrichten:

Ссылка

Sie sollten einige Leistungsindikatoren hinzufügen können, die auf den Prozess zentriert sind. Sie können sich ansehen, wie viele Threads hochgespielt werden, wie viel Arbeitsspeicher belegt ist. Ich würde hier einige der anderen Vorschläge berücksichtigen und das Szenario, nach dem Sie suchen, messen. Wenn Sie die Daten des Leistungsindikators in eine CSV-Datei ablegen, können Sie die Ergebnisse sogar schnell grafisch darstellen, um einige gute Daten zu erhalten, an denen Sie wirklich herumkauen können. Wenn Sie herausfinden können, welcher Messwert sich mit dem 1.2s vs 7s Szenario ändert, können Sie damit beginnen, fundierte Vermutungen darüber anzustellen, was vor sich geht, und weiter vorgehen.

    
Andrew Dunaway 03.04.2012 17:10
quelle
0

Synchrone Aufrufe an gemeinsam genutzte Ressourcen, wie die Konsole oder das Dateisystem, werden die Leistung erheblich beeinträchtigen, aber nach dem Aussehen der Dinge ist dieser Code nur maximale CPU und die Zeitabweichungen müssen durch andere Prozesse verursacht werden, die CPU-Zeit anfordern.

    
Shay 04.04.2012 08:39
quelle