From a7def3ce4473827098b3b5edff0b052dc43b7feb Mon Sep 17 00:00:00 2001
From: Andy Green <andy@warmcat.com>
Date: Sun, 7 May 2017 10:02:03 +0800
Subject: [PATCH] LWS_WITH_STATS
---
CMakeLists.txt | 2 +
component.mk | 1 +
lib/context.c | 6 ++-
lib/libwebsockets.c | 79 +++++++++++++++++++++++++++++++++++++
lib/libwebsockets.h | 48 ++++++++++++++++++++++
lib/lws-plat-esp32.c | 1 +
lib/lws-plat-unix.c | 2 +
lib/output.c | 15 +++++++
lib/pollfd.c | 10 +++++
lib/private-libwebsockets.h | 29 +++++++++++++-
lib/server.c | 25 ++++++++++++
lib/service.c | 21 ++++++++++
lib/ssl.c | 16 +++++++-
lws_config.h.in | 2 +
14 files changed, 254 insertions(+), 3 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a962682c..b035f8d5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -117,6 +117,7 @@ option(LWS_WITH_RANGES "Support http ranges (RFC7233)" ON)
option(LWS_FALLBACK_GETHOSTBYNAME "Also try to do dns resolution using gethostbyname if getaddrinfo fails" OFF)
option(LWS_WITH_ZIP_FOPS "Support serving pre-zipped files" ON)
option(LWS_AVOID_SIGPIPE_IGN "Android 7+ seems to need this" OFF)
+option(LWS_WITH_STATS "Keep statistics of lws internal operations" OFF)
if (LWS_WITH_LWSWS)
message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
@@ -1767,6 +1768,7 @@ message(" LWS_PLAT_OPTEE = ${LWS_PLAT_OPTEE}")
message(" LWS_WITH_ESP32 = ${LWS_WITH_ESP32}")
message(" LWS_WITH_ZIP_FOPS = ${LWS_WITH_ZIP_FOPS}")
message(" LWS_AVOID_SIGPIPE_IGN = ${LWS_AVOID_SIGPIPE_IGN}")
+message(" LWS_WITH_STATS = ${LWS_WITH_STATS}")
message("---------------------------------------------------------------------")
diff --git a/component.mk b/component.mk
index f7dbbd8e..ed334a80 100644
--- a/component.mk
+++ b/component.mk
@@ -25,6 +25,7 @@ build:
-DCMAKE_BUILD_TYPE=RELEASE \
-DOPENSSL_INCLUDE_DIR=${IDF_PATH}/components/openssl/include \
-DOPENSSL_LIBRARIES=x \
+ -DLWS_WITH_STATS=1 \
-DZLIB_LIBRARY=$(BUILD_DIR_BASE)/zlib/libzlib.a \
-DZLIB_INCLUDE_DIR=$(COMPONENT_PATH)/../zlib \
-DLWS_WITH_ESP32=1 ;\
diff --git a/lib/context.c b/lib/context.c
index 435f48ef..f791ca6a 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -616,6 +616,9 @@ lws_create_context(struct lws_context_creation_info *info)
lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP);
lwsl_info(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED);
lwsl_info(" sizeof (*info) : %ld\n", (long)sizeof(*info));
+#if defined(LWS_WITH_STATS)
+ lwsl_notice(" LWS_WITH_STATS : on\n");
+#endif
#if LWS_POSIX
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
#endif
@@ -1109,12 +1112,13 @@ lws_context_destroy2(struct lws_context *context)
vh = vh1;
}
+ lws_stats_log_dump(context);
+
lws_ssl_context_destroy(context);
lws_plat_context_late_destroy(context);
if (context->external_baggage_free_on_destroy)
free(context->external_baggage_free_on_destroy);
-
lws_free(context);
}
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 98b8df9a..7750429f 100755
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -249,6 +249,7 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
context = wsi->context;
pt = &context->pt[(int)wsi->tsi];
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_CLOSE, 1);
/* if we have children, close them first */
if (wsi->child_list) {
@@ -3110,3 +3111,81 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len,
}
#endif
+
+#if defined(LWS_WITH_STATS)
+
+LWS_VISIBLE LWS_EXTERN uint64_t
+lws_stats_get(struct lws_context *context, int index)
+{
+ if (index >= LWSSTATS_SIZE)
+ return 0;
+
+ return context->lws_stats[index];
+}
+
+LWS_VISIBLE LWS_EXTERN void
+lws_stats_log_dump(struct lws_context *context)
+{
+ if (!context->updated)
+ return;
+
+ context->updated = 0;
+
+ lwsl_notice("\n");
+ lwsl_notice("LWS internal statistics dump ----->\n");
+ lwsl_notice("LWSSTATS_C_CONNECTIONS: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_CONNECTIONS));
+ lwsl_notice("LWSSTATS_C_API_CLOSE: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_API_CLOSE));
+ lwsl_notice("LWSSTATS_C_API_READ: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_API_READ));
+ lwsl_notice("LWSSTATS_C_API_LWS_WRITE: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_API_LWS_WRITE));
+ lwsl_notice("LWSSTATS_C_API_WRITE: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_API_WRITE));
+ lwsl_notice("LWSSTATS_C_WRITE_PARTIALS: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_WRITE_PARTIALS));
+ lwsl_notice("LWSSTATS_C_WRITEABLE_CB_REQ: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB_REQ));
+ lwsl_notice("LWSSTATS_C_WRITEABLE_CB_EFF_REQ: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB_EFF_REQ));
+ lwsl_notice("LWSSTATS_C_WRITEABLE_CB: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB));
+ lwsl_notice("LWSSTATS_C_SSL_CONNECTIONS_FAILED: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_SSL_CONNECTIONS_FAILED));
+ lwsl_notice("LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED));
+ lwsl_notice("LWSSTATS_C_TIMEOUTS: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_TIMEOUTS));
+ lwsl_notice("LWSSTATS_C_SERVICE_ENTRY: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_SERVICE_ENTRY));
+ lwsl_notice("LWSSTATS_B_READ: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_B_READ));
+ lwsl_notice("LWSSTATS_B_WRITE: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_B_WRITE));
+ lwsl_notice("LWSSTATS_B_PARTIALS_ACCEPTED_PARTS: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_B_PARTIALS_ACCEPTED_PARTS));
+ lwsl_notice("LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY: %8llums\n", (unsigned long long)lws_stats_get(context, LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY) / 1000);
+ if (lws_stats_get(context, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED))
+ lwsl_notice(" Avg accept delay: %8llums\n",
+ (unsigned long long)(lws_stats_get(context, LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY) /
+ lws_stats_get(context, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED)) / 1000);
+ lwsl_notice("LWSSTATS_MS_WRITABLE_DELAY: %8lluus\n",
+ (unsigned long long)lws_stats_get(context, LWSSTATS_MS_WRITABLE_DELAY));
+ lwsl_notice("LWSSTATS_MS_WORST_WRITABLE_DELAY: %8lluus\n",
+ (unsigned long long)lws_stats_get(context, LWSSTATS_MS_WORST_WRITABLE_DELAY));
+ if (lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB))
+ lwsl_notice(" Avg writable delay: %8lluus\n",
+ (unsigned long long)(lws_stats_get(context, LWSSTATS_MS_WRITABLE_DELAY) /
+ lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB)));
+ lwsl_notice("\n");
+}
+
+void
+lws_stats_atomic_bump(struct lws_context * context,
+ struct lws_context_per_thread *pt, int index, uint64_t bump)
+{
+ lws_pt_lock(pt);
+ context->lws_stats[index] += bump;
+ if (index != LWSSTATS_C_SERVICE_ENTRY)
+ context->updated = 1;
+ lws_pt_unlock(pt);
+}
+
+void
+lws_stats_atomic_max(struct lws_context * context,
+ struct lws_context_per_thread *pt, int index, uint64_t val)
+{
+ lws_pt_lock(pt);
+ if (val > context->lws_stats[index]) {
+ context->lws_stats[index] = val;
+ context->updated = 1;
+ }
+ lws_pt_unlock(pt);
+}
+
+#endif
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 3baaf4ee..4065aad1 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -4784,6 +4784,54 @@ lws_email_destroy(struct lws_email *email);
#endif
//@}
+/*
+ * Stats are all uint64_t numbers that start at 0.
+ * Index names here have the convention
+ *
+ * _C_ counter
+ * _B_ byte count
+ * _MS_ millisecond count
+ */
+
+enum {
+ LWSSTATS_C_CONNECTIONS, /**< count incoming connections */
+ LWSSTATS_C_API_CLOSE, /**< count calls to close api */
+ LWSSTATS_C_API_READ, /**< count calls to read from socket api */
+ LWSSTATS_C_API_LWS_WRITE, /**< count calls to lws_write API */
+ LWSSTATS_C_API_WRITE, /**< count calls to write API */
+ LWSSTATS_C_WRITE_PARTIALS, /**< count of partial writes */
+ LWSSTATS_C_WRITEABLE_CB_REQ, /**< count of writable callback requests */
+ LWSSTATS_C_WRITEABLE_CB_EFF_REQ, /**< count of effective writable callback requests */
+ LWSSTATS_C_WRITEABLE_CB, /**< count of writable callbacks */
+ LWSSTATS_C_SSL_CONNECTIONS_FAILED, /**< count of failed SSL connections */
+ LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, /**< count of accepted SSL connections */
+ LWSSTATS_C_TIMEOUTS, /**< count of timed-out connections */
+ LWSSTATS_C_SERVICE_ENTRY, /**< count of entries to lws service loop */
+ LWSSTATS_B_READ, /**< aggregate bytes read */
+ LWSSTATS_B_WRITE, /**< aggregate bytes written */
+ LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, /**< aggreate of size of accepted write data from new partials */
+ LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, /**< aggregate delay in accepting connection */
+ LWSSTATS_MS_WRITABLE_DELAY, /**< aggregate delay between asking for writable and getting cb */
+ LWSSTATS_MS_WORST_WRITABLE_DELAY, /**< single worst delay between asking for writable and getting cb */
+
+ /* Add new things just above here ---^
+ * This is part of the ABI, don't needlessly break compatibility */
+ LWSSTATS_SIZE
+};
+
+#if defined(LWS_WITH_STATS)
+
+LWS_VISIBLE LWS_EXTERN uint64_t
+lws_stats_get(struct lws_context *context, int index);
+LWS_VISIBLE LWS_EXTERN void
+lws_stats_log_dump(struct lws_context *context);
+#else
+static inline uint64_t
+lws_stats_get(struct lws_context *context, int index) { return 0; }
+static inline void
+lws_stats_log_dump(struct lws_context *context) { }
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/lws-plat-esp32.c b/lib/lws-plat-esp32.c
index 19536ce9..dc549111 100644
--- a/lib/lws-plat-esp32.c
+++ b/lib/lws-plat-esp32.c
@@ -115,6 +115,7 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
return 1;
pt = &context->pt[tsi];
+ lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);
if (timeout_ms < 0)
goto faked_service;
diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c
index 3c41a466..b9f317bb 100644
--- a/lib/lws-plat-unix.c
+++ b/lib/lws-plat-unix.c
@@ -114,6 +114,8 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
pt = &context->pt[tsi];
+ lws_stats_atomic_bump(context, pt, LWSSTATS_C_SERVICE_ENTRY, 1);
+
if (timeout_ms < 0)
goto faked_service;
diff --git a/lib/output.c b/lib/output.c
index a41b0e0d..efb26068 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -95,10 +95,13 @@ LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
{
struct lws_context *context = lws_get_context(wsi);
+ struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
size_t real_len = len;
unsigned int n;
int m;
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_WRITE, 1);
+
if (!len)
return 0;
/* just ignore sends after we cleared the truncation buffer */
@@ -207,6 +210,9 @@ handle_truncated_send:
lwsl_debug("%p new partial sent %d from %lu total\n", wsi, n,
(unsigned long)real_len);
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITE_PARTIALS, 1);
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, n);
+
/*
* - if we still have a suitable malloc lying around, use it
* - or, if too small, reallocate it
@@ -244,12 +250,16 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
int pre = 0, n;
size_t orig_len = len;
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_LWS_WRITE, 1);
+
if ((int)len < 0) {
lwsl_err("%s: suspicious len int %d, ulong %lu\n", __func__,
(int)len, (unsigned long)len);
return -1;
}
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_WRITE, len);
+
#ifdef LWS_WITH_ACCESS_LOG
wsi->access_log.sent += len;
#endif
@@ -766,12 +776,17 @@ file_had_it:
LWS_VISIBLE int
lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
{
+ struct lws_context *context = wsi->context;
+ struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
int n;
+ lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
+
n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
if (n >= 0) {
if (wsi->vhost)
wsi->vhost->conn_stats.rx += n;
+ lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
lws_restart_ws_ping_pong_timer(wsi);
return n;
}
diff --git a/lib/pollfd.c b/lib/pollfd.c
index b43f7913..7c3a0efa 100644
--- a/lib/pollfd.c
+++ b/lib/pollfd.c
@@ -336,6 +336,7 @@ lws_change_pollfd(struct lws *wsi, int _and, int _or)
LWS_VISIBLE int
lws_callback_on_writable(struct lws *wsi)
{
+ struct lws_context_per_thread *pt;
#ifdef LWS_USE_HTTP2
struct lws *network_wsi, *wsi2;
int already;
@@ -347,6 +348,15 @@ lws_callback_on_writable(struct lws *wsi)
if (wsi->socket_is_permanently_unusable)
return 0;
+ pt = &wsi->context->pt[(int)wsi->tsi];
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
+#if defined(LWS_WITH_STATS)
+ if (!wsi->active_writable_req_us) {
+ wsi->active_writable_req_us = time_in_microseconds();
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_EFF_REQ, 1);
+ }
+#endif
+
#ifdef LWS_USE_HTTP2
lwsl_info("%s: %p\n", __func__, wsi);
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index d59bd7b3..21fccdc7 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -879,6 +879,12 @@ struct lws_context {
char worst_latency_info[256];
#endif
+#if defined(LWS_WITH_STATS)
+ uint64_t lws_stats[LWSSTATS_SIZE];
+ uint64_t last_dump;
+ int updated;
+#endif
+
int max_fds;
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV) || defined(LWS_USE_LIBEVENT)
int use_ev_sigint;
@@ -1465,6 +1471,9 @@ struct lws {
SSL *ssl;
BIO *client_bio;
struct lws *pending_read_list_prev, *pending_read_list_next;
+#if defined(LWS_WITH_STATS)
+ uint64_t accept_start_us;
+#endif
#endif
#ifdef LWS_WITH_HTTP_PROXY
struct lws_rewrite *rw;
@@ -1474,7 +1483,9 @@ struct lws {
unsigned long latency_start;
#endif
lws_sock_file_fd_type desc; /* .filefd / .sockfd */
-
+#if defined(LWS_WITH_STATS)
+ uint64_t active_writable_req_us;
+#endif
/* ints */
int position_in_fds_table;
int rxflow_len;
@@ -2072,6 +2083,22 @@ lws_same_vh_protocol_remove(struct lws *wsi);
LWS_EXTERN void
lws_same_vh_protocol_insert(struct lws *wsi, int n);
+#if defined(LWS_WITH_STATS)
+void
+lws_stats_atomic_bump(struct lws_context * context,
+ struct lws_context_per_thread *pt, int index, uint64_t bump);
+void
+lws_stats_atomic_max(struct lws_context * context,
+ struct lws_context_per_thread *pt, int index, uint64_t val);
+#else
+static inline uint64_t lws_stats_atomic_bump(struct lws_context * context,
+ struct lws_context_per_thread *pt, int index, uint64_t bump) {
+ (void)context; (void)pt; (void)index; (void)bump; return 0; }
+static inline uint64_t lws_stats_atomic_max(struct lws_context * context,
+ struct lws_context_per_thread *pt, int index, uint64_t val) {
+ (void)context; (void)pt; (void)index; (void)val; return 0; }
+#endif
+
#ifdef __cplusplus
};
#endif
diff --git a/lib/server.c b/lib/server.c
index d1ff1e9f..f442b94a 100644
--- a/lib/server.c
+++ b/lib/server.c
@@ -1757,6 +1757,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
{
struct lws_context *context = vh->context;
struct lws *new_wsi = lws_create_new_server_wsi(vh);
+ struct lws_context_per_thread *pt;
int n, ssl = 0;
if (!new_wsi) {
@@ -1764,6 +1765,8 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
compatible_close(fd.sockfd);
return NULL;
}
+ pt = &context->pt[(int)new_wsi->tsi];
+ lws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);
if (parent) {
new_wsi->parent = parent;
@@ -2192,6 +2195,16 @@ try_pollout:
}
if (wsi->mode == LWSCM_RAW) {
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
+#if defined(LWS_WITH_STATS)
+ {
+ uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
+
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
+ lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
+ wsi->active_writable_req_us = 0;
+ }
+#endif
n = user_callback_handle_rxflow(wsi->protocol->callback,
wsi, LWS_CALLBACK_RAW_WRITEABLE,
wsi->user_space, NULL, 0);
@@ -2206,6 +2219,18 @@ try_pollout:
break;
if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
+
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
+#if defined(LWS_WITH_STATS)
+ {
+ uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
+
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
+ lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
+ wsi->active_writable_req_us = 0;
+ }
+#endif
+
n = user_callback_handle_rxflow(wsi->protocol->callback,
wsi, LWS_CALLBACK_HTTP_WRITEABLE,
wsi->user_space, NULL, 0);
diff --git a/lib/service.c b/lib/service.c
index b23defd7..e33c6a7c 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -24,8 +24,20 @@
static int
lws_calllback_as_writeable(struct lws *wsi)
{
+ struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int n;
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
+#if defined(LWS_WITH_STATS)
+ {
+ uint64_t ul = time_in_microseconds() - wsi->active_writable_req_us;
+
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_WRITABLE_DELAY, ul);
+ lws_stats_atomic_max(wsi->context, pt, LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
+ wsi->active_writable_req_us = 0;
+ }
+#endif
+
switch (wsi->mode) {
case LWSCM_RAW:
n = LWS_CALLBACK_RAW_WRITEABLE;
@@ -425,6 +437,8 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec)
if (wsi->desc.sockfd != LWS_SOCK_INVALID && wsi->position_in_fds_table >= 0)
n = pt->fds[wsi->position_in_fds_table].events;
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_TIMEOUTS, 1);
+
/* no need to log normal idle keepalive timeout */
if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE)
lwsl_notice("wsi %p: TIMEDOUT WAITING on %d (did hdr %d, ah %p, wl %d, pfd events %d) %llu vs %llu\n",
@@ -786,6 +800,13 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
if (context->last_timeout_check_s != now) {
context->last_timeout_check_s = now;
+#if defined(LWS_WITH_STATS)
+ if (!tsi && now - context->last_dump > 10) {
+ lws_stats_log_dump(context);
+ context->last_dump = now;
+ }
+#endif
+
lws_plat_service_periodic(context);
/* retire unused deprecated context */
diff --git a/lib/ssl.c b/lib/ssl.c
index a7969f3d..b5f9e1e6 100644
--- a/lib/ssl.c
+++ b/lib/ssl.c
@@ -298,6 +298,8 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
if (!wsi->ssl)
return lws_ssl_capable_read_no_ssl(wsi, buf, len);
+ lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
+
errno = 0;
n = SSL_read(wsi->ssl, buf, len);
#if defined(LWS_WITH_ESP32)
@@ -354,6 +356,8 @@ lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len)
return LWS_SSL_CAPABLE_ERROR;
}
+ lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
+
if (wsi->vhost)
wsi->vhost->conn_stats.rx += n;
@@ -652,6 +656,11 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
/* normal SSL connection processing path */
+#if defined(LWS_WITH_STATS)
+ if (!wsi->accept_start_us)
+ wsi->accept_start_us = time_in_microseconds();
+#endif
+
n = SSL_accept(wsi->ssl);
lws_latency(context, wsi,
"SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1);
@@ -686,13 +695,18 @@ go_again:
break;
}
-
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_FAILED, 1);
lwsl_err("SSL_accept failed socket %u: %s\n", wsi->desc.sockfd,
lws_ssl_get_error_string(m, n, buf, sizeof(buf)));
lws_ssl_elaborate_error();
goto fail;
accepted:
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, 1);
+#if defined(LWS_WITH_STATS)
+ lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, time_in_microseconds() - wsi->accept_start_us);
+#endif
+
/* OK, we are accepted... give him some time to negotiate */
lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
context->timeout_secs);
diff --git a/lws_config.h.in b/lws_config.h.in
index d83211bf..96c17053 100644
--- a/lws_config.h.in
+++ b/lws_config.h.in
@@ -133,6 +133,8 @@
#cmakedefine LWS_FALLBACK_GETHOSTBYNAME
+#cmakedefine LWS_WITH_STATS
+
/* OpenSSL various APIs */
#cmakedefine LWS_HAVE_TLS_CLIENT_METHOD
--
GitLab