mirror of
https://github.com/me-no-dev/ESPAsyncWebServer.git
synced 2025-08-05 21:54:38 +02:00
Merge pull request #171 from mathieucarbou/buffcredit
in-flight buffer credits
This commit is contained in:
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -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' }}
|
||||
|
@@ -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`
|
||||
|
||||
@@ -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 =
|
||||
@@ -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)
|
||||
|
||||
|
@@ -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`
|
||||
|
||||
@@ -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 =
|
||||
@@ -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)
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
{
|
||||
"owner": "mathieucarbou",
|
||||
"name": "AsyncTCP",
|
||||
"version": "^3.2.15",
|
||||
"version": "^3.3.0",
|
||||
"platforms": "espressif32"
|
||||
},
|
||||
{
|
||||
|
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
|
Reference in New Issue
Block a user