Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 1
// SPDX-License-Identifier: LGPL-3.0-or-later
2
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
3
 
4
//
5
// Perf tests
6
//
7
 
8
#include <Arduino.h>
9
#if defined(ESP32) || defined(LIBRETINY)
10
#include <AsyncTCP.h>
11
#include <WiFi.h>
12
#elif defined(ESP8266)
13
#include <ESP8266WiFi.h>
14
#include <ESPAsyncTCP.h>
15
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
16
#include <RPAsyncTCP.h>
17
#include <WiFi.h>
18
#endif
19
 
20
#include <ESPAsyncWebServer.h>
21
 
22
static const char *htmlContent PROGMEM = R"(
23
<!DOCTYPE html>
24
<html>
25
<head>
26
    <title>Sample HTML</title>
27
</head>
28
<body>
29
    <h1>Hello, World!</h1>
30
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
31
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
32
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
33
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
34
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
35
    dapibus elit, id varius sem dui id lacus.</p>
36
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
37
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
38
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
39
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
40
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
41
    dapibus elit, id varius sem dui id lacus.</p>
42
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
43
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
44
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
45
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
46
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
47
    dapibus elit, id varius sem dui id lacus.</p>
48
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
49
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
50
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
51
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
52
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
53
    dapibus elit, id varius sem dui id lacus.</p>
54
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
55
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
56
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
57
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
58
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
59
    dapibus elit, id varius sem dui id lacus.</p>
60
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
61
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
62
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
63
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
64
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
65
    dapibus elit, id varius sem dui id lacus.</p>
66
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
67
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
68
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
69
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
70
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
71
    dapibus elit, id varius sem dui id lacus.</p>
72
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin euismod, purus a euismod
73
    rhoncus, urna ipsum cursus massa, eu dictum tellus justo ac justo. Quisque ullamcorper
74
    arcu nec tortor ullamcorper, vel fermentum justo fermentum. Vivamus sed velit ut elit
75
    accumsan congue ut ut enim. Ut eu justo eu lacus varius gravida ut a tellus. Nulla facilisi.
76
    Integer auctor consectetur ultricies. Fusce feugiat, mi sit amet bibendum viverra, orci leo
77
    dapibus elit, id varius sem dui id lacus.</p>
78
</body>
79
</html>
80
)";
81
 
82
static const size_t htmlContentLength = strlen_P(htmlContent);
83
static constexpr char characters[] = "0123456789ABCDEF";
84
static size_t charactersIndex = 0;
85
 
86
static AsyncWebServer server(80);
87
static AsyncEventSource events("/events");
88
 
89
static volatile size_t requests = 0;
90
 
91
void setup() {
92
  Serial.begin(115200);
93
 
94
#if ASYNCWEBSERVER_WIFI_SUPPORTED
95
  WiFi.mode(WIFI_AP);
96
  WiFi.softAP("esp-captive");
97
#endif
98
 
99
  // Pauses in the request parsing phase
100
  //
101
  // autocannon -c 32 -w 32 -a 96 -t 30 --renderStatusCodes -m POST -H "Content-Type: application/json" -b '{"foo": "bar"}' http://192.168.4.1/delay
102
  //
103
  // curl -v -X POST -H "Content-Type: application/json" -d '{"game": "test"}' http://192.168.4.1/delay
104
  //
105
  server.onNotFound([](AsyncWebServerRequest *request) {
106
    requests = requests + 1;
107
    if (request->url() == "/delay") {
108
      request->send(200, "application/json", "{\"status\":\"OK\"}");
109
    } else {
110
      request->send(404, "text/plain", "Not found");
111
    }
112
  });
113
  server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
114
    if (request->url() == "/delay") {
115
      delay(3000);
116
    }
117
  });
118
 
119
  // HTTP endpoint
120
  //
121
  // > autocannon -c 16 -w 16 -d 20 --renderStatusCodes  http://192.168.4.1/
122
  // > ab -c 16 -t 20 http://192.168.4.1/
123
  //
124
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
125
    // need to cast to uint8_t*
126
    // if you do not, the const char* will be copied in a temporary String buffer
127
    requests = requests + 1;
128
    request->send(200, "text/html", (uint8_t *)htmlContent, htmlContentLength);
129
  });
130
 
131
  // IMPORTANT - DO NOT WRITE SUCH CODE IN PRODUCTON !
132
  //
133
  // This example simulates the slowdown that can happen when:
134
  // - downloading a huge file from sdcard
135
  // - doing some file listing on SDCard because it is horribly slow to get a file listing with file stats on SDCard.
136
  // So in both cases, ESP would deadlock or TWDT would trigger.
137
  //
138
  // This example simulats that by slowing down the chunk callback:
139
  // - d=2000 is the delay in ms in the callback
140
  // - l=10000 is the length of the response
141
  //
142
  // time curl -N -v -G -d 'd=2000' -d 'l=10000'  http://192.168.4.1/slow.html --output -
