Wir haben einen 64-Bit-Server für Windows 2003 R2 Enterprise, auf dem eine benutzerdefinierte Arbeitslast ausgeführt wird, die unter einem merkwürdigen Leistungsproblem leidet. Die reduzierte Version unten leidet unter einem kleineren Buckel, ist aber qualitativ gleich.
Wir haben es auf eine einfache Trivial-App reduziert, die nichts weiter tut als:
- auf eine Steckdose hören
- Beitritt zu einer Multicast-Gruppe
- Abhören von Paketen, die in dieser Gruppe eingehen
- Lesen und Verwerfen der Pakete
Die Testanwendung selbst ist eine leicht modifizierte Version des Beispiels für den Boost ASIO-Multicast-Empfänger, sodass nicht wirklich viel schief gehen sollte. Aktueller Code (!) Unten…
Während dieses Programms unter Last ausgeführt wird, wird die CPU für diesen Prozess von Zeit zu Zeit hochgefahren, wobei die gesamte Verarbeitung im Kernel-Code erfolgt:
(Hier wird nur CPU 6 angezeigt. Für die Dauer dieses Tests (3h17m) sind alle anderen Prozessoren inaktiv.)
Wie Sie in der Grafik sehen können, geschieht die gesamte Verarbeitungszeit im Kernel-Code, wenn die Lastspitzen auftreten. Die aufgewendete Zeit wird hauptsächlich für verzögerte Prozeduraufrufe (max. 16,8%) und die Behandlung von Interrupts (max. 8,5%) aufgewendet. Es sieht so aus, als würde eine verzögerte Bereinigung stattfinden, aber wir haben keine Ahnung, was es sein könnte.
Soweit wir das beurteilen können, geschieht dies nur auf dem W2K3E-64.
Dies geschieht auf unterschiedlicher Hardware (HS21, HS22, HS22V, HP DL380).
Das Ausführen der Testanwendung unter Windows 2008 zeigt das Problem in viel geringerem Maße (häufiger, aber mit kleineren Buckeln).
Wie können wir das beheben oder wo sollen wir als nächstes suchen?
Aktueller Code aus dem Beispiel:
void handle_receive_from(const boost::system::error_code& error,
size_t bytes_recvd)
{
if (!error)
{
++m_receivedPackets;
m_receivedBytes += bytes_recvd;
m_last64TotalBytes += bytes_recvd;
if ( ( m_receivedPackets & 0x3F ) == 0 )
{
printf( "Received %u bytes in %u packets. The average size of the last 64 packets was %u bytes, and the last byte received was %x.\n",
m_receivedBytes, m_receivedPackets, m_last64TotalBytes / 64, m_buffer[ bytes_recvd - 1 ] );
m_last64TotalBytes = 0;
}
m_socket.async_receive_from(
boost::asio::buffer(m_buffer, max_length), m_senderEndpoint,
boost::bind(&receiver::handle_receive_from, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cerr << "An error occurred when performing an asyncronous read." << std::endl;
m_socket.get_io_service().stop();
}
}
Antworten:
"Es sieht so aus, als würde eine verzögerte Bereinigung stattfinden, aber wir haben keine Ahnung, was es sein könnte."
Dies könnte eine Speicherbereinigung sein, aber ich bin nicht sicher, ob die Speicherbereinigung als privilegierte Zeit angezeigt wird. Wenn es sich um eine .NET-Anwendung handelt, können Sie sich die
.NET CLR Memory
Leistungsindikatoren ansehen (insbesondere Gen 2 ist teuer).In diesem Sinne scheint das Erraten möglicher Probleme etwas rückwärts zu sein. Am besten profilieren Sie Ihre Anwendung und sehen, was sie währenddessen tut, um zu sehen, welche Anrufe die Anwendung tätigt. Möglicherweise können Sie nur den Prozessmonitor verwenden , um die Systemaufrufe zu überwachen.
quelle
.NET
. Ich habe eine Art Garbage Collection auf Betriebssystemebene theoretisiert.Ich gehe davon aus, dass das System Multicast-Pakete empfängt. Können Sie versuchen, zu verhindern, dass die Pakete empfangen werden, und feststellen, ob das gleiche Problem auftritt?
Wie wäre es, der Multicast-Gruppe beizutreten, aber dann nicht auf Pakete zu warten?
Sie sagen, es passiert auf verschiedenen Systemen, aber was ist mit der tatsächlichen NIC-Hardware? Es ist möglich, dass es auf diesen verschiedenen Systemen gleich ist.
Update: Wenn alle Systeme Broadcom-Netzwerkkarten verwenden, liegt das Problem möglicherweise an der Netzwerkkarte. Insbesondere die von Microsoft bereitgestellten Broadcom-Treiber sind mies; Die auf der Broadcom-Website sind viel besser.
quelle
Sie können sich zwei Dinge ansehen: Ihr Thread-Quantum und die Ursachen Ihres DPC (verzögerte Prozeduraufrufe).
Thread-Quanten sind sehr einfach zu adressieren (wahrscheinlich ein roter Hering, können aber auch überprüft werden);
Am wahrscheinlichsten ist Hintergrunddienste ausgewählt. Versuchen Sie, Programme auszuwählen. Dadurch wird die Zeit zwischen Interrupts verkürzt und es können mehr Threads in derselben Zeit auf dem Prozessor ausgeführt werden. Sie erhalten mehr Interrupts, aber weniger Verarbeitungszeit.
Verzögerte Prozedur Anrufe sind etwas schwieriger zu diagnostizieren.
Wie von @wfaulk angegeben, weist dies normalerweise auf ein Treiberproblem hin. Es gibt ein praktisches Tool namens DPC Latency Checker, mit dem Sie diese Probleme diagnostizieren können. Auch wenn dies auf mehreren Hardwareplattformen geschieht, haben alle möglicherweise einen gemeinsamen Treiber. Führen Sie DPC Checker aus und befolgen Sie die Anweisungen auf ihrer Website.
Drei Anschlussfragen:
Verwenden Sie Teamed-NICs? Sie verwenden den TCP / IP-Stack, um miteinander zu kommunizieren, und können schwerwiegende DPC-Probleme verursachen.
Unterstützen Ihre Netzwerkkarten TCP Offload? Ist es aktiviert?
(Eine vollständige Aufnahme im Dunkeln) Ist Ihr Testserver Teil einer Domain? Gruppenrichtlinienobjekte werden standardmäßig alle 90 Minuten aktualisiert ...
quelle