Предупреждение: Это не окончательный ответ на вашу проблему, но есть кое-что, что нужно попробовать (он слишком велик для комментария).
С (например) GigE скорость передачи данных составляет ~ 100 МБ / с. При [общем] объеме буферного пространства ядра 614400 оно будет пополняться ~ 175 раз в секунду. ИМО, это все еще маловато. Когда я использовал SO_RCVBUF
[для коммерческого продукта], я использовал минимум 8 МБ. Это дает широкий (более) запас для задержек переключения задач.
Попробуйте установить что-нибудь огромное например 100 МБ, чтобы исключить это как фактор [во время тестирования / запуска].
Во-первых, важно убедиться, что ядро и драйвер NI C могут обрабатывать пропускную способность / задержку.
Возможно, вы получаете слишком много прерываний в секунду, и накладные расходы пролога / эпилога ISR могут быть слишком высокая. Драйвер карты NI C может реализовать драйвер опроса и прерывания с NAPI
для карт ethe rnet.
См .: https://serverfault.com/questions/241421/napi-vs-adaptive-interrupts
См .: https://01.org/linux-interrupt-moderation
Возможно, у вашего процесса / потока недостаточно высокого приоритета для быстрого планирования.
Вы можете использовать планировщик R / T с sched_setscheduler
, SCHED_RR
и приоритетом (например) 8. Примечание: если значение выше 11 убивает систему, потому что при 12 и выше у вас более высокий приоритет, чем у большинства внутренних потоков ядра - не очень хорошо.
Возможно, вам потребуется отключить балансировку IRQ и установить привязку IRQ к одному ядру ЦП.
Затем вы можете установить свой входной процесс / поток, заблокированный для этого ядра [с помощью sched_setaffinity
и / или pthread_setaffinity
].
Вам может потребоваться своего рода «нулевая копия», чтобы обойти копирование ядра из его буферов в ваши буферы пользовательского пространства.
Вы можете mmap
буферы сокета ядра с помощью PACKET_MMAP
. См .: https://sites.google.com/site/packetmmap/
Я был бы осторожен с накладными расходами на ваш вывод qDebug
. Похоже на реализацию типа iostream. Накладные расходы могут быть значительными. Это может значительно замедлить работу.
То есть вы не измеряете производительность своей системы. Вы измеряете производительность своей системы плюс код отладки.
Когда мне приходилось отлаживать / отслеживать такие вещи, я использовал [собственный] журнал «событий» реализована с помощью кольцевой очереди в памяти с фиксированным числом элементов.
Вызовы отладки, такие как:
eventadd(EVENT_TYPE_RECEIVE_START,some_event_specific_data);
Здесь eventadd
заполняет «событие» фиксированного размера struct
с тип события, данные события и метка времени найма (например, struct timespec
из clock_gettime(CLOCK_MONOTONIC,...)
.
Накладные расходы каждого такого вызова довольно низкие. События просто сохраняются в кольце событий. Только последние Запоминаются N.
В какой-то момент ваша программа запускает дамп этой очереди в файл и завершается.
Этот механизм похож на [и смоделирован] H / W logi c анализатор. Он также похож на dtrace
Вот пример элемента события:
struct event {
long long evt_tstamp; // timestamp
int evt_type; // event type
int evt_data; // type specific data
};