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

in-flight buffer credits #171

Merged
merged 7 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:

- name: Install AsyncTCP (ESP32)
if: ${{ matrix.core == 'esp32:esp32' }}
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/mathieucarbou/AsyncTCP#v3.2.15
run: ARDUINO_LIBRARY_ENABLE_UNSAFE_INSTALL=true arduino-cli lib install --git-url https://github.com/mathieucarbou/AsyncTCP#v3.3.0

- name: Install ESPAsyncTCP (ESP8266)
if: ${{ matrix.core == 'esp8266:esp8266' }}
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ lib_deps = mathieucarbou/ESPAsyncWebServer @ 3.4.0

**Dependencies:**

- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.2.15`
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.15](https://github.com/mathieucarbou/AsyncTCP/releases)
- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.3.0`
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.3.0](https://github.com/mathieucarbou/AsyncTCP/releases)

- **ESP32 with AsyncTCPSock**: `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`

Expand All @@ -99,7 +99,7 @@ AsyncTCPSock can be used instead of AsyncTCP by excluding AsyncTCP from the libr
lib_compat_mode = strict
lib_ldf_mode = chain
lib_deps =
; mathieucarbou/AsyncTCP @ 3.2.15
; mathieucarbou/AsyncTCP @ 3.3.0
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
mathieucarbou/ESPAsyncWebServer @ 3.4.0
lib_ignore =
Expand All @@ -116,7 +116,7 @@ Performance of `mathieucarbou/ESPAsyncWebServer @ 3.4.0`:
> autocannon -c 10 -w 10 -d 20 http://192.168.4.1
```

With `mathieucarbou/AsyncTCP @ 3.2.15`
With `mathieucarbou/AsyncTCP @ 3.3.0`

[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)

Expand Down
8 changes: 4 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ lib_deps = mathieucarbou/ESPAsyncWebServer @ 3.4.0

**Dependencies:**

- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.2.15`
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.2.15](https://github.com/mathieucarbou/AsyncTCP/releases)
- **ESP32 with AsyncTCP**: `mathieucarbou/AsyncTCP @ 3.3.0`
Arduino IDE: [https://github.com/mathieucarbou/AsyncTCP#v3.3.0](https://github.com/mathieucarbou/AsyncTCP/releases)

- **ESP32 with AsyncTCPSock**: `https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip`

Expand All @@ -99,7 +99,7 @@ AsyncTCPSock can be used instead of AsyncTCP by excluding AsyncTCP from the libr
lib_compat_mode = strict
lib_ldf_mode = chain
lib_deps =
; mathieucarbou/AsyncTCP @ 3.2.15
; mathieucarbou/AsyncTCP @ 3.3.0
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
mathieucarbou/ESPAsyncWebServer @ 3.4.0
lib_ignore =
Expand All @@ -116,7 +116,7 @@ Performance of `mathieucarbou/ESPAsyncWebServer @ 3.4.0`:
> autocannon -c 10 -w 10 -d 20 http://192.168.4.1
```

With `mathieucarbou/AsyncTCP @ 3.2.15`
With `mathieucarbou/AsyncTCP @ 3.3.0`

[![](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)](https://mathieu.carbou.me/ESPAsyncWebServer/perf-c10.png)

Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
{
"owner": "mathieucarbou",
"name": "AsyncTCP",
"version": "^3.2.15",
"version": "^3.3.0",
"platforms": "espressif32"
},
{
Expand Down
6 changes: 3 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ lib_deps =
; bblanchon/ArduinoJson @ 5.13.4
; bblanchon/ArduinoJson @ 6.21.5
bblanchon/ArduinoJson @ 7.2.1
mathieucarbou/AsyncTCP @ 3.2.15
mathieucarbou/AsyncTCP @ 3.3.0
board = esp32dev
board_build.partitions = partitions-4MB.csv
board_build.filesystem = littlefs
Expand All @@ -49,7 +49,7 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
; board = esp32-s3-devkitc-1
; board = esp32-c6-devkitc-1
lib_deps =
mathieucarbou/AsyncTCP @ 3.2.15
mathieucarbou/AsyncTCP @ 3.3.0

[env:arduino-310]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
Expand Down Expand Up @@ -102,7 +102,7 @@ board = ${sysenv.PIO_BOARD}
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
board = ${sysenv.PIO_BOARD}
lib_deps =
mathieucarbou/AsyncTCP @ 3.2.15
mathieucarbou/AsyncTCP @ 3.3.0

[env:ci-arduino-310]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip
Expand Down
4 changes: 4 additions & 0 deletions src/WebResponseImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class AsyncBasicResponse : public AsyncWebServerResponse {

class AsyncAbstractResponse : public AsyncWebServerResponse {
private:
// amount of responce data in-flight, i.e. sent, but not acked yet
size_t _in_flight{0};
// in-flight queue credits
size_t _in_flight_credit{2};
String _head;
// Data is inserted into cache at begin().
// This is inefficient with vector, but if we use some other container,
Expand Down
31 changes: 31 additions & 0 deletions src/WebResponses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,21 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, u
request->client()->close();
return 0;
}
// return a credit for each chunk of acked data (polls does not give any credits)
if (len)
++_in_flight_credit;

// for chunked responses ignore acks if there are no _in_flight_credits left
if (_chunked && !_in_flight_credit) {
#ifdef ESP32
log_d("(chunk) out of in-flight credits");
#endif
return 0;
}

_ackedLength += len;
_in_flight -= (_in_flight > len) ? len : _in_flight;
// get the size of available sock space
size_t space = request->client()->space();

size_t headLen = _head.length();
Expand All @@ -364,16 +378,31 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, u
String out = _head.substring(0, space);
_head = _head.substring(space);
_writtenLength += request->client()->write(out.c_str(), out.length());
_in_flight += out.length();
--_in_flight_credit; // take a credit
return out.length();
}
}

if (_state == RESPONSE_CONTENT) {
// for response data we need to control the queue and in-flight fragmentation. Sending small chunks could give low latency,
// but flood asynctcp's queue and fragment socket buffer space for large responses.
// Let's ignore polled acks and acks in case when we have more in-flight data then the available socket buff space.
// That way we could balance on having half the buffer in-flight while another half is filling up, while minimizing events in asynctcp q
if (_in_flight > space) {
// log_d("defer user call %u/%u", _in_flight, space);
// take the credit back since we are ignoring this ack and rely on other inflight data
if (len)
--_in_flight_credit;
return 0;
}

size_t outLen;
if (_chunked) {
if (space <= 8) {
return 0;
}

outLen = space;
} else if (!_sendContentLength) {
outLen = space;
Expand Down Expand Up @@ -422,6 +451,8 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest* request, size_t len, u

if (outLen) {
_writtenLength += request->client()->write((const char*)buf, outLen);
_in_flight += outLen;
--_in_flight_credit; // take a credit
}

if (_chunked) {
Expand Down
Loading