143
  //
144
  // THIS CODE WILL CRASH BECAUSE OF THE WATCHDOG.
145
  // IF YOU REALLY NEED TO DO THIS, YOU MUST DISABLE THE TWDT
146
  //
147
  // CORRECT WAY IS TO USE SSE OR WEBSOCKETS TO DO THE COSTLY PROCESSING ASYNC.
148
  //
149
  server.on("/slow.html", HTTP_GET, [](AsyncWebServerRequest *request) {
150
    requests = requests + 1;
151
    uint32_t d = request->getParam("d")->value().toInt();
152
    uint32_t l = request->getParam("l")->value().toInt();
153
    Serial.printf("d = %" PRIu32 ", l = %" PRIu32 "\n", d, l);
154
    AsyncWebServerResponse *response = request->beginChunkedResponse("text/html", [d, l](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
155
      Serial.printf("%u\n", index);
156
      // finished ?
157
      if (index >= l) {
158
        return 0;
159
      }
160
 
161
      // slow down the task to simulate some heavy processing, like SD card reading
162
      delay(d);
163
 
164
      memset(buffer, characters[charactersIndex], 256);
165
      charactersIndex = (charactersIndex + 1) % sizeof(characters);
166
      return 256;
167
    });
168
 
169
    request->send(response);
170
  });
171
 
172
  // SSS endpoint
173
  //
174
  // launch 16 concurrent workers for 30 seconds
175
  // > for i in {1..16}; do ( count=$(gtimeout 30 curl -s -N -H "Accept: text/event-stream" http://192.168.4.1/events 2>&1 | grep -c "^data:"); echo "Total: $count events, $(echo "$count / 4" | bc -l) events / second" ) & done;
176
  //
177
  // With AsyncTCP, with 16 workers: a lot of "Event message queue overflow: discard message", no crash
178
  //
179
  // Total: 1711 events, 427.75 events / second
180
  // Total: 1711 events, 427.75 events / second
181
  // Total: 1626 events, 406.50 events / second
182
  // Total: 1562 events, 390.50 events / second
183
  // Total: 1706 events, 426.50 events / second
184
  // Total: 1659 events, 414.75 events / second
185
  // Total: 1624 events, 406.00 events / second
186
  // Total: 1706 events, 426.50 events / second
187
  // Total: 1487 events, 371.75 events / second
188
  // Total: 1573 events, 393.25 events / second
189
  // Total: 1569 events, 392.25 events / second
190
  // Total: 1559 events, 389.75 events / second
191
  // Total: 1560 events, 390.00 events / second
192
  // Total: 1562 events, 390.50 events / second
193
  // Total: 1626 events, 406.50 events / second
194
  //
195
  // With AsyncTCP, with 10 workers:
196
  //
197
  // Total: 2038 events, 509.50 events / second
198
  // Total: 2120 events, 530.00 events / second
199
  // Total: 2119 events, 529.75 events / second
200
  // Total: 2038 events, 509.50 events / second
201
  // Total: 2037 events, 509.25 events / second
202
  // Total: 2119 events, 529.75 events / second
203
  // Total: 2119 events, 529.75 events / second
204
  // Total: 2120 events, 530.00 events / second
205
  // Total: 2038 events, 509.50 events / second
206
  // Total: 2038 events, 509.50 events / second
207
  //
208
  // With AsyncTCPSock, with 16 workers: ESP32 CRASH !!!
209
  //
210
  // With AsyncTCPSock, with 10 workers:
211
  //
212
  // Total: 1242 events, 310.50 events / second
213
  // Total: 1242 events, 310.50 events / second
214
  // Total: 1242 events, 310.50 events / second
215
  // Total: 1242 events, 310.50 events / second
216
  // Total: 1181 events, 295.25 events / second
217
  // Total: 1182 events, 295.50 events / second
218
  // Total: 1240 events, 310.00 events / second
219
  // Total: 1181 events, 295.25 events / second
220
  // Total: 1181 events, 295.25 events / second
221
  // Total: 1183 events, 295.75 events / second
222
  //
223
  server.addHandler(&events);
224
 
225
  server.begin();
226
}
227
 
228
static uint32_t lastSSE = 0;
229
static uint32_t deltaSSE = 10;
230
 
231
static uint32_t lastHeap = 0;
232
 
233
void loop() {
234
  uint32_t now = millis();
235
  if (now - lastSSE >= deltaSSE) {
236
    events.send(String("ping-") + now, "heartbeat", now);
237
    lastSSE = millis();
238
  }
239
 
240
#ifdef ESP32
241
  if (now - lastHeap >= 2000) {
242
    Serial.printf(
243
      "Uptime: %3lu s, requests: %3u, Free heap: %" PRIu32 ", Min free heap: %" PRIu32 "\n", millis() / 1000, requests, ESP.getFreeHeap(), ESP.getMinFreeHeap()
244
    );
245
    lastHeap = now;
246
  }
247
#endif
248
}