Скорость порта не сходится с итоговой скоростью чтения

Добрый день.
Пытаюсь выжать максимум из rs485 , но получается что реальная скорость опроса , не совпадает с расчетной.
Сетап:
6 реле WB (разные)
Контроллер orange pi (долго ждал в том году когда появятся WB-шные, в итого пришлось делать без него)
CH340 USB-Rs485 адаптер
Опрос через самописный аналог wb-mqtt-serial (оригинальный не захотел вставать на orange, да и лицензия не позволят вроде как)
Скорость 115200

Проблема:
Ожидание: за секунду трафик по шине составит примерно 115200/8*0,92 ~ 13КБ
Факт: 2.4КБ

Суть вопроса:
Есть ли такая проблема при использовании контроллера WB?
Какие задержки при ответе у реле WB?
Где кроется причина такого поведения (USB-адаптер, задержки реле, особенности шины, или тормоза программы)

Дополнительная информация
Задержка ответа в настройках реле = 0
Прошивка 1.20.0
“Поток” опроса на на 92% висит в функциях Read и Write
Никаких ошибок при опросе не возникает
Осциллографа нет - посмотреть что происходит на шине нет возможности.
программа опроса на .net 6, понятно что есть свой оверхед, но его тоже вполне можно оценить - программа грузит одно ядро процессора на 30% - часть из них может быть в методах Read/Write даже если уменьшим ожидания на 30% все равно разница в разы.
На полноценном компе наблюдается аналогичная картина (правда устройство опрашиваю не wb - а китайский датчик), и заметил , что время в методах read/write в основно зависит не от трафика, а от количества запросов к устройству.
По вышеописанным причинам - очень сомневаюсь что проблема в производительности программы, и сильно подозреваю ch340 адаптер.
Очень интересно, кто-нибудь проводил аналогичные замеры и встречал ли аналогичные проблемы?

ps
По большому счету опрос выключателей 15 раз в секунду происходит (чего в общем достаточно), но планирую еще добавить пару реле в щиток, датчики wb-шные универсальные, еще 2 комплекта для защиты от протечек, - т.е. линии станут длинными а не внутри щитка, хотелось бы побольше запаса.

А что такое 0,92?
Ну и не учитываете, наверно, 3,5 байта тишины после каждой посылки.

Пример:

export DEV_ADDR=98
root@wirenboard-AGH767IU:~# export DEV_PORT=/dev/ttyRS485-1
time for i in {0..200}; do echo "count $i $(modbus_client -mrtu -pnone -b115200 -s2 $DEV_PORT -a$DEV_ADDR -t0x03 -r128)"; done
#cut
count 189 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 190 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 191 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 192 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 193 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 194 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 195 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 196 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 197 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 198 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 199 SUCCESS: read 1 of elements:
	Data: 0x0062 
count 200 SUCCESS: read 1 of elements:
	Data: 0x0062 

real	0m3.050s
user	0m0.870s
sys	0m1.194s

3.05/200 = 0.015
15мс на запрос, в среднем,

time modbus_client --debug -mrtu -pnone -b115200 -s2 $DEV_PORT -a$DEV_ADDR -t0x03 -r128
Opening /dev/ttyRS485-1 at 115200 bauds (N, 8, 2)
[62][03][00][80][00][01][8C][71]
Waiting for a confirmation...
<62><03><02><00><62><FD><A5>
SUCCESS: read 1 of elements:
	Data: 0x0062 

real	0m0.025s
user	0m0.002s
sys	0m0.015s

8+3,5 байт отправлено 7+3,5 принято.
Байт в теории передается за 87 мкС, с двумя стопбитами.

Точно нет. Он не вносит (не может) сколько-либо заметных задержек.

рекомендую Быстрый Modbus ⚡ — Wiren Board
“событийная” модель, она лучше для большого количества устройств. Ну и приоритеты, если на быстрый переходить не хотите. То есть планировщик опроса обязан опросить все приоритетные регистры именно в текущем цикле.

даже примем 11 бит на байт (95мкс)
8+3,5+7+3,5 = 22 байта
2211 =242 бита
242/115200
1000=2.1 мс
тест выше с modbus_client дал 15 мс на запрос. тут даже больше чем у меня получилось.
тест наверно не очень честный - запуск процесса тоже время добавит. но даже если взять user время или из 3,05 вычесть user и sys - можно предположить что 0,8 сек на отправку - все равно выходит 4 мс. против 2мс расчетных (2 мс оверхед меньше чем получился у меня, но это только ограничение снизу - т.е. оверхед не меньше 2мс)
Может можно какую то статистику собрать с wb-mqtt-serial?

Запустил у себя такой же тест.
image
но не очень понимаю как трактовать результаты

0,92 - это процент времени, который поток опроса проводит в методах read\write.
умножал так как цифры все приводил из расчета в секунду

попробую чуть аккуратней посчитать и без магических коэффициентов
(статистика собирается каждые 5 секунд)
время проведенное в методах read\write 4,6221787 сек. (засыпания потока чтоб выдержать паузу сюда не входят)
количество команд на чтение 629
количество данных в ответах на чтение 3295 байт
запрос чтения 8 байт, ответ устройства 6 байт + данные. плюс тишина 3.5 (когда засыпает мастер - это не входит в read\write операции)
получаем за 629*(8+6 + 3.5) + 3295 = 14302,5 байт
в битах получим 14302,5 * 11 = 157327,5
из расчета 115200 должно получится 1,36 секунд.
факт ~4,6сек. теряется где то 5мс на каждом запросе.

stat
(время time_serila_write_time - запись, time_serila_read_time - чтение. write минимальный, потому как скорей всего данные идут в буфер и управление возвращается. и ждем уже на функции read. чтение + запись + формирование ответа time_nmodbus_read - чуть больше чем read+write)

Спасибо за ответ. Попробую конечно “быстрый модбас”, пока не уперся еще в лимиты, этот вопрос скорее не практический а теоретический. быстрый модбас же тоже будет работать быстрее если не будет теряться 5мс на каждом запросе.
Ну и неплохо бы иметь понимание - спасет ли меня (в случае если упрусь в лимиты) переход на контроллер wb (и за одно не тратить силы на собственную реализацию.)

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

Делал. довольно давно год назад, но с тех пор в этой части изменений не было. Примерно 3мс занимает опрос одного регистра на 115200 с помощью wb-mqtt-serial. И быстрей передать-принять уже не получалось

Задача-какая? Скажем так, я удачно опрашивал ~50 регистров с гарантированым временем 100мс. То есть механизм работы планировщика такой: он сортирует таблицу регистров шины с “весами” () времени до очередного опроса, те что пора опрашивать - отдает на опрос, если остается время - опрашивает и “неприоритетные”.

                            // Период чтения данного канала в миллисекундах
                            // Рекомендуется использовать для каналов, данные от которых надо получать с минимальными задержками
                            // Чтение каналов с заданным периодом имеет больший приоритет, чем чтение других каналов
                            // Если не указан, чтение будет производиться в свободное от опроса других каналов время
                            "read_period_ms": 10,

На контроллере, кстати - уже есть и вывод в debug и метрики.

А хотите получить доступ к самому новому ПО и железу? Ну и возможность добавлять новые фичи. Нам постоянно нужны хорошие программисты. Приходите к нам работать!

Вот наверно этого ответа я ждал. 3мс это близко к расчетному времени.

Дело судя по всему все таки в USB-rs485 преобразователе. написал тест и C#, на C++ результаты сходятся (на винде пробовал, тащить это на контроллер лень очень было). и на китайском датчике 24мс на чтение против 14 расчетных. - стало быть замеры на WB устройствах у меня корректны.
как-нибудь еще попробую с UART-rs485 конвертором…

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

Спасибо и хорошего дня.

Не пожалейте немного денег - и возьмите анализатор. Например (первая попавшаяся ссылка) https://www.ozon.ru/product/usb-saleae-24m-8ch-logicheskiy-analizator-24m-8ch-s-buferizatsiey-podderzhka-1-1-16-1290378694
Это клон известного “Sigrok”. Можно подключить прямо на шину RS485 - и видеть что в ней реально происходит.

Ну, вполне вероятно, так как сам чип по факту имеет внутренний буфер и делает между байтами “паузы”. Вот тут например рассматривали