У меня проблема с производительностью, которую я не понимаю. Система, над которой я работаю, имеет два потока, которые выглядят примерно так:
Версия A:
- Поток 1: Обработка данных -> Выбор данных -> Форматирование данных -> FIFO
- Тема 2: FIFO -> Розетка
Где «Выбор» сокращает данные, а FIFO в конце потока 1 - это FIFO в начале потока 2 (FIFO фактически являются параллельными очередями TBB). Из соображений производительности я изменил потоки так:
Версия B:
- Поток 1: Обработка данных -> Выбор данных -> FIFO
- Поток 2: FIFO -> Форматирование данных -> Сокет
Первоначально эта оптимизация оказалась успешной. Поток 1 способен значительно повысить пропускную способность. Я не слишком внимательно смотрел на производительность Thread 2, потому что ожидал, что загрузка процессора будет выше и (из-за утончения данных) это не было серьезной проблемой. Однако один из моих коллег попросил сравнить производительность версии A и версии B. Чтобы протестировать настройку, у меня было гнездо потока 2 (boost asio tcp socket) для записи в экземпляр iperf на том же компьютере (127.0.0.1) с цель показать максимальную пропускную способность.
Для сравнения двух настроек я сначала попытался заставить систему записывать данные из сокета на скорости 500 Мбит / с. В рамках тестирования производительности я следил за вершиной. То, что я увидел, удивило меня. Версия A не отображалась в «top -H» и iperf (на самом деле это было так, как подозревали). Тем не менее, версия B (моя «улучшенная версия») обнаруживалась в «top -H» с загрузкой процессора ~ 10%, и (как ни странно) iperf показывал с 8%.
Очевидно, это означало, что я что-то делаю не так. Я не могу доказать, что я, хотя! Вещи, которые я подтвердил:
- Обе версии дают сокету 32k кусков данных
- Обе версии используют одну и ту же библиотеку наддува (1.45)
- Оба имеют одинаковые настройки оптимизации (-O3)
- Оба получают одинаковые данные, записывают одни и те же данные и записывают их с одинаковой скоростью.
- Оба используют один и тот же блокирующий вызов записи.
- Я тестирую из той же коробки с точно такой же настройкой (Red Hat)
- Часть «форматирования» потока 2 - это , а не проблема (я удалил ее и воспроизвел проблему)
- Небольшие пакеты по сети - это , а не проблема (я использую TCP_CORK, и я подтвердил через wireshark, что все сегменты TCP ~ 16k).
- Установка режима ожидания в 1 мс сразу после записи в сокет приводит к тому, что загрузка ЦП в потоке сокета и iperf (?!) возвращается к 0%.
- Профиль бедного человека показывает очень мало (нить в сокете почти всегда спит).
- Callgrind показывает очень мало (запись в сокет едва записывает даже регистры)
- Переключение iperf для netcat (запись в / dev / null) ничего не меняет (фактически использование процессора netcat составляло ~ 20%).
Единственное, о чем я могу думать, это то, что я ввел более плотную петлю вокруг записи в сокет. Однако, при 500 Мбит / с я не ожидал бы, что использование процессора в обоих процессах и iperf будет увеличено?
Я не понимаю, почему это происходит. Мои коллеги и я в основном вне идей. Есть мысли или предложения? Я с удовольствием попробую что-нибудь на этом этапе.