1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26
27 #if defined(LWS_WITH_STATS)
28
29 uint64_t
lws_stats_get(struct lws_context * context,int index)30 lws_stats_get(struct lws_context *context, int index)
31 {
32 struct lws_context_per_thread *pt = &context->pt[0];
33
34 if (index >= LWSSTATS_SIZE)
35 return 0;
36
37 return pt->lws_stats[index];
38 }
39
40 static const char * stat_names[] = {
41 "C_CONNECTIONS",
42 "C_API_CLOSE",
43 "C_API_READ",
44 "C_API_LWS_WRITE",
45 "C_API_WRITE",
46 "C_WRITE_PARTIALS",
47 "C_WRITEABLE_CB_REQ",
48 "C_WRITEABLE_CB_EFF_REQ",
49 "C_WRITEABLE_CB",
50 "C_SSL_CONNECTIONS_FAILED",
51 "C_SSL_CONNECTIONS_ACCEPTED",
52 "C_SSL_CONNECTIONS_ACCEPT_SPIN",
53 "C_SSL_CONNS_HAD_RX",
54 "C_TIMEOUTS",
55 "C_SERVICE_ENTRY",
56 "B_READ",
57 "B_WRITE",
58 "B_PARTIALS_ACCEPTED_PARTS",
59 "US_SSL_ACCEPT_LATENCY_AVG",
60 "US_WRITABLE_DELAY_AVG",
61 "US_WORST_WRITABLE_DELAY",
62 "US_SSL_RX_DELAY_AVG",
63 "C_PEER_LIMIT_AH_DENIED",
64 "C_PEER_LIMIT_WSI_DENIED",
65 "C_CONNECTIONS_CLIENT",
66 "C_CONNECTIONS_CLIENT_FAILED",
67 };
68
69 static int
quantify(struct lws_context * context,int tsi,char * p,int len,int idx,uint64_t * sum)70 quantify(struct lws_context *context, int tsi, char *p, int len, int idx,
71 uint64_t *sum)
72 {
73 const lws_humanize_unit_t *schema = humanize_schema_si;
74 struct lws_context_per_thread *pt = &context->pt[tsi];
75 uint64_t u, u1;
76
77 lws_pt_stats_lock(pt);
78 u = pt->lws_stats[idx];
79
80 /* it's supposed to be an average? */
81
82 switch (idx) {
83 case LWSSTATS_US_SSL_ACCEPT_LATENCY_AVG:
84 u1 = pt->lws_stats[LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED];
85 if (u1)
86 u = u / u1;
87 break;
88 case LWSSTATS_US_SSL_RX_DELAY_AVG:
89 u1 = pt->lws_stats[LWSSTATS_C_SSL_CONNS_HAD_RX];
90 if (u1)
91 u = u / u1;
92 break;
93 case LWSSTATS_US_WRITABLE_DELAY_AVG:
94 u1 = pt->lws_stats[LWSSTATS_C_WRITEABLE_CB];
95 if (u1)
96 u = u / u1;
97 break;
98 }
99 lws_pt_stats_unlock(pt);
100
101 *sum += u;
102
103 switch (stat_names[idx][0]) {
104 case 'U':
105 schema = humanize_schema_us;
106 break;
107 case 'B':
108 schema = humanize_schema_si_bytes;
109 break;
110 }
111
112 return lws_humanize(p, len, u, schema);
113 }
114
115
116 void
lws_stats_log_dump(struct lws_context * context)117 lws_stats_log_dump(struct lws_context *context)
118 {
119 struct lws_vhost *v = context->vhost_list;
120 uint64_t summary[LWSSTATS_SIZE];
121 char bufline[128], *p, *end = bufline + sizeof(bufline) - 1;
122 int n, m;
123
124 if (!context->updated)
125 return;
126
127 context->updated = 0;
128 memset(summary, 0, sizeof(summary));
129
130 lwsl_notice("\n");
131 lwsl_notice("LWS internal statistics dump ----->\n");
132 for (n = 0; n < (int)LWS_ARRAY_SIZE(stat_names); n++) {
133 uint64_t u = 0;
134
135 /* if it's all zeroes, don't report it */
136
137 for (m = 0; m < context->count_threads; m++) {
138 struct lws_context_per_thread *pt = &context->pt[m];
139
140 u |= pt->lws_stats[n];
141 }
142 if (!u)
143 continue;
144
145 p = bufline;
146 p += lws_snprintf(p, lws_ptr_diff(end, p), "%28s: ",
147 stat_names[n]);
148
149 for (m = 0; m < context->count_threads; m++)
150 quantify(context, m, p, lws_ptr_diff(end, p), n, &summary[n]);
151
152 lwsl_notice("%s\n", bufline);
153 }
154
155 lwsl_notice("Simultaneous SSL restriction: %8d/%d\n",
156 context->simultaneous_ssl,
157 context->simultaneous_ssl_restriction);
158
159 lwsl_notice("Live wsi: %8d\n",
160 context->count_wsi_allocated);
161
162 while (v) {
163 if (v->lserv_wsi &&
164 v->lserv_wsi->position_in_fds_table != LWS_NO_FDS_POS) {
165
166 struct lws_context_per_thread *pt =
167 &context->pt[(int)v->lserv_wsi->tsi];
168 struct lws_pollfd *pfd;
169
170 pfd = &pt->fds[v->lserv_wsi->position_in_fds_table];
171
172 lwsl_notice(" Listen port %d actual POLLIN: %d\n",
173 v->listen_port,
174 (int)pfd->events & LWS_POLLIN);
175 }
176
177 v = v->vhost_next;
178 }
179
180 for (n = 0; n < context->count_threads; n++) {
181 struct lws_context_per_thread *pt = &context->pt[n];
182 struct lws *wl;
183 int m = 0;
184
185 lwsl_notice("PT %d\n", n + 1);
186
187 lws_pt_lock(pt, __func__);
188
189 lwsl_notice(" AH in use / max: %d / %d\n",
190 pt->http.ah_count_in_use,
191 context->max_http_header_pool);
192
193 wl = pt->http.ah_wait_list;
194 while (wl) {
195 m++;
196 wl = wl->http.ah_wait_list;
197 }
198
199 lwsl_notice(" AH wait list count / actual: %d / %d\n",
200 pt->http.ah_wait_list_length, m);
201
202 lws_pt_unlock(pt);
203 }
204
205 #if defined(LWS_WITH_PEER_LIMITS)
206 m = 0;
207 for (n = 0; n < (int)context->pl_hash_elements; n++) {
208 lws_start_foreach_llp(struct lws_peer **, peer,
209 context->pl_hash_table[n]) {
210 m++;
211 } lws_end_foreach_llp(peer, next);
212 }
213
214 lwsl_notice(" Peers: total active %d\n", m);
215 if (m > 10) {
216 m = 10;
217 lwsl_notice(" (showing 10 peers only)\n");
218 }
219
220 if (m) {
221 for (n = 0; n < (int)context->pl_hash_elements; n++) {
222 char buf[72];
223
224 lws_start_foreach_llp(struct lws_peer **, peer,
225 context->pl_hash_table[n]) {
226 struct lws_peer *df = *peer;
227
228 if (!lws_plat_inet_ntop(df->af, df->addr, buf,
229 sizeof(buf) - 1))
230 strcpy(buf, "unknown");
231 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
232 lwsl_notice(" peer %s: count wsi: %d, count ah: %d\n",
233 buf, df->count_wsi,
234 df->http.count_ah);
235 #else
236 lwsl_notice(" peer %s: count wsi: %d\n",
237 buf, df->count_wsi);
238 #endif
239
240 if (!--m)
241 break;
242 } lws_end_foreach_llp(peer, next);
243 }
244 }
245 #endif
246
247 lwsl_notice("\n");
248 }
249
250 void
lws_stats_bump(struct lws_context_per_thread * pt,int i,uint64_t bump)251 lws_stats_bump(struct lws_context_per_thread *pt, int i, uint64_t bump)
252 {
253 lws_pt_stats_lock(pt);
254 pt->lws_stats[i] += bump;
255 if (i != LWSSTATS_C_SERVICE_ENTRY) {
256 pt->updated = 1;
257 pt->context->updated = 1;
258 }
259 lws_pt_stats_unlock(pt);
260 }
261
262 void
lws_stats_max(struct lws_context_per_thread * pt,int index,uint64_t val)263 lws_stats_max(struct lws_context_per_thread *pt, int index, uint64_t val)
264 {
265 lws_pt_stats_lock(pt);
266 if (val > pt->lws_stats[index]) {
267 pt->lws_stats[index] = val;
268 pt->updated = 1;
269 pt->context->updated = 1;
270 }
271 lws_pt_stats_unlock(pt);
272 }
273
274 #endif
275
276
277