Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase max LWIP sockets on ESP32-S3 #6021

Merged
merged 1 commit into from
Feb 14, 2022
Merged

Increase max LWIP sockets on ESP32-S3 #6021

merged 1 commit into from
Feb 14, 2022

Conversation

anecdata
Copy link
Member

@anecdata anecdata commented Feb 11, 2022

This PR changes the max socket limit from 4 to 8, implementing one of the improvements enabled by the 192KB increase in internal SRAM in the ESP32-S3 compared to the ESP32-S2, as discussed in issue #5915.

Sockets are memory-intensive, and memory use appears to be somewhat non-linear, and somewhat variable based on the socket use.

ESP32-S2

On ESP32-S2 (Adafruit CircuitPython 7.2.0-alpha.2 on 2022-02-11; ESP32-S2-DevKitC-1-N4R2 with ESP32S2), fresh memory stats on reset are:

         espidf.heap_caps_get_*:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S2               118784       133472        158404        2046880

Launching code.py and connecting to wifi brings IDF memory down to:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S2                63488        78296        158404        2008080

With a max socket limit of 4 on ESP32-S2 (TLS connections each use two sockets), a first TLS connection brings the memory down to:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S2                21504        42508        158404        1999376

and adding a second simultaneous TLS connection bring the memory down to:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S2                 4608         9872        158404        1990832

Pretty slim margin, but it works. It is possible to run out of IDF memory with two TLS connections, resulting in memory exception (or sometimes an OSError: Failed SSL handshake, which can arise when there's not enough memory to complete the certificate transaction).

ESP32-S3 baseline

On ESP32-S3 (Adafruit CircuitPython 7.2.0-alpha.2 on 2022-02-11; ESP32-S3-DevKitC-1-N8R2 with ESP32S3), fresh memory stats on reset are:

         espidf.heap_caps_get_*:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S3               225280       299836        333708        2046880

Launching code.py and connecting to wifi brings IDF memory down to:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S3               225280       242012        333708        2007440

Sequential stats after running one, then two, simultaneous TLS sockets, as above:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S3               196608       206272        333708        1998736
ESP32-S3               163840       173492        333708        1990192

Plenty of headroom.

ESP32-S3 with PR

On ESP32-S3 with PR (Adafruit CircuitPython 7.2.0-alpha.2-8-gddac37add-dirty on 2022-02-11; ESP32-S3-DevKitC-1-N8R2 with ESP32S3), fresh memory stats on reset are:

         espidf.heap_caps_get_*:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S3               221184       292232        326460        2046896

Launching code.py and connecting to wifi brings IDF memory down to:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S3               221184       234412        326460        2015968

Now, on the modified ESP32-S3 ,

Allowing up to 8 sockets (or 4 TLS connections), sequential stats after each TLS connection is running are as follows:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
ESP32-S3               192512       200396        326460        2007120
ESP32-S3               159744       167636        326460        1998768
ESP32-S3               131072       136760        326460        1989312
ESP32-S3                96256       102528        326460        1980880

Still an order of magnitude more headroom than in the ESP32-S2 case, and uses only about half of the 192KB increase in internal SRAM, leaving room for other features such as increasing the CIRCUITPY_PYSTACK_SIZE.

Much like with CircuitPython heap memory, users will need to balance the use of IDF memory between any aggressive uses such as these increased socket connections, larger numbers of wifi AP connections, and perhaps some memory-intensive BLE features in the future.

@anecdata anecdata added esp32-s3 espressif applies to multiple Espressif chips labels Feb 12, 2022
@anecdata
Copy link
Member Author

anecdata commented Feb 12, 2022

I don't have an ESP32-S3 without external PSRAM. I would not expect that you could run many sockets with only internal RAM for everything, but can someone who has one of those boards please test that this PR does no harm?

edit: n/m, realized the N8 build will work on the N8R* board(s). Results:

ESP32-S3 N8 Baseline

Using alpha release:
Adafruit CircuitPython 7.2.0-alpha.2 on 2022-02-11; ESP32-S3-DevKitC-1-N8 with ESP32S3:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
REPL after reset:
                        58368       123548        335004         173856
After wifi connect:
                        50176        92940        335004         134384
After 1st TLS connection:
                        50176        58932        335004         125488
After 2nd TLS connection:
                        20992        26128        335004         117168

On 3rd TLS connection attempt: RuntimeError: Out of sockets

ESP32-S3 N8 Regression Test

Using PR artifact:
Adafruit CircuitPython 7.2.0-alpha.2-10-g676229822 on 2022-02-11; ESP32-S3-DevKitC-1-N8 with ESP32S3:

         largest_free_block()  free_size()  total_size()  gc.mem_free()
REPL after reset:
                        50176       113508        334732         173856
After wifi connect:
                        50176        92668        334732         134384
After 1st TLS connection:
                        47104        56948        334732         125680
After 2nd TLS connection:
                        19968        24188        334732         117120

On 3rd TLS connection attempt: espidf.MemoryError:

A couple of KB difference (still better than ESP32-S2 N4R2). I suspect there are some socket-related pre-allocations in the IDF.

Addendum: Memory stats above are a bit of a worst case in socket creation. Each TLS socket above is actually two sockets with ssl wrapper, connected to a server. Simply creating a bare unconnected TCP socket uses only ~400 bytes.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@tannewt tannewt merged commit fd4164f into adafruit:main Feb 14, 2022
@anecdata anecdata deleted the more_sockets branch February 14, 2022 18:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
esp32-s3 espressif applies to multiple Espressif chips
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants