У нас есть 64-разрядный сервер Windows 2003 R2 Enterprise, на котором выполняется настраиваемая рабочая нагрузка, страдающая от странной проблемы с производительностью. Урезанная версия ниже страдает меньшим горбом, но в качественном отношении она такая же.
Мы свели его к простому тривиальному приложению, которое ничего не делает, кроме:
Само тестовое приложение представляет собой немного измененную версию приемник многоадресной рассылки Boost ASIO пример, так что на самом деле не так уж много должно пойти не так. Актуальный код (!) Ниже…
Время от времени при запуске этой программы под нагрузкой ЦП для этого процесса будет наращивать всю обработку, выполняемую в коде ядра:
(здесь показан только CPU 6. На время этого теста (3ч17мин) все остальные процессоры простаивают)
Как видно из графика, при скачках нагрузки все время обработки происходит в коде ядра. Время, затрачиваемое в основном на отложенные вызовы процедур (максимум 16,8%) и обработку прерываний (максимум 8,5%). Похоже, что происходит какая-то отложенная очистка, но мы понятия не имеем, что это может быть.
Насколько мы можем судить, это происходит только на W2K3E-64.
Это происходит на другом оборудовании (HS21, HS22, HS22V, HP DL380).
Запуск тестового приложения в Windows 2008 демонстрирует проблему в гораздо меньшей степени (чаще, но меньшие неровности).
Как мы можем это исправить или куда смотреть дальше?
Актуальный код из примера:
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();
}
}
Я предполагаю, что система получает многоадресные пакеты. Можете ли вы попытаться предотвратить получение пакетов и посмотреть, увидите ли вы ту же проблему?
А как насчет того, чтобы присоединиться к группе многоадресной рассылки, но не слушать пакеты?
Вы говорите, что это происходит в разных системах, но как насчет фактического оборудования NIC? Возможно, что в этих разных системах то же самое.
Обновление: если все системы используют сетевые адаптеры Broadcom, возможно, проблема связана с сетевым адаптером. В частности, драйверы Broadcom, поставляемые Microsoft, никуда не годятся; те, что есть на сайте Broadcom, намного лучше.
«Похоже, что происходит какая-то отложенная очистка, но мы понятия не имеем, что это может быть».
Это может быть сборка мусора, но я не уверен, отображается ли сборка мусора как привилегированное время. Если это приложение .NET, вы можете посмотреть .NET CLR Memory
счетчики производительности (особенно дорогое поколение Gen 2).
В этой связи предположение о возможных проблемах кажется немного обратным. Лучше всего было бы профилировать свое приложение и посмотреть, что оно делает во время этого, чтобы увидеть, какие вызовы делает приложение. Возможно, вам удастся просто использовать Монитор процесса для просмотра системных вызовов.
Вы можете посмотреть на две вещи: квант вашего потока и то, что вызывает ваш DPC (отложенные вызовы процедур).
Квант потока очень легко решить (возможно, отвлекающий маневр, но с таким же успехом можно и проверить);
Скорее всего выбраны фоновые службы, попробуйте выбрать «Программы». Это уменьшит количество времени между прерываниями и позволит большему количеству потоков выполняться за то же время на процессоре. Вы получаете больше прерываний, но меньше времени на обработку.
Отложенные вызовы процедур немного сложнее диагностировать;
Как заявил @wfaulk, это обычно указывает на проблему с драйвером. Есть удобный инструмент под названием Проверка задержки DPC что поможет вам диагностировать эти проблемы. Несмотря на то, что это происходит на нескольких аппаратных платформах, все они могут использовать общий драйвер. Запустите DPC Checker и следуйте инструкциям на их сайте.
Три дополнительных вопроса:
Вы используете объединенные сетевые адаптеры? Они используют стек TCP / IP для связи друг с другом и могут вызвать серьезные проблемы с DPC.
Поддерживают ли ваши сетевые карты разгрузку TCP? Это включено?
(Полный кадр в темноте) Является ли ваш тестовый сервер частью домена? По умолчанию объекты групповой политики обновляются каждые 90 минут ...