LINUX.ORG.RU

Проблема с темпом выдачи данных 1,6 ms (Qt c++, tcp)

 , ,


0

4

Linux Astra. При передачи данных возникают задержки около 200, 50 миллисекунд через несколько тысяч пачек, есть зависимость от взаимодействия с рабочим столом (сворачивание окон) . Протокол: запрос-ответ, управляющий пакет 100 байт, ответный 800 байт, темп 1,6 мс. Используются линуксовые сокеты,в setsockopt TCP_NODELAY 1. На поток выдачи выставлен scheduler SCHED_FIFO с приоритетом 98, прерывания обрабатываются на отдельном ядре. Пересобирал ядро для повышения частоты прерываний CONFIG_HZ с 250 до 1000. Проблема сохраняется на тестовой программе, выдающей константный массив. Прошу помочь.



Последнее исправление: Speed_nik (всего исправлений: 1)

есть зависимость от взаимодействия с рабочим столом (сворачивание окон)

Ты же не выполняешь IO-операции в главном потоке, правда?

XMs ★★★★★
()

Поиграйся с размерами приемного и передающего буфера. Попробуй неблокирующий режим передачи.

eagleivg ★★★★★
()
Ответ на: комментарий от eagleivg

В setsockopt ставил TCP_MAXSEG 1024,SO_SNDBUF 4096, пачки не режутся

Speed_nik
() автор топика
Ответ на: комментарий от Speed_nik

В смысле? Если ты создавал отдельный поток (QThread/std::thread/whatever) и все сетевые операции делал в нём — то, значит, всё хорошо, у тебя код выполняется в отдельном потоке. Если нет — всё в главном.


Используются линуксовые сокеты,в setsockopt TCP_NODELAY 1

Есть ли в этом объективная причина? Почему не воспользуешься QTCPSocket? С ним и при многопоточности проще

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 2)
Ответ на: комментарий от XMs

Класс создал, инициализировал, закинул в поток (movetothread). Вызовы происходят с ID потока.

Сначала использовал QTCPSocket, переписал в надежде ускорить работу.

TCP_NODELAY, т. к. пакеты небольшие ускоряет передачу

Speed_nik
() автор топика
Ответ на: комментарий от Speed_nik

Класс создал, инициализировал, закинул в поток

Только сейчас или ещё тогда? А гуи тред ничего из данных рабочего потока не лочит?

deep-purple ★★★★★
()
Ответ на: комментарий от XMs

В смысле?

А ты, кстати, не всматривался в htop с кутёвым приложением? Оно своей жизнью живёт: иногда самостоятельно по прихоти его левой пятки потоки создаёт/удаляет.

deep-purple ★★★★★
()

Попробуй освободить одно ядро поближе к dma зоне от остальных процессов и потоков и посади туда сетевой поток.

Но для начала, тебе нужен какой-то бенчмарк твоей сети, что бы понять много или мало 1.6ms.

Ещё, можно логи поставить на критическом пути программы, с целевым лэйтенси ~2ms можно вполне себе брать spdlog или даже boost::log и посмотреть где «тормозит».

есть зависимость от взаимодействия с рабочим столом (сворачивание окон)

Проблема сохраняется на тестовой программе, выдающей константный массив

Видимо таки дело в affinity если оба два правда.

pon4ik ★★★★★
()
Ответ на: комментарий от anonymous

тсп может 50us в 99.99% случаев, при правильной сетевухе и прочих тюнингах, даже на штатном ляликсовом tcp стеке.

pon4ik ★★★★★
()
Ответ на: комментарий от Speed_nik

Не лочит

Т.е. гуй вообще никоим образом ни байтика информации из рабочего треда не использует? А что же он тогда показывает? Пустое окно? Не верится.

Колись каким образом гуй получает информацию для отображения состояния и/или данных из рабочего треда.

deep-purple ★★★★★
()
Ответ на: комментарий от anonymous

Я бы сначала поигрался с сокетами без полезной нагрузки. iperf слишком навороченный, придётся как минимум сорцы посмотреть, что бы убедиться, что он про лэйтенси а не про трупут.

pon4ik ★★★★★
()
Ответ на: комментарий от Speed_nik

Класс создал, инициализировал

Какой класс? Свой или QTCPSocket?

Покажи, как у тебя происходит обмен данными с сетью.


переписал в надежде ускорить работу

QTCPSocket, конечно, может тормозить, но из-за эвентлупа, а не сам по себе. Его можно использовать без него

XMs ★★★★★
()
Ответ на: комментарий от XMs

Я такое поведение замечал только если более одного «потока» (кутреда, поэтому в кавычках), создаёт ещё 1, а сильно реже даже 2 реальных потока, когда я заставляю рабочий «поток» шевелиться.

deep-purple ★★★★★
()
Ответ на: комментарий от Speed_nik

сигналы/слоты

Перепроверь и руками, явно, в коннектах слотов укажи queued connection, но только в тех, которые касаются подписки на эмиты из рабочего треда (дада, я знаю что оно автоматически типа само, но читай дальше). Проверь чтобы в коде НЕ БЫЛО так, что какой-то объект в треде гуя может эмитнуть сигнал, на который другой объект в треде гуя подписан как «queued».

очередь

Какая-то своя в потоке или ты про queued о котором я абзацем выше?

Добавь рабочему треду «мощщИ»: http://doc.qt.io/qt-5/qthread.html#Priority-enum

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Явно указана очередь в cornnect слотов, вызовы не пересекаются. Очередь QQueue для поддержки буфера выдачи, приоритет потока TimeCritical

Speed_nik
() автор топика
Ответ на: комментарий от Speed_nik

Без кода сложно. Попробуй сделать минимальный пример, который сможешь выложить и где проблема будет проявляться

XMs ★★★★★
()

Ещё пачка наводящих вопросов:

  • У тебя под контролем сервер или клиент или и то и то
  • Есть ли вылеты на петле
  • Стандартные ли настройки буферов сокетов на стороне клиента и сервер
  • Пробовал ли SO_BUSY_POLL
  • Как ты дёргаешь сокет - неблокирущий, асинхронный или блокирующий
pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Только сервер.

Вылетов нет.

К клиенту доступа нет, сервер и тестовый клиент настраивал с помощью setsockopt, в sysctl. Помогло слабо, в связи с этим не уверен в правильности настройки.

Попробую SO_BUSY_POLL

Сначала был асинхронный, теперь блокирующий

Speed_nik
() автор топика
Ответ на: комментарий от XMs

Ты же не выполняешь IO-операции в главном потоке, правда?

На что ты намекаешь? Код выполняемый в главном потоке особо замедлен что ли? Это такой же код, просто, он оккупировав главный поток залочит UI. Почему этот код должен выполняться медленее?

thomasbug
()
Ответ на: комментарий от thomasbug

оккупировав главный поток залочит UI

Может быть и наоборот: UI залочит всё остальное. Что у ТСа и происходит при сворачивании

XMs ★★★★★
()
Ответ на: комментарий от Speed_nik

Сделай для начала echo клиент/сервер с твоим типовым пэйлоадом и с ним играйся, в идеале, без культей. Для начала без очереди сообщений совсем, просто один запрос ответ пинг понг. Когда там добьёшься нужного времени отклика, ищи разницу со своей реализацией или усложняй echo конфиг пока он тоже не начнёт лагать.

В общем и целом держать сервер на десктопе где не все ядра отданные ему заняты им безраздельно - лотерея если хочется в лэйтенси. Не должно быть переключений контекста с другими процессами как минимум.

Вылетов нет

Имеются в виду не падения, а процент вылетов времён отклика из математического ожидания.

pon4ik ★★★★★
()

есть зависимость от взаимодействия с рабочим столом (сворачивание окон)

А без этого темп держится или нет?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Если на ядре запущен ещё один планировщик кроме FIFO и есть активно работающие процессы - то почему бы и нет?

1.6ms это ещё мало, я как-то замерял, у меня получилось что до 12ms можно курить в такой конфигурации и это без DE и с почти всеми спящими остальными процессами. А 1.6ms это целевая лэйтенси, читай внимательней, вылеты идут по 50-200ms. Больше похоже на то, что кто-то буфер сокета забивает где то или на всякие инверсии приоритетов, ну или просто сеть кал.

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от pon4ik

Если на ядре запущен ещё один планировщик кроме FIFO и есть активно работающие процессы - то почему бы и нет?

Если все процессоры заняты, affinity не поможет. Если есть свободные процессоры, переброска нити на другой процессор не даст задержку в 1.6мс.

у меня получилось что до 12ms можно курить в такой конфигурации

И причем здесь affinity?

А 1.6ms это целевая лэйтенси, читай внимательней, вылеты идут по 50-200ms.

Улучшать целевую латентность в 1.6мс за счет affinity - так себе идея. Начинать надо с TCP_NODELAY и маленьких клиента с сервером. Очевидно, что задержки в десятки миллисекунд - это какой-то В/В. Вопрос только в том, имеют эти задержки внутреннюю или внешнюю природу - например, манипуляции окнами на фреймбуфере могут загрузить вообще всё.

А по-хорошему, если такие требования к задержкам, надо использовать UDP.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

При том, что надо хотя бы освободить ядра на которых крутится mission critical код для начала. Само переключение на другое ядро не даст задержки такой. А вот ожидание свободного ядра при вытесняющем планировании может дать и по-более и будет зависеть от погоды на Марсезагруженности системы. Может причина и не в этом, но минус одна переменная это всегда хорошо. А в этом, она сильно чаще, чем кажется.

Короче, согнать другие процессы включая init с тех ядер, на которых выполняется целевое решение нужно. А не affinity потоков своих наяривать.

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Интересно. А где по-нормальному (в контексте описаной ТС проблемы) должен делаться замер времени? И какими вызовами/средствами?

thomasbug
()
Ответ на: комментарий от pon4ik

А вот ожидание свободного ядра при вытесняющем планировании может дать и по-более и будет зависеть от погоды на Марсезагруженности системы.

О чем и речь. Но с этим борются приоритетами.

Короче, согнать другие процессы включая init с тех ядер, на которых выполняется целевое решение нужно.

Время таких мер еще не пришло - 200мс этим не объяснишь.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

200мс если куча хрени работает теоретически может быть, но согласен, маловероятно. Вот 50 - запросто с de как мне кажется, даже мыслей небыо никогда замерять что-то под таким конфигом:)

pon4ik ★★★★★
()
Ответ на: комментарий от thomasbug

А где по-нормальному (в контексте описаной ТС проблемы) должен делаться замер времени? И какими вызовами/средствами?

Я бы делал на передающем и приемном концах. Пронумеровать сообщения и смотреть дельты. Или даже сделать перед началом колхоз-синхронизацию времени (по UDP, естественно).

И какими вызовами/средствами?

С целевой задержкой 1.6мс подойдет примерно всё. gettimeofday, например.

tailgunner ★★★★★
()
Ответ на: комментарий от Speed_nik

Это хорошо. Значит, нужно писать минимальный сценарий воспроизведения. Без изысков - send, poll, TCP_NODELAY.

tailgunner ★★★★★
()
Ответ на: комментарий от thomasbug

По хорошему - везде, нужен просто профиль работы приложения. Но, дёшево(быстро) это можно сделать только сэмплерным профайлером. А он сам привносит издержки да и точности скорее всего будет маловато.

А инструментировать код, да ещё и эффективно задача определённого времени. Но, кмк, те же 200мс можно увидеть и в профиле от того же oprofile, только смотреть надо будет очень внимательно и сопоставлять таймштампы пиков.

pon4ik ★★★★★
()

Кстати, а ты сетевые дампы смотрел? Как минимум, если там тоже отражается задержка, можно использовать таймштампы пакетов с задержкой, что бы сопоставлять их с таймштампами других событий которые вызывают подозрение.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

В данном случае я не вижу преимуществ. Содержимое пакета всё равно определяем мы, почему не положить в него время? Тем более, если использовать колхоз-синхронизацию времени. SO_TIMESTAMPING нужен, когда в протокольный payload невозможно впихнуть время.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от Speed_nik

Процессы перебрасывает с помощью sched_setaffinity

Выстави affinity иниту в начале загрузки.

О, или проверь, есть ли в Astra опция ядра isol_cpus (если тебе доступно изменение конфигурации загрузчика).

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от Speed_nik

Надо все остальные процессы в системе согнать с ядер на которых планируется выполнять твой процесс. Я обычно делаю это с помощью ps и taskset. Это не атомарно, но атомарного решения тут в принципе нет. Если потом, вдруг кто-то и остался висеть на нужных ядрах их можно нагрепать и согнать ещё раз.

Ешё, можно заморочиться наверное и на старте пускать init через taskset.

pon4ik ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.