/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010-2019 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation: * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "core/private.h" #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) { struct lws_vhost *v = context->vhost_list; int n; #if defined(LWS_WITH_PEER_LIMITS) int m; #endif 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_ACCEPT_SPIN: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN)); 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_SSL_CONNS_HAD_RX: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_SSL_CONNS_HAD_RX)); lwsl_notice("LWSSTATS_C_PEER_LIMIT_AH_DENIED: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_PEER_LIMIT_AH_DENIED)); lwsl_notice("LWSSTATS_C_PEER_LIMIT_WSI_DENIED: %8llu\n", (unsigned long long)lws_stats_get(context, LWSSTATS_C_PEER_LIMIT_WSI_DENIED)); 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_SSL_RX_DELAY: %8llums\n", (unsigned long long)lws_stats_get(context, LWSSTATS_MS_SSL_RX_DELAY) / 1000); if (lws_stats_get(context, LWSSTATS_C_SSL_CONNS_HAD_RX)) lwsl_notice(" Avg accept-rx delay: %8llums\n", (unsigned long long)(lws_stats_get(context, LWSSTATS_MS_SSL_RX_DELAY) / lws_stats_get(context, LWSSTATS_C_SSL_CONNS_HAD_RX)) / 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("Simultaneous SSL restriction: %8d/%d\n", context->simultaneous_ssl, context->simultaneous_ssl_restriction); lwsl_notice("Live wsi: %8d\n", context->count_wsi_allocated); context->updated = 1; while (v) { if (v->lserv_wsi && v->lserv_wsi->position_in_fds_table != LWS_NO_FDS_POS) { struct lws_context_per_thread *pt = &context->pt[(int)v->lserv_wsi->tsi]; struct lws_pollfd *pfd; pfd = &pt->fds[v->lserv_wsi->position_in_fds_table]; lwsl_notice(" Listen port %d actual POLLIN: %d\n", v->listen_port, (int)pfd->events & LWS_POLLIN); } v = v->vhost_next; } for (n = 0; n < context->count_threads; n++) { struct lws_context_per_thread *pt = &context->pt[n]; struct lws *wl; int m = 0; lwsl_notice("PT %d\n", n + 1); lws_pt_lock(pt, __func__); lwsl_notice(" AH in use / max: %d / %d\n", pt->http.ah_count_in_use, context->max_http_header_pool); wl = pt->http.ah_wait_list; while (wl) { m++; wl = wl->http.ah_wait_list; } lwsl_notice(" AH wait list count / actual: %d / %d\n", pt->http.ah_wait_list_length, m); lws_pt_unlock(pt); } #if defined(LWS_WITH_PEER_LIMITS) m = 0; for (n = 0; n < (int)context->pl_hash_elements; n++) { lws_start_foreach_llp(struct lws_peer **, peer, context->pl_hash_table[n]) { m++; } lws_end_foreach_llp(peer, next); } lwsl_notice(" Peers: total active %d\n", m); if (m > 10) { m = 10; lwsl_notice(" (showing 10 peers only)\n"); } if (m) { for (n = 0; n < (int)context->pl_hash_elements; n++) { char buf[72]; lws_start_foreach_llp(struct lws_peer **, peer, context->pl_hash_table[n]) { struct lws_peer *df = *peer; if (!lws_plat_inet_ntop(df->af, df->addr, buf, sizeof(buf) - 1)) strcpy(buf, "unknown"); #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) lwsl_notice(" peer %s: count wsi: %d, count ah: %d\n", buf, df->count_wsi, df->http.count_ah); #else lwsl_notice(" peer %s: count wsi: %d\n", buf, df->count_wsi); #endif if (!--m) break; } lws_end_foreach_llp(peer, next); } } #endif 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_stats_lock(pt); context->lws_stats[index] += bump; if (index != LWSSTATS_C_SERVICE_ENTRY) context->updated = 1; lws_pt_stats_unlock(pt); } void lws_stats_atomic_max(struct lws_context * context, struct lws_context_per_thread *pt, int index, uint64_t val) { lws_pt_stats_lock(pt); if (val > context->lws_stats[index]) { context->lws_stats[index] = val; context->updated = 1; } lws_pt_stats_unlock(pt); } #endif