• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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