TL; DR: Возможно ли, что я ограничил производительность реактора? Как бы я сказал? Насколько дорого и масштабируемо (между потоками) внедрение io_service?
У меня есть массивно параллельное приложение, работающее на машине HyperTreaded-Dual-Quad-Core-Xeon с тоннами оперативной памяти и быстрым SSD RAID. Это разработано с использованием boost :: asio.
Это приложение принимает подключения примерно от 1000 других компьютеров, считывает данные, декодирует простой протокол и перетасовывает данные в файлы, отображаемые с помощью mmap (). Приложение также предварительно извлекает «будущие» страницы mmap с помощью madvise (WILLNEED), поэтому вряд ли оно будет блокировать ошибки страницы, но, чтобы быть уверенным, я попытался создать до 300 потоков.
Это работает на ядре Linux 2.6.32-27-generic (Ubuntu Server x64 LTS 10.04). Версия Gcc - 4.4.3, версия boost :: asio - 1.40 (обе являются Ubuntu LTS).
Запустив vmstat, iostat и top, я вижу, что пропускная способность диска (как в TPS, так и в объеме данных) составляет одну цифру%. Точно так же длина очереди диска всегда намного меньше, чем количество потоков, поэтому я не думаю, что я ограничен вводом / выводом. Кроме того, RSS поднимается, но затем стабилизируется на нескольких гигабайтах (как и ожидалось), и vmstat не показывает пейджинг, поэтому я думаю, что я не связан с памятью. Процессор постоянен при 0-1% пользователя, 6-7% системы, а остальные в режиме ожидания. Подсказка! Одно полное «ядро» (не забывайте о гиперпоточности) составляет 6,25% ЦП.
Я знаю, что система отстает, потому что клиентские машины блокируют отправку по протоколу TCP при превышении 64 КБ, и сообщают об этом; все они сообщают об этом факте, и пропускная способность системы намного меньше, чем хотелось бы, предполагалось и теоретически возможно.
Полагаю, я борюсь за какой-то замок. Я использую блокировку уровня приложения для защиты таблицы поиска, которая может быть изменена, поэтому я разбила ее на 256 блокировок / таблиц верхнего уровня, чтобы сломать эту зависимость. Однако это, похоже, совсем не помогло.
Все потоки проходят через один глобальный экземпляр io_service. Запуск strace в приложении показывает, что оно тратит большую часть своего времени на вызовы futex, что, как я полагаю, связано с реализацией реактора io_service на основе четного кода.
Возможно ли, что я ограничил производительность реактора? Как бы я сказал? Насколько дорого и масштабируемо (между потоками) внедрение io_service?
РЕДАКТИРОВАТЬ: Первоначально я не нашел этот другой поток, потому что он использовал набор тегов, которые не перекрывали мои: - / Вполне возможно, моя проблема заключается в чрезмерной блокировке, используемой в реализации реактора boost :: asio , См. Сервер сокетов C ++ - Невозможно насыщать процессор
Однако остается вопрос: как я могу доказать это? И как я могу это исправить?