Добрый день, уважаемый читатель! В одной из прошлых статей я рассказывал о библиотеке Mbed TLS, которая служит для создания шифрованных соединений на ESP32.
В конце статья я упомянул о том, что некоторые настройки этой библиотеки напрямую влияют на расход оперативной памяти при установке TLS-соединений. В справочной системе к ESP-IDF даже приведена таблица, иллюстрирующее это влияние:
Я решил самостоятельно провести аналогичные тесты на пробном проекте в разных режимах работы:
1. Разные режимы подключения сертификата:
- При загрузке сертификата через буфер
- При использовании глобального хранилища сертификатов
- При использовании встроенного пакета сертификатов
2. Разные способы создания соединения:
- Условно назовём его "старт-стоп", когда "одноразовое" HTTP-соединение инициализируется, выполняется, а затем сразу же удаляется из памяти. В следующем цикле всё повторяем сначала.
- Повторное использование соединения, когда однажды созданное соединение используется вновь и вновь, только меняется url запроса
3. Исследовать будем влияние четырех опций, которые я рассматривал в предыдущей статье:
- mbedTLS v3.x related → Variable SSL buffer length
- mbedTLS v3.x related → Enable serialization of the TLS context structures
- mbedTLS v3.x related → Keep peer certificate after handshake completion
- Using dynamic TX/RX buffer (только в режиме передачи сертификата через буфер)
4. Ну и наконец я проверил влияние версии ESP-IDF на все это:
- ESP-IDF 4.4.3
- ESP-IDF 5.0.0
- ESP-IDF 5.0.1
__________________
Итак, всего у меня получилось ни много ни мало аж 162 варианта настроек, включая 6 вариантов, когда TLS была вообще отключена. Разумеется я не стал перебирать все эти варианты вручную, все делалось полностью автоматически.
На каждый вариант плата успевала отправить 8-10 замеров свободной оперативной памяти, затем плата перешивалась заново, с новыми настройками. На "всё про всё" ушло примерно 2,5 суток машинного времени плюс два вечера на подготовку программы и набора батников для управления всем этим хозяйством.
Как читать таблицы
Ниже будут таблицы с полученными экспериментальными данными, следует понимать их так:
- Первый столбец - режим подключения сертификата: no sll | buffer | global storage | bundle
- Второй столбец - версия ESP-IDF
- Далее идут четыре столбца с опциями Mbed TLS в различных сочетаниях
- Общий размер кучи, доступный вашему приложению
- Пиковый размер занятой кучи при запуске программы перед первым соединением с сервером. Это значение отражает, сколько максимально потребовалось памяти, чтобы установить WiFi-подключение и получить время с SNTP - сервера. От этого значения я отталкивался чтобы оценить, сколько конкретно памяти уходит на TLS + HTTP соединение.
- Далее идут два одинаковых блока, один для одноразового режима, другой для режима повторного использования:
- Перед отправкой запроса - размер занятой памяти непосредственно перед выполнением запроса к серверу. Это значение показывает, сколько памяти остается занятыми через примерно 1 минуту после закрытия предыдущего соединения. То есть после того как запрос был передан и все "устаканилось". Назовем его условно "стабильным расходом". Это значение не учитывает реальный расход памяти непосредственно во время соединения.
- Изм. перед отпр. запр. - увеличение (+) или уменьшение (-) размера занятой памяти перед соединением (пред. пункт) по сравнению с настройками по умолчанию*
- После отправки запроса - тот же замер, но непосредственно после того, как запрос был выполнен. Как правило это значение немного больше первого, но также не учитывает реальный расход памяти непосредственно во время соединения.
- Изм. после отпр. запр. - увеличение (+) или уменьшение (-) размера занятой памяти после соединения (пред. пункт) по сравнению с настройками по умолчанию*
- Максимум расхода памяти за цикл - здесь фиксируется максимальный расход памяти за все время работы МК с момента сброса. Если учитывать, что TLS жрет много памяти, то таким образом мы как раз и можем оценить её пиковый расход при установке TLS-соединения.
- Расход памяти на выполнения запроса - вычитаем из результатов предыдущего пункта значение из столбца 8 (размер занятой памяти до первого соединения) и получаем размер памяти, необходимый для выполнения HTTPS-запроса в выбранном режиме.
- Изм. расхода памяти - увеличение (+) или уменьшение (-) размера используемой памяти (пред. пункт) по сравнению с настройками по умолчанию*. Разумеется, в данном случае минус лучше чем плюс.
*По умолчанию включена опция "Keep peer certificate after handshake completion", именно этот вариант будет первым в таблице в каждом из вариантов. Все сравнения отсчитаны именно от неё.
Предупреждение. Не стоит рассматривать приведенные цифры как абсолютно верные. Иногда данные о свободной памяти могут давать явно кривоватые значения, однако общая тенденция вполне ясна. Для более точных результатов нужно повторить запуск в одном и том же режиме хотя бы 3-5 раз, но такое тестирование вылилось бы в недели.
Итак, поехали... Таблички крупные, поэтому кликайте на них для просмотра в полном размере.
Общие замечания
- Разумеется, в режиме повторного использования соединения требуется больше памяти, так как само HTTP-соединение хоть и закрывается (отключается от сервера), но остается висеть в памяти. В среднем это дает около 2360~2400 "лишних" байт в куче. Именно столько, видимо, и занимает HTTP-соединение, которое остается не удалённым.
- Размер занятой кучи сразу после закрытия соединения стабильно больше того же размера через ~1 минуту к началу следующего сеанса. Значит выделенная память освобождается не все сразу, а постепенно. О чем-то таком я встречал обсуждение на форуме esp32.com, что если очень часто и много выполнять HTTP-запросы, то свободная куча постепенно расходуется, но потом постепенно и освобождается.
- Сразу бросается в глаза, что для ESP-IDF 5.0.0 общий размер доступной кучи стал заметно ниже, по сравнению с версией 4.4.3. Но в ESP-IDF 5.0.1 эту ситуацию исправили, и даже добавили "чуть-чуть" сверху. Видимо, в ESP-IDF 5.0.0 присутствовал какой-то глюк или баг в этом плане, не зря ESP-IDF 5.0.1 так быстро выпустили. Более того, довольно заметно оптимизировали размер потребляемой памяти, потребляемой "в пике" при запуске микроконтроллера, что не может не радовать.
NO SSL
Для начала рассмотрим табличку для режима, когда данные отправлялись на сервер напрямую, в открытом виде:
Из таблицы видно, что пиковый расход памяти без SSL ничем не отличается от пикового расхода до начала первого сеанса связи. Значит дополнительная память на HTTP (без S) соединение если и тратится, то не больше этого пикового значения.
TLS buffer
Подключаем серфтификат через буфер напрямую:
Из таблицы можно понять, что полученные значения в общем и целом соответствуют тому, что говорит нам справка ESP-IDF.
- Использование Using dynamic TX/RX buffer вместе со всеми "вложенными" опциями дает нам лишние ~20000 - 24000 байт памяти, но эта опция не совместима ни с global store, ни с crt bundle.
- Отключение всех опций дает небольшую экономию примерно 3000 - 7000 байт
- Добавление Enable serialization of the TLS context structures к Keep peer certificate after handshake completion, иногда дает прирост потребления, и иногда уменьшение. Но скорее всего это просто случайные погрешности измерения. Ну типа так звезды сошлись.
TLS global store
То же самое, но сертификат был сначала добавлен в глобальное хранилище, из-за чего размер занимаемой памяти, разумеется вырос:
В целом и общем мои выводы тут совпадают с предыдущими, если не считать что в общем памяти нужно немного больше.
TLS bundle
Ну и в заключение подключим готовый пакет из 137 (точнее 138) сертификатов от Mozilla (плюс 1 дополнительный для Lets Encrypt).
Во-первых заметно, что ~360 байт оперативки "отъедается" на обслуживание bundle, хотя он и хранится на flash-памяти.
Во-вторых, интересно, что "стабильный" расход памяти ниже чем в режиме глобального хранилища и приближается к "буферу". Оно и понятно - сертификаты теперь сидят не в оперативной памяти, а на flash.
Размер двоичного файла при этом растет, но не сильно на много - примерно на 60-65 килобайт.
Для чего вот это всё?
Ну хотя бы для того, что бы выбрать правильные опции и режимы работы для вашего проекта в зависимости от необходимой скорости соединения и доступной оперативной памяти.
_______________
На этом пока всё, до встречи на сайте и на dzen-канале!
👍 Понравилась статья? Поддержите канал лайком или комментарием! Каналы на Дзене "живут" только за счет ваших лайков.
📌Подпишитесь на канал и вы всегда будете в курсе новых статей.