Неожиданное использование сокетов - PullRequest
1 голос
/ 12 марта 2011

У меня проблема с производительностью, которую я не понимаю. Система, над которой я работаю, имеет два потока, которые выглядят примерно так:

Версия 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 будет увеличено?

Я не понимаю, почему это происходит. Мои коллеги и я в основном вне идей. Есть мысли или предложения? Я с удовольствием попробую что-нибудь на этом этапе.

Ответы [ 3 ]

0 голосов
/ 12 марта 2011

Что, если FIFO был узким местом в версии A. Тогда оба потока будут сидеть и ждать FIFO большую часть времени.А в версии B вы будете передавать данные на iperf быстрее.

0 голосов
/ 12 марта 2011

Что именно вы храните в очередях FIFO?Храните ли вы пакеты данных, т.е. буферы?

В версии A вы записывали отформатированные данные (возможно, байты) в очередь.Таким образом, отправка его в сокет включала только запись буфера фиксированного размера.

Однако в версии B данные высокого уровня хранятся в очередях.Форматирование теперь создает больший размер буфера, который записывается непосредственно в сокет.Это заставляет стек TCp / ip тратить циклы ЦП на фрагментацию и накладные расходы ...

Это моя теория, основанная на том, что вы уже сказали.

0 голосов
/ 12 марта 2011

Это будет очень трудно проанализировать без фрагментов кода или фактических объемов данных.

Одна вещь, которая приходит на ум: если предварительно отформатированный поток данных значительно больше, чем постформатный, возможно, вы тратите больше пропускной способности / циклов, копируя кучу большего количества данных через границу FIFO (сокета).

Попробуйте оценить или измерить скорость передачи данных на каждом этапе. Если скорость передачи данных выше на выходе «selection», рассмотрите влияние перемещения форматирования на другую сторону границы. Возможно ли, что для перехода select-> format в конфигурации A не требуется копия, а конфигурация B налагает много копий?

... только догадки, без глубокого понимания системы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...