• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ets_timer_arm_new vs sys_timeout

Apollo

New member
Привет всем.

Народ, подскажите, пож-та, в чем разница в реализации таймеров между core (ets_timer_arm_new) и lwip (sys_timeout)?

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

А так же хочется знать, чем отличается реализация tcp-стека core (espconn.h) от lwip. И почему заголовки lwip вообще не поставляются в составе Espressif IoT SDK? :)

Заранее благодарю за ответ.
 

pvvx

Активный участник сообщества
Какие-то странные вопросы. :)
Похоже не изучены основы, а беретесь сразу за верхи.
ets_timer_arm_new - это управление программным таймером на основе аппаратного. _new по причине что у аппаратного таймера переключают делитель на счет в us. У ROM-BIOS ets_timer_arm() расчет идет на другой делитель в аппаратном таймере. Процедуры ets_timer_arm создают добавляют в связный список новый программный таймер и вычисляет задержку до срабатывания следующего программного таймера и записывают её в регистр alarm аппаратного таймера. Когда будет работать процедура ets_run(), то она определит срабатывание alarm у аппартного таймера и вызовет код вашего программного таймера... Это упрощенно.
У Lwip нет таймеров. Ему при старте система назначает отрабатывать его процедуру каждые 25ms через программный таймер. Эта процедура опрашивает состояния соединений и т.д. и у неё свои программные счетчики. В режиме wifi sleep LIGHT китайцы увеличивают этот таймер в сотни раз и Lwip не может правильно работать - у него возникают переполнения в TCP стеке и т.д..
 

pvvx

Активный участник сообщества
А так же хочется знать, чем отличается реализация tcp-стека core (espconn.h) от lwip. И почему заголовки lwip вообще не поставляются в составе Espressif IoT SDK? :)
В первую и главную очередь у espconn отличия в глючности - это же китай-код от Espressif :) Является нагромождением над Lwip для большего потребления памяти при обработке соединений, увеличения времени исполнения вашего кода, введения ограничений по массе параметров управления соединениями и служит для увеличения размера прошивки. Lwip же глюков не имеет... Вот Espressif и добавил espconn, а Lwip хидеры закрыл.
espconn - это подобие упрощения работы с Lwip. Было создано китайцами в надежде скрыть, что в нутре находится Lwip, на первых стадиях, когда все их либы были закрыты...
 
Последнее редактирование:

Apollo

New member
Какие-то странные вопросы. :) Похоже не изучены основы, а беретесь сразу за верхи.
Возможно, вы правы. Было бы прекрасно увидеть ссылки на основы, которые бы проливали свет на "странные вопросы" :)

... Это упрощенно.
Это было понятно. По-сути, это следует из API. В принципе, и то, что обработка таймерного колбека производится не в прерывании, тоже просматривается.

У Lwip нет таймеров.
Вы имеете ввиду в таймерах lwip не используются аппаратные таймеры? Потому что таймеры как таковые там есть, см. lwip/timers.h (функции sys_timeout & sys_untimeout).

[На правах офтопа] Китайский таймерный API, как это ни странно, эффективнее lwip-шного, т.к. не требует динамического распределения памяти внутри процедуры установки таймера; временем жизни контекста таймера управляет клиент. Поскольку кол-во таймеров зачастую определяется в дизайн-тайм, то достаточно статического распределения памяти.
 

Apollo

New member
espconn - это подобие упрощения работы с Lwip. Было создано китайцами в надежде скрыть, что в нутре находится Lwip, на первых стадиях, когда все их либы были закрыты...
Понятно. Спасибо! А с API lwip такая беда: как клиент, я не имею возможности зарядить операцию recv, следовательно, не имею возможности управлять памятью, в которую данные должны быть записаны. lwip распределяет память самостоятельно, вызывая колбек с... одним-двумя байтами в посылке (пишу telnet сервер, данные приходят практически посимвольно), и, вместо того, чтобы скользить по буферу, заряжая в recv смещенные указатели, приходится накапливать данные в отдельном буфере. Для моих задач некритично, конечно, но в принципе, неоптимально.
 

pvvx

Активный участник сообщества
Вы имеете ввиду в таймерах lwip не используются аппаратные таймеры? Потому что таймеры как таковые там есть, см. lwip/timers.h (функции sys_timeout & sys_untimeout).
Это больше задание и изменение счетчиков для основной процедуры вызываемой у Lwip по таймеру ETSTimer check_timeouts_timer назначенной при старте SDK и вызывающей void sys_check_timeouts(void).
Пример в моем meSDK ->
https://github.com/pvvx/esp8266web/blob/master/app/sdklib/system/app_main.c#L581
https://github.com/pvvx/esp8266web/blob/master/app/sdklib/lwip/core/timers.c#L374
Никакого отношения к API... NO_SYS

Китайский таймерный API, как это ни странно, эффективнее lwip-шного, т.к. не требует динамического распределения памяти внутри процедуры установки таймера; временем жизни контекста таймера управляет клиент. Поскольку кол-во таймеров зачастую определяется в дизайн-тайм, то достаточно статического распределения памяти.
Lwip не низкий уровень управления аппаратурой (не драйвер hard уровня), или не ROM-BIOS, или не ...
Что за "дизайн-тайм, то достаточно статического распределения памяти."? :confused:
Разжевывать каждую процедуру невозможно - на это потребуется посвятить всю жизнь :p
Я вам и говорю - вы зашли не с того уровня. На MCU такого класса как ESP8266 нет понтов уровней API и прочих абстракций. На них элементарно не хватает ресурсов. По этому всякие Ардуино и прочие проекты оперирующие высокими уровнями обречены на провал.
Как пример - классический TCP сокет должен иметь от 160 килобайт памяти RAM (сумма с TCP стеком) - это чисто требования для полного обслуживания по TCP. Их нет у ESP8266 и приходиться переходить к не классической схеме написания ПО, по методу "свалки" - всё подряд в единой куче. Более похоже на "патч". По этому, если вы размышляете на уровне API и прочей абстракции - ничего хорошего не выйдет.
В моих проектах на базе meSDK espconn вырезан из библиотек, как часть другого никчемного китай-кода расходующего память...
 
Последнее редактирование:

pvvx

Активный участник сообщества
Понятно. Спасибо! А с API lwip такая беда: как клиент, я не имею возможности зарядить операцию recv, следовательно, не имею возможности управлять памятью, в которую данные должны быть записаны. lwip распределяет память самостоятельно, вызывая колбек с... одним-двумя байтами в посылке (пишу telnet сервер, данные приходят практически посимвольно), и, вместо того, чтобы скользить по буферу, заряжая в recv смещенные указатели, приходится накапливать данные в отдельном буфере. Для моих задач некритично, конечно, но в принципе, неоптимально.
Lwip всё делает правильно. По другому представляется сложнее. TCP - это вам не UART. :) Это блочный драйвер, а не последовательный. :p
Он нормально кеширует ваши данные хоть побайтно и имеет процедуры доступа к ним в своем буфере, так-же и все процедуры управления этими буферами... Через espconn это невозможно, и она дублирует эти буфера в блоках heap...
 

Apollo

New member
Ой, огромное вам спасибо за исходники sdk. Признаться, не ожидал их увидеть в публичном доступе :) Поэтому даже не делал попытки поискать. Еще раз спасибо.

Lwip не низкий уровень управления аппаратурой (не драйвер hard уровня), или не ROM-BIOS, или не ...
Что за "дизайн-тайм, то достаточно статического распределения памяти."? :confused:
PS: Ваши аргументы понятны, я не стараюсь их оспорить, я о другом. Попробую пояснить. API и уровнь абстрации - вещи несвязанные, аппаратные регистры, конфигурирующие тот или иной железный модуль - тоже API. А вот библиотека lwip - уже уровнь абстракции, скрывающий эти железные потроха. И у этой библиотеки еcть свой API. Он может позволять писать эффективный код, а может и не позволять этого делать. В частности, то, что этот API не позволяет клиенту управлять памятью, предназначенной для приема данных - это большой минус, препятствующий написанию эффективного кода, ибо невозможно сделать zero-copy процедуру приема и обработки данных, плюс клиенту необходимо подчищать динамически выделенные на стороне библиотеки блоки памяти. Каждая аллокация - это поиск подходящего блока памяти, фрагментация памяти. Зачем это делать частью API? Вовсе необязательно.

PPS: Кстати, посмотрел реализацию systimeout - ну точно, контекст таймера аллокируется динамически :) Дизайн-тайм - это время разработки (до компиляции и запуска), на этом этапе разработчик может принять решение, в частности, о том, как будут созданы те или иные объекты его программы, они могут быть статические, либо распределены динамически. При этом число и время жизни некоторых объектов может быть известно точно и эти объекты можно сделать статическими. В подавляющем большинстве случаев, к ним относится и таймер.
 

pvvx

Активный участник сообщества
Ой, огромное вам спасибо за исходники sdk. Признаться, не ожидал их увидеть в публичном доступе :) Поэтому даже не делал попытки поискать. Еще раз спасибо.
Это не исходники - это мой реверс (дизассемблирование и перевод в СИ). Часть, Lwip, выкладывалась китайцами, но в непотребном виде - без заголовков и трасляцией только с выключенными всеми варнингами - только так и пишут в Espressif (от этого встречается масса неинициализированных указателей и уже более года лапатят свои баги в SDK с тысячной аудиторией проверки - у меня Lwip доделан для нормальной трансляции...
В подавляющем большинстве случаев, к ним относится и таймер.
Таймер в ROM-BIOS с динамическим распределением. Какая статика, если открыто сотня TCP портов и к ним назначены свои таймеры в пользовательском коде? Держать вечно забитую bss память? bss вычитает из heap и по тому безразлично, если только не пользуетесь чистым китайским SDK. У них распределитель памяти отжирает на заголовки более чем в два раза больше чем в моем meSDK - чистая встроенная китай-фича (просто взяли добавили для понту - чтобы было неповадно :) ), т.к. исходники менеджера памяти из одного колодцу... :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
В частности, то, что этот API не позволяет клиенту управлять памятью, предназначенной для приема данных - это большой минус, препятствующий написанию эффективного кода, ибо невозможно сделать zero-copy процедуру приема и обработки данных, плюс клиенту необходимо подчищать динамически выделенные на стороне библиотеки блоки памяти. Каждая аллокация - это поиск подходящего блока памяти, фрагментация памяти. Зачем это делать частью API? Вовсе необязательно.
Есть другое более лучшее решение?
Остальные (малые TCP стеки) используют статическое распределение памяти и на них ничего не сделать. По тому я в корне с вами не согласен заменять динамическую на статическую... Тем более исходники Lwip даны. Как при этом обслужить хоть эти одновременные 63 соединения в секунду в Web-свалке? -> Кол-во и скорость открытия множественных Web соединений (JMeter)
Взять так и зарезервировать на начальном этапе 63*ОкноTCP стека (в базе TCP_WND = 4*TCP_MSS = 1460*4 байт)? У ESP всего после "обгрызанного" китай кода основных библиотек остается до 50 килобайт на всё про всё и стеку не желательно отъедать более 2 кило (с вычетом под SDK) - затирает данные ROM-BIOS.
Не нравиться - рассмотрите этот модуль Убийцы ESP8266: Часть 2 - Nufront NL6621, но там тоже Lwip, но памяти больше и т.д..
 
Последнее редактирование:
Сверху Снизу