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();
}
}