xref: /aosp_15_r20/external/libwebsockets/lib/system/metrics/metrics.c (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker  * lws Generic Metrics
3*1c60b9acSAndroid Build Coastguard Worker  *
4*1c60b9acSAndroid Build Coastguard Worker  * Copyright (C) 2019 - 2021 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker  *
6*1c60b9acSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker  * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker  * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker  *
13*1c60b9acSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker  *
16*1c60b9acSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker  * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker  */
24*1c60b9acSAndroid Build Coastguard Worker 
25*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
26*1c60b9acSAndroid Build Coastguard Worker #include <assert.h>
27*1c60b9acSAndroid Build Coastguard Worker 
28*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_tag_add(lws_dll2_owner_t * owner,const char * name,const char * val)29*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val)
30*1c60b9acSAndroid Build Coastguard Worker {
31*1c60b9acSAndroid Build Coastguard Worker 	size_t vl = strlen(val);
32*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_tag_t *tag;
33*1c60b9acSAndroid Build Coastguard Worker 
34*1c60b9acSAndroid Build Coastguard Worker 	// lwsl_notice("%s: adding %s=%s\n", __func__, name, val);
35*1c60b9acSAndroid Build Coastguard Worker 
36*1c60b9acSAndroid Build Coastguard Worker 	/*
37*1c60b9acSAndroid Build Coastguard Worker 	 * Remove (in order to replace) any existing tag of same name
38*1c60b9acSAndroid Build Coastguard Worker 	 */
39*1c60b9acSAndroid Build Coastguard Worker 
40*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll(struct lws_dll2 *, d, owner->head) {
41*1c60b9acSAndroid Build Coastguard Worker 		tag = lws_container_of(d, lws_metrics_tag_t, list);
42*1c60b9acSAndroid Build Coastguard Worker 
43*1c60b9acSAndroid Build Coastguard Worker 		if (!strcmp(name, tag->name)) {
44*1c60b9acSAndroid Build Coastguard Worker 			lws_dll2_remove(&tag->list);
45*1c60b9acSAndroid Build Coastguard Worker 			lws_free(tag);
46*1c60b9acSAndroid Build Coastguard Worker 			break;
47*1c60b9acSAndroid Build Coastguard Worker 		}
48*1c60b9acSAndroid Build Coastguard Worker 
49*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll(d);
50*1c60b9acSAndroid Build Coastguard Worker 
51*1c60b9acSAndroid Build Coastguard Worker 	/*
52*1c60b9acSAndroid Build Coastguard Worker 	 * Create the new tag
53*1c60b9acSAndroid Build Coastguard Worker 	 */
54*1c60b9acSAndroid Build Coastguard Worker 
55*1c60b9acSAndroid Build Coastguard Worker 	tag = lws_malloc(sizeof(*tag) + vl + 1, __func__);
56*1c60b9acSAndroid Build Coastguard Worker 	if (!tag)
57*1c60b9acSAndroid Build Coastguard Worker 		return 1;
58*1c60b9acSAndroid Build Coastguard Worker 
59*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_clear(&tag->list);
60*1c60b9acSAndroid Build Coastguard Worker 	tag->name = name;
61*1c60b9acSAndroid Build Coastguard Worker 	memcpy(&tag[1], val, vl + 1);
62*1c60b9acSAndroid Build Coastguard Worker 
63*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_add_tail(&tag->list, owner);
64*1c60b9acSAndroid Build Coastguard Worker 
65*1c60b9acSAndroid Build Coastguard Worker 	return 0;
66*1c60b9acSAndroid Build Coastguard Worker }
67*1c60b9acSAndroid Build Coastguard Worker 
68*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_tag_wsi_add(struct lws * wsi,const char * name,const char * val)69*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tag_wsi_add(struct lws *wsi, const char *name, const char *val)
70*1c60b9acSAndroid Build Coastguard Worker {
71*1c60b9acSAndroid Build Coastguard Worker 	__lws_lc_tag(wsi->a.context, NULL, &wsi->lc, "|%s", val);
72*1c60b9acSAndroid Build Coastguard Worker 
73*1c60b9acSAndroid Build Coastguard Worker 	return lws_metrics_tag_add(&wsi->cal_conn.mtags_owner, name, val);
74*1c60b9acSAndroid Build Coastguard Worker }
75*1c60b9acSAndroid Build Coastguard Worker 
76*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
77*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_tag_ss_add(struct lws_ss_handle * ss,const char * name,const char * val)78*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tag_ss_add(struct lws_ss_handle *ss, const char *name, const char *val)
79*1c60b9acSAndroid Build Coastguard Worker {
80*1c60b9acSAndroid Build Coastguard Worker 	__lws_lc_tag(ss->context, NULL, &ss->lc, "|%s", val);
81*1c60b9acSAndroid Build Coastguard Worker 	return lws_metrics_tag_add(&ss->cal_txn.mtags_owner, name, val);
82*1c60b9acSAndroid Build Coastguard Worker }
83*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
84*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_tag_sspc_add(struct lws_sspc_handle * sspc,const char * name,const char * val)85*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tag_sspc_add(struct lws_sspc_handle *sspc, const char *name,
86*1c60b9acSAndroid Build Coastguard Worker 			 const char *val)
87*1c60b9acSAndroid Build Coastguard Worker {
88*1c60b9acSAndroid Build Coastguard Worker 	__lws_lc_tag(sspc->context, NULL, &sspc->lc, "|%s", val);
89*1c60b9acSAndroid Build Coastguard Worker 	return lws_metrics_tag_add(&sspc->cal_txn.mtags_owner, name, val);
90*1c60b9acSAndroid Build Coastguard Worker }
91*1c60b9acSAndroid Build Coastguard Worker #endif
92*1c60b9acSAndroid Build Coastguard Worker #endif
93*1c60b9acSAndroid Build Coastguard Worker 
94*1c60b9acSAndroid Build Coastguard Worker void
lws_metrics_tags_destroy(lws_dll2_owner_t * owner)95*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tags_destroy(lws_dll2_owner_t *owner)
96*1c60b9acSAndroid Build Coastguard Worker {
97*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_tag_t *t;
98*1c60b9acSAndroid Build Coastguard Worker 
99*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, owner->head) {
100*1c60b9acSAndroid Build Coastguard Worker 		t = lws_container_of(d, lws_metrics_tag_t, list);
101*1c60b9acSAndroid Build Coastguard Worker 
102*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_remove(&t->list);
103*1c60b9acSAndroid Build Coastguard Worker 		lws_free(t);
104*1c60b9acSAndroid Build Coastguard Worker 
105*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
106*1c60b9acSAndroid Build Coastguard Worker }
107*1c60b9acSAndroid Build Coastguard Worker 
108*1c60b9acSAndroid Build Coastguard Worker size_t
lws_metrics_tags_serialize(lws_dll2_owner_t * owner,char * buf,size_t len)109*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len)
110*1c60b9acSAndroid Build Coastguard Worker {
111*1c60b9acSAndroid Build Coastguard Worker 	char *end = buf + len - 1, *p = buf;
112*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_tag_t *t;
113*1c60b9acSAndroid Build Coastguard Worker 
114*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll(struct lws_dll2 *, d, owner->head) {
115*1c60b9acSAndroid Build Coastguard Worker 		t = lws_container_of(d, lws_metrics_tag_t, list);
116*1c60b9acSAndroid Build Coastguard Worker 
117*1c60b9acSAndroid Build Coastguard Worker 		p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
118*1c60b9acSAndroid Build Coastguard Worker 				  "%s=\"%s\"", t->name, (const char *)&t[1]);
119*1c60b9acSAndroid Build Coastguard Worker 
120*1c60b9acSAndroid Build Coastguard Worker 		if (d->next && p + 2 < end)
121*1c60b9acSAndroid Build Coastguard Worker 			*p++ = ',';
122*1c60b9acSAndroid Build Coastguard Worker 
123*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll(d);
124*1c60b9acSAndroid Build Coastguard Worker 
125*1c60b9acSAndroid Build Coastguard Worker 	*p = '\0';
126*1c60b9acSAndroid Build Coastguard Worker 
127*1c60b9acSAndroid Build Coastguard Worker 	return lws_ptr_diff_size_t(p, buf);
128*1c60b9acSAndroid Build Coastguard Worker }
129*1c60b9acSAndroid Build Coastguard Worker 
130*1c60b9acSAndroid Build Coastguard Worker const char *
lws_metrics_tag_get(lws_dll2_owner_t * owner,const char * name)131*1c60b9acSAndroid Build Coastguard Worker lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name)
132*1c60b9acSAndroid Build Coastguard Worker {
133*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_tag_t *t;
134*1c60b9acSAndroid Build Coastguard Worker 
135*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll(struct lws_dll2 *, d, owner->head) {
136*1c60b9acSAndroid Build Coastguard Worker 		t = lws_container_of(d, lws_metrics_tag_t, list);
137*1c60b9acSAndroid Build Coastguard Worker 
138*1c60b9acSAndroid Build Coastguard Worker 		if (!strcmp(name, t->name))
139*1c60b9acSAndroid Build Coastguard Worker 			return (const char *)&t[1];
140*1c60b9acSAndroid Build Coastguard Worker 
141*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll(d);
142*1c60b9acSAndroid Build Coastguard Worker 
143*1c60b9acSAndroid Build Coastguard Worker 	return NULL;
144*1c60b9acSAndroid Build Coastguard Worker }
145*1c60b9acSAndroid Build Coastguard Worker 
146*1c60b9acSAndroid Build Coastguard Worker static int
147*1c60b9acSAndroid Build Coastguard Worker lws_metrics_dump_cb(lws_metric_pub_t *pub, void *user);
148*1c60b9acSAndroid Build Coastguard Worker 
149*1c60b9acSAndroid Build Coastguard Worker static void
lws_metrics_report_and_maybe_clear(struct lws_context * ctx,lws_metric_pub_t * pub)150*1c60b9acSAndroid Build Coastguard Worker lws_metrics_report_and_maybe_clear(struct lws_context *ctx, lws_metric_pub_t *pub)
151*1c60b9acSAndroid Build Coastguard Worker {
152*1c60b9acSAndroid Build Coastguard Worker 	if (!pub->us_first || pub->us_last == pub->us_dumped)
153*1c60b9acSAndroid Build Coastguard Worker 		return;
154*1c60b9acSAndroid Build Coastguard Worker 
155*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_dump_cb(pub, ctx);
156*1c60b9acSAndroid Build Coastguard Worker }
157*1c60b9acSAndroid Build Coastguard Worker 
158*1c60b9acSAndroid Build Coastguard Worker static void
lws_metrics_periodic_cb(lws_sorted_usec_list_t * sul)159*1c60b9acSAndroid Build Coastguard Worker lws_metrics_periodic_cb(lws_sorted_usec_list_t *sul)
160*1c60b9acSAndroid Build Coastguard Worker {
161*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_policy_dyn_t *dmp = lws_container_of(sul,
162*1c60b9acSAndroid Build Coastguard Worker 						lws_metric_policy_dyn_t, sul);
163*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *ctx = lws_container_of(dmp->list.owner,
164*1c60b9acSAndroid Build Coastguard Worker 					struct lws_context, owner_mtr_dynpol);
165*1c60b9acSAndroid Build Coastguard Worker 
166*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->system_ops || !ctx->system_ops->metric_report)
167*1c60b9acSAndroid Build Coastguard Worker 		return;
168*1c60b9acSAndroid Build Coastguard Worker 
169*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll(struct lws_dll2 *, d, dmp->owner.head) {
170*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
171*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt);
172*1c60b9acSAndroid Build Coastguard Worker 
173*1c60b9acSAndroid Build Coastguard Worker 		lws_metrics_report_and_maybe_clear(ctx, pub);
174*1c60b9acSAndroid Build Coastguard Worker 
175*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll(d);
176*1c60b9acSAndroid Build Coastguard Worker 
177*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SYS_SMD) && defined(LWS_WITH_SECURE_STREAMS)
178*1c60b9acSAndroid Build Coastguard Worker 	(void)lws_smd_msg_printf(ctx, LWSSMDCL_METRICS,
179*1c60b9acSAndroid Build Coastguard Worker 				 "{\"dump\":\"%s\",\"ts\":%lu}",
180*1c60b9acSAndroid Build Coastguard Worker 				   dmp->policy->name,
181*1c60b9acSAndroid Build Coastguard Worker 				   (long)ctx->last_policy);
182*1c60b9acSAndroid Build Coastguard Worker #endif
183*1c60b9acSAndroid Build Coastguard Worker 
184*1c60b9acSAndroid Build Coastguard Worker 	if (dmp->policy->us_schedule)
185*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_schedule(ctx, 0, &dmp->sul,
186*1c60b9acSAndroid Build Coastguard Worker 				 lws_metrics_periodic_cb,
187*1c60b9acSAndroid Build Coastguard Worker 				 (lws_usec_t)dmp->policy->us_schedule);
188*1c60b9acSAndroid Build Coastguard Worker }
189*1c60b9acSAndroid Build Coastguard Worker 
190*1c60b9acSAndroid Build Coastguard Worker /*
191*1c60b9acSAndroid Build Coastguard Worker  * Policies are in two pieces, a const policy and a dynamic part that contains
192*1c60b9acSAndroid Build Coastguard Worker  * lists and sul timers for the policy etc.  This creates a dynmic part
193*1c60b9acSAndroid Build Coastguard Worker  * corresponding to the static part.
194*1c60b9acSAndroid Build Coastguard Worker  *
195*1c60b9acSAndroid Build Coastguard Worker  * Metrics can exist detached from being bound to any policy about how to
196*1c60b9acSAndroid Build Coastguard Worker  * report them, these are collected but not reported unless they later become
197*1c60b9acSAndroid Build Coastguard Worker  * bound to a reporting policy dynamically.
198*1c60b9acSAndroid Build Coastguard Worker  */
199*1c60b9acSAndroid Build Coastguard Worker 
200*1c60b9acSAndroid Build Coastguard Worker lws_metric_policy_dyn_t *
lws_metrics_policy_dyn_create(struct lws_context * ctx,const lws_metric_policy_t * po)201*1c60b9acSAndroid Build Coastguard Worker lws_metrics_policy_dyn_create(struct lws_context *ctx,
202*1c60b9acSAndroid Build Coastguard Worker 			      const lws_metric_policy_t *po)
203*1c60b9acSAndroid Build Coastguard Worker {
204*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_policy_dyn_t *dmet;
205*1c60b9acSAndroid Build Coastguard Worker 
206*1c60b9acSAndroid Build Coastguard Worker 	dmet = lws_zalloc(sizeof(*dmet), __func__);
207*1c60b9acSAndroid Build Coastguard Worker 	if (!dmet)
208*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
209*1c60b9acSAndroid Build Coastguard Worker 
210*1c60b9acSAndroid Build Coastguard Worker 	dmet->policy = po;
211*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_add_tail(&dmet->list, &ctx->owner_mtr_dynpol);
212*1c60b9acSAndroid Build Coastguard Worker 
213*1c60b9acSAndroid Build Coastguard Worker 	if (po->us_schedule)
214*1c60b9acSAndroid Build Coastguard Worker 		lws_sul_schedule(ctx, 0, &dmet->sul,
215*1c60b9acSAndroid Build Coastguard Worker 				 lws_metrics_periodic_cb,
216*1c60b9acSAndroid Build Coastguard Worker 				 (lws_usec_t)po->us_schedule);
217*1c60b9acSAndroid Build Coastguard Worker 
218*1c60b9acSAndroid Build Coastguard Worker 	return dmet;
219*1c60b9acSAndroid Build Coastguard Worker }
220*1c60b9acSAndroid Build Coastguard Worker 
221*1c60b9acSAndroid Build Coastguard Worker /*
222*1c60b9acSAndroid Build Coastguard Worker  * Get a dynamic metrics policy from the const one, may return NULL if OOM
223*1c60b9acSAndroid Build Coastguard Worker  */
224*1c60b9acSAndroid Build Coastguard Worker 
225*1c60b9acSAndroid Build Coastguard Worker lws_metric_policy_dyn_t *
lws_metrics_policy_get_dyn(struct lws_context * ctx,const lws_metric_policy_t * po)226*1c60b9acSAndroid Build Coastguard Worker lws_metrics_policy_get_dyn(struct lws_context *ctx,
227*1c60b9acSAndroid Build Coastguard Worker 			   const lws_metric_policy_t *po)
228*1c60b9acSAndroid Build Coastguard Worker {
229*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll(struct lws_dll2 *, d, ctx->owner_mtr_dynpol.head) {
230*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_policy_dyn_t *dm =
231*1c60b9acSAndroid Build Coastguard Worker 			lws_container_of(d, lws_metric_policy_dyn_t, list);
232*1c60b9acSAndroid Build Coastguard Worker 
233*1c60b9acSAndroid Build Coastguard Worker 		if (dm->policy == po)
234*1c60b9acSAndroid Build Coastguard Worker 			return dm;
235*1c60b9acSAndroid Build Coastguard Worker 
236*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll(d);
237*1c60b9acSAndroid Build Coastguard Worker 
238*1c60b9acSAndroid Build Coastguard Worker 	/*
239*1c60b9acSAndroid Build Coastguard Worker 	 * no dyn policy part for this const policy --> create one
240*1c60b9acSAndroid Build Coastguard Worker 	 *
241*1c60b9acSAndroid Build Coastguard Worker 	 * We want a dynamic part for listing metrics that bound to the policy
242*1c60b9acSAndroid Build Coastguard Worker 	 */
243*1c60b9acSAndroid Build Coastguard Worker 
244*1c60b9acSAndroid Build Coastguard Worker 	return lws_metrics_policy_dyn_create(ctx, po);
245*1c60b9acSAndroid Build Coastguard Worker }
246*1c60b9acSAndroid Build Coastguard Worker 
247*1c60b9acSAndroid Build Coastguard Worker static int
lws_metrics_check_in_policy(const char * polstring,const char * name)248*1c60b9acSAndroid Build Coastguard Worker lws_metrics_check_in_policy(const char *polstring, const char *name)
249*1c60b9acSAndroid Build Coastguard Worker {
250*1c60b9acSAndroid Build Coastguard Worker 	struct lws_tokenize ts;
251*1c60b9acSAndroid Build Coastguard Worker 
252*1c60b9acSAndroid Build Coastguard Worker 	memset(&ts, 0, sizeof(ts));
253*1c60b9acSAndroid Build Coastguard Worker 
254*1c60b9acSAndroid Build Coastguard Worker 	ts.start = polstring;
255*1c60b9acSAndroid Build Coastguard Worker 	ts.len = strlen(polstring);
256*1c60b9acSAndroid Build Coastguard Worker 	ts.flags = (uint16_t)(LWS_TOKENIZE_F_MINUS_NONTERM |
257*1c60b9acSAndroid Build Coastguard Worker 			      LWS_TOKENIZE_F_ASTERISK_NONTERM |
258*1c60b9acSAndroid Build Coastguard Worker 			      LWS_TOKENIZE_F_COMMA_SEP_LIST |
259*1c60b9acSAndroid Build Coastguard Worker 			      LWS_TOKENIZE_F_NO_FLOATS |
260*1c60b9acSAndroid Build Coastguard Worker 			      LWS_TOKENIZE_F_DOT_NONTERM);
261*1c60b9acSAndroid Build Coastguard Worker 
262*1c60b9acSAndroid Build Coastguard Worker 	do {
263*1c60b9acSAndroid Build Coastguard Worker 		ts.e = (int8_t)lws_tokenize(&ts);
264*1c60b9acSAndroid Build Coastguard Worker 
265*1c60b9acSAndroid Build Coastguard Worker 		if (ts.e == LWS_TOKZE_TOKEN) {
266*1c60b9acSAndroid Build Coastguard Worker 			if (!lws_strcmp_wildcard(ts.token, ts.token_len, name,
267*1c60b9acSAndroid Build Coastguard Worker 						 strlen(name)))
268*1c60b9acSAndroid Build Coastguard Worker 				/* yes, we are mentioned in this guy's policy */
269*1c60b9acSAndroid Build Coastguard Worker 				return 0;
270*1c60b9acSAndroid Build Coastguard Worker 		}
271*1c60b9acSAndroid Build Coastguard Worker 	} while (ts.e > 0);
272*1c60b9acSAndroid Build Coastguard Worker 
273*1c60b9acSAndroid Build Coastguard Worker 	/* no, this policy doesn't apply to a metric with our name */
274*1c60b9acSAndroid Build Coastguard Worker 
275*1c60b9acSAndroid Build Coastguard Worker 	return 1;
276*1c60b9acSAndroid Build Coastguard Worker }
277*1c60b9acSAndroid Build Coastguard Worker 
278*1c60b9acSAndroid Build Coastguard Worker static const lws_metric_policy_t *
lws_metrics_find_policy(struct lws_context * ctx,const char * name)279*1c60b9acSAndroid Build Coastguard Worker lws_metrics_find_policy(struct lws_context *ctx, const char *name)
280*1c60b9acSAndroid Build Coastguard Worker {
281*1c60b9acSAndroid Build Coastguard Worker 	const lws_metric_policy_t *mp = ctx->metrics_policies;
282*1c60b9acSAndroid Build Coastguard Worker 
283*1c60b9acSAndroid Build Coastguard Worker 	if (!mp) {
284*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
285*1c60b9acSAndroid Build Coastguard Worker 		if (ctx->pss_policies)
286*1c60b9acSAndroid Build Coastguard Worker 			mp = ctx->pss_policies->metrics;
287*1c60b9acSAndroid Build Coastguard Worker #endif
288*1c60b9acSAndroid Build Coastguard Worker 		if (!mp)
289*1c60b9acSAndroid Build Coastguard Worker 			return NULL;
290*1c60b9acSAndroid Build Coastguard Worker 	}
291*1c60b9acSAndroid Build Coastguard Worker 
292*1c60b9acSAndroid Build Coastguard Worker 	while (mp) {
293*1c60b9acSAndroid Build Coastguard Worker 		if (mp->report && !lws_metrics_check_in_policy(mp->report, name))
294*1c60b9acSAndroid Build Coastguard Worker 			return mp;
295*1c60b9acSAndroid Build Coastguard Worker 
296*1c60b9acSAndroid Build Coastguard Worker 		mp = mp->next;
297*1c60b9acSAndroid Build Coastguard Worker 	}
298*1c60b9acSAndroid Build Coastguard Worker 
299*1c60b9acSAndroid Build Coastguard Worker 	return NULL;
300*1c60b9acSAndroid Build Coastguard Worker }
301*1c60b9acSAndroid Build Coastguard Worker 
302*1c60b9acSAndroid Build Coastguard Worker /*
303*1c60b9acSAndroid Build Coastguard Worker  * Create a lws_metric_t, bind to a named policy if possible (or add to the
304*1c60b9acSAndroid Build Coastguard Worker  * context list of unbound metrics) and set its lws_system
305*1c60b9acSAndroid Build Coastguard Worker  * idx.  The metrics objects themselves are typically composed into other
306*1c60b9acSAndroid Build Coastguard Worker  * objects and are well-known composed members of them.
307*1c60b9acSAndroid Build Coastguard Worker  */
308*1c60b9acSAndroid Build Coastguard Worker 
309*1c60b9acSAndroid Build Coastguard Worker lws_metric_t *
lws_metric_create(struct lws_context * ctx,uint8_t flags,const char * name)310*1c60b9acSAndroid Build Coastguard Worker lws_metric_create(struct lws_context *ctx, uint8_t flags, const char *name)
311*1c60b9acSAndroid Build Coastguard Worker {
312*1c60b9acSAndroid Build Coastguard Worker 	const lws_metric_policy_t *po;
313*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_policy_dyn_t *dmp;
314*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_pub_t *pub;
315*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_t *mt;
316*1c60b9acSAndroid Build Coastguard Worker 	char pname[32];
317*1c60b9acSAndroid Build Coastguard Worker 	size_t nl;
318*1c60b9acSAndroid Build Coastguard Worker 
319*1c60b9acSAndroid Build Coastguard Worker 	if (ctx->metrics_prefix) {
320*1c60b9acSAndroid Build Coastguard Worker 
321*1c60b9acSAndroid Build Coastguard Worker 		/*
322*1c60b9acSAndroid Build Coastguard Worker 		 * In multi-process case, we want to prefix metrics from this
323*1c60b9acSAndroid Build Coastguard Worker 		 * process / context with a string distinguishing which
324*1c60b9acSAndroid Build Coastguard Worker 		 * application they came from
325*1c60b9acSAndroid Build Coastguard Worker 		 */
326*1c60b9acSAndroid Build Coastguard Worker 
327*1c60b9acSAndroid Build Coastguard Worker 		nl = (size_t)lws_snprintf(pname, sizeof(pname) - 1, "%s.%s",
328*1c60b9acSAndroid Build Coastguard Worker 				  ctx->metrics_prefix, name);
329*1c60b9acSAndroid Build Coastguard Worker 		name = pname;
330*1c60b9acSAndroid Build Coastguard Worker 	} else
331*1c60b9acSAndroid Build Coastguard Worker 		nl = strlen(name);
332*1c60b9acSAndroid Build Coastguard Worker 
333*1c60b9acSAndroid Build Coastguard Worker 	mt = (lws_metric_t *)lws_zalloc(sizeof(*mt) /* private */ +
334*1c60b9acSAndroid Build Coastguard Worker 					sizeof(lws_metric_pub_t) +
335*1c60b9acSAndroid Build Coastguard Worker 					nl + 1 /* copy of metric name */,
336*1c60b9acSAndroid Build Coastguard Worker 					__func__);
337*1c60b9acSAndroid Build Coastguard Worker 	if (!mt)
338*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
339*1c60b9acSAndroid Build Coastguard Worker 
340*1c60b9acSAndroid Build Coastguard Worker 	pub = lws_metrics_priv_to_pub(mt);
341*1c60b9acSAndroid Build Coastguard Worker 	pub->name = (char *)pub + sizeof(lws_metric_pub_t);
342*1c60b9acSAndroid Build Coastguard Worker 	memcpy((char *)pub->name, name, nl + 1);
343*1c60b9acSAndroid Build Coastguard Worker 	pub->flags = flags;
344*1c60b9acSAndroid Build Coastguard Worker 
345*1c60b9acSAndroid Build Coastguard Worker 	/* after these common members, we have to use the right type */
346*1c60b9acSAndroid Build Coastguard Worker 
347*1c60b9acSAndroid Build Coastguard Worker 	if (!(flags & LWSMTFL_REPORT_HIST)) {
348*1c60b9acSAndroid Build Coastguard Worker 		/* anything is smaller or equal to this */
349*1c60b9acSAndroid Build Coastguard Worker 		pub->u.agg.min = ~(u_mt_t)0;
350*1c60b9acSAndroid Build Coastguard Worker 		pub->us_first = lws_now_usecs();
351*1c60b9acSAndroid Build Coastguard Worker 	}
352*1c60b9acSAndroid Build Coastguard Worker 
353*1c60b9acSAndroid Build Coastguard Worker 	mt->ctx = ctx;
354*1c60b9acSAndroid Build Coastguard Worker 
355*1c60b9acSAndroid Build Coastguard Worker 	/*
356*1c60b9acSAndroid Build Coastguard Worker 	 * Let's see if we can bind to a reporting policy straight away
357*1c60b9acSAndroid Build Coastguard Worker 	 */
358*1c60b9acSAndroid Build Coastguard Worker 
359*1c60b9acSAndroid Build Coastguard Worker 	po = lws_metrics_find_policy(ctx, name);
360*1c60b9acSAndroid Build Coastguard Worker 	if (po) {
361*1c60b9acSAndroid Build Coastguard Worker 		dmp = lws_metrics_policy_get_dyn(ctx, po);
362*1c60b9acSAndroid Build Coastguard Worker 		if (dmp) {
363*1c60b9acSAndroid Build Coastguard Worker 			lwsl_notice("%s: metpol %s\n", __func__, name);
364*1c60b9acSAndroid Build Coastguard Worker 			lws_dll2_add_tail(&mt->list, &dmp->owner);
365*1c60b9acSAndroid Build Coastguard Worker 
366*1c60b9acSAndroid Build Coastguard Worker 			return 0;
367*1c60b9acSAndroid Build Coastguard Worker 		}
368*1c60b9acSAndroid Build Coastguard Worker 	}
369*1c60b9acSAndroid Build Coastguard Worker 
370*1c60b9acSAndroid Build Coastguard Worker 	/*
371*1c60b9acSAndroid Build Coastguard Worker 	 * If not, well, let's go on without and maybe later at runtime, he'll
372*1c60b9acSAndroid Build Coastguard Worker 	 * get interested in us and apply a reporting policy
373*1c60b9acSAndroid Build Coastguard Worker 	 */
374*1c60b9acSAndroid Build Coastguard Worker 
375*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_add_tail(&mt->list, &ctx->owner_mtr_no_pol);
376*1c60b9acSAndroid Build Coastguard Worker 
377*1c60b9acSAndroid Build Coastguard Worker 	return mt;
378*1c60b9acSAndroid Build Coastguard Worker }
379*1c60b9acSAndroid Build Coastguard Worker 
380*1c60b9acSAndroid Build Coastguard Worker /*
381*1c60b9acSAndroid Build Coastguard Worker  * If our metric is bound to a reporting policy, return a pointer to it,
382*1c60b9acSAndroid Build Coastguard Worker  * otherwise NULL
383*1c60b9acSAndroid Build Coastguard Worker  */
384*1c60b9acSAndroid Build Coastguard Worker 
385*1c60b9acSAndroid Build Coastguard Worker const lws_metric_policy_t *
lws_metric_get_policy(lws_metric_t * mt)386*1c60b9acSAndroid Build Coastguard Worker lws_metric_get_policy(lws_metric_t *mt)
387*1c60b9acSAndroid Build Coastguard Worker {
388*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_policy_dyn_t *dp;
389*1c60b9acSAndroid Build Coastguard Worker 
390*1c60b9acSAndroid Build Coastguard Worker 	/*
391*1c60b9acSAndroid Build Coastguard Worker 	 * Our metric must either be on the "no policy" context list or
392*1c60b9acSAndroid Build Coastguard Worker 	 * listed by the dynamic part of the policy it is bound to
393*1c60b9acSAndroid Build Coastguard Worker 	 */
394*1c60b9acSAndroid Build Coastguard Worker 	assert(mt->list.owner);
395*1c60b9acSAndroid Build Coastguard Worker 
396*1c60b9acSAndroid Build Coastguard Worker 	if ((char *)mt->list.owner >= (char *)mt->ctx &&
397*1c60b9acSAndroid Build Coastguard Worker 	    (char *)mt->list.owner < (char *)mt->ctx + sizeof(struct lws_context))
398*1c60b9acSAndroid Build Coastguard Worker 		/* we are on the "no policy" context list */
399*1c60b9acSAndroid Build Coastguard Worker 		return NULL;
400*1c60b9acSAndroid Build Coastguard Worker 
401*1c60b9acSAndroid Build Coastguard Worker 	/* we are listed by a dynamic policy owner */
402*1c60b9acSAndroid Build Coastguard Worker 
403*1c60b9acSAndroid Build Coastguard Worker 	dp = lws_container_of(mt->list.owner, lws_metric_policy_dyn_t, owner);
404*1c60b9acSAndroid Build Coastguard Worker 
405*1c60b9acSAndroid Build Coastguard Worker 	/* return the const policy the dynamic policy represents */
406*1c60b9acSAndroid Build Coastguard Worker 
407*1c60b9acSAndroid Build Coastguard Worker 	return dp->policy;
408*1c60b9acSAndroid Build Coastguard Worker }
409*1c60b9acSAndroid Build Coastguard Worker 
410*1c60b9acSAndroid Build Coastguard Worker void
lws_metric_rebind_policies(struct lws_context * ctx)411*1c60b9acSAndroid Build Coastguard Worker lws_metric_rebind_policies(struct lws_context *ctx)
412*1c60b9acSAndroid Build Coastguard Worker {
413*1c60b9acSAndroid Build Coastguard Worker 	const lws_metric_policy_t *po;
414*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_policy_dyn_t *dmp;
415*1c60b9acSAndroid Build Coastguard Worker 
416*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
417*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner_mtr_no_pol.head) {
418*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
419*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt);
420*1c60b9acSAndroid Build Coastguard Worker 
421*1c60b9acSAndroid Build Coastguard Worker 		po = lws_metrics_find_policy(ctx, pub->name);
422*1c60b9acSAndroid Build Coastguard Worker 		if (po) {
423*1c60b9acSAndroid Build Coastguard Worker 			dmp = lws_metrics_policy_get_dyn(ctx, po);
424*1c60b9acSAndroid Build Coastguard Worker 			if (dmp) {
425*1c60b9acSAndroid Build Coastguard Worker 				lwsl_info("%s: %s <- pol %s\n", __func__,
426*1c60b9acSAndroid Build Coastguard Worker 						pub->name, po->name);
427*1c60b9acSAndroid Build Coastguard Worker 				lws_dll2_remove(&mt->list);
428*1c60b9acSAndroid Build Coastguard Worker 				lws_dll2_add_tail(&mt->list, &dmp->owner);
429*1c60b9acSAndroid Build Coastguard Worker 			}
430*1c60b9acSAndroid Build Coastguard Worker 		} else
431*1c60b9acSAndroid Build Coastguard Worker 			lwsl_debug("%s: no pol for %s\n", __func__, pub->name);
432*1c60b9acSAndroid Build Coastguard Worker 
433*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
434*1c60b9acSAndroid Build Coastguard Worker }
435*1c60b9acSAndroid Build Coastguard Worker 
436*1c60b9acSAndroid Build Coastguard Worker int
lws_metric_destroy(lws_metric_t ** pmt,int keep)437*1c60b9acSAndroid Build Coastguard Worker lws_metric_destroy(lws_metric_t **pmt, int keep)
438*1c60b9acSAndroid Build Coastguard Worker {
439*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_t *mt = *pmt;
440*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt);
441*1c60b9acSAndroid Build Coastguard Worker 
442*1c60b9acSAndroid Build Coastguard Worker 	if (!mt)
443*1c60b9acSAndroid Build Coastguard Worker 		return 0;
444*1c60b9acSAndroid Build Coastguard Worker 
445*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(&mt->list);
446*1c60b9acSAndroid Build Coastguard Worker 
447*1c60b9acSAndroid Build Coastguard Worker 	if (keep) {
448*1c60b9acSAndroid Build Coastguard Worker 		lws_dll2_add_tail(&mt->list, &mt->ctx->owner_mtr_no_pol);
449*1c60b9acSAndroid Build Coastguard Worker 
450*1c60b9acSAndroid Build Coastguard Worker 		return 0;
451*1c60b9acSAndroid Build Coastguard Worker 	}
452*1c60b9acSAndroid Build Coastguard Worker 
453*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_HIST) {
454*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_bucket_t *b = pub->u.hist.head, *b1;
455*1c60b9acSAndroid Build Coastguard Worker 
456*1c60b9acSAndroid Build Coastguard Worker 		pub->u.hist.head = NULL;
457*1c60b9acSAndroid Build Coastguard Worker 
458*1c60b9acSAndroid Build Coastguard Worker 		while (b) {
459*1c60b9acSAndroid Build Coastguard Worker 			b1 = b->next;
460*1c60b9acSAndroid Build Coastguard Worker 			lws_free(b);
461*1c60b9acSAndroid Build Coastguard Worker 			b = b1;
462*1c60b9acSAndroid Build Coastguard Worker 		}
463*1c60b9acSAndroid Build Coastguard Worker 	}
464*1c60b9acSAndroid Build Coastguard Worker 
465*1c60b9acSAndroid Build Coastguard Worker 	lws_free(mt);
466*1c60b9acSAndroid Build Coastguard Worker 	*pmt = NULL;
467*1c60b9acSAndroid Build Coastguard Worker 
468*1c60b9acSAndroid Build Coastguard Worker 	return 0;
469*1c60b9acSAndroid Build Coastguard Worker }
470*1c60b9acSAndroid Build Coastguard Worker 
471*1c60b9acSAndroid Build Coastguard Worker /*
472*1c60b9acSAndroid Build Coastguard Worker  * Allow an existing metric to have its reporting policy changed at runtime
473*1c60b9acSAndroid Build Coastguard Worker  */
474*1c60b9acSAndroid Build Coastguard Worker 
475*1c60b9acSAndroid Build Coastguard Worker int
lws_metric_switch_policy(lws_metric_t * mt,const char * polname)476*1c60b9acSAndroid Build Coastguard Worker lws_metric_switch_policy(lws_metric_t *mt, const char *polname)
477*1c60b9acSAndroid Build Coastguard Worker {
478*1c60b9acSAndroid Build Coastguard Worker 	const lws_metric_policy_t *po;
479*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_policy_dyn_t *dmp;
480*1c60b9acSAndroid Build Coastguard Worker 
481*1c60b9acSAndroid Build Coastguard Worker 	po = lws_metrics_find_policy(mt->ctx, polname);
482*1c60b9acSAndroid Build Coastguard Worker 	if (!po)
483*1c60b9acSAndroid Build Coastguard Worker 		return 1;
484*1c60b9acSAndroid Build Coastguard Worker 
485*1c60b9acSAndroid Build Coastguard Worker 	dmp = lws_metrics_policy_get_dyn(mt->ctx, po);
486*1c60b9acSAndroid Build Coastguard Worker 	if (!dmp)
487*1c60b9acSAndroid Build Coastguard Worker 		return 1;
488*1c60b9acSAndroid Build Coastguard Worker 
489*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(&mt->list);
490*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_add_tail(&mt->list, &dmp->owner);
491*1c60b9acSAndroid Build Coastguard Worker 
492*1c60b9acSAndroid Build Coastguard Worker 	return 0;
493*1c60b9acSAndroid Build Coastguard Worker }
494*1c60b9acSAndroid Build Coastguard Worker 
495*1c60b9acSAndroid Build Coastguard Worker /*
496*1c60b9acSAndroid Build Coastguard Worker  * If keep is set, don't destroy existing metrics objects, just detach them
497*1c60b9acSAndroid Build Coastguard Worker  * from the policy being deleted and keep track of them on ctx->
498*1c60b9acSAndroid Build Coastguard Worker  * owner_mtr_no_pol
499*1c60b9acSAndroid Build Coastguard Worker  */
500*1c60b9acSAndroid Build Coastguard Worker 
501*1c60b9acSAndroid Build Coastguard Worker void
lws_metric_policy_dyn_destroy(lws_metric_policy_dyn_t * dm,int keep)502*1c60b9acSAndroid Build Coastguard Worker lws_metric_policy_dyn_destroy(lws_metric_policy_dyn_t *dm, int keep)
503*1c60b9acSAndroid Build Coastguard Worker {
504*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_cancel(&dm->sul);
505*1c60b9acSAndroid Build Coastguard Worker 
506*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, dm->owner.head) {
507*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_t *m = lws_container_of(d, lws_metric_t, list);
508*1c60b9acSAndroid Build Coastguard Worker 
509*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_destroy(&m, keep);
510*1c60b9acSAndroid Build Coastguard Worker 
511*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
512*1c60b9acSAndroid Build Coastguard Worker 
513*1c60b9acSAndroid Build Coastguard Worker 	lws_sul_cancel(&dm->sul);
514*1c60b9acSAndroid Build Coastguard Worker 
515*1c60b9acSAndroid Build Coastguard Worker 	lws_dll2_remove(&dm->list);
516*1c60b9acSAndroid Build Coastguard Worker 	lws_free(dm);
517*1c60b9acSAndroid Build Coastguard Worker }
518*1c60b9acSAndroid Build Coastguard Worker 
519*1c60b9acSAndroid Build Coastguard Worker /*
520*1c60b9acSAndroid Build Coastguard Worker  * Destroy all dynamic metrics policies, deinit any metrics still using them
521*1c60b9acSAndroid Build Coastguard Worker  */
522*1c60b9acSAndroid Build Coastguard Worker 
523*1c60b9acSAndroid Build Coastguard Worker void
lws_metrics_destroy(struct lws_context * ctx)524*1c60b9acSAndroid Build Coastguard Worker lws_metrics_destroy(struct lws_context *ctx)
525*1c60b9acSAndroid Build Coastguard Worker {
526*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
527*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner_mtr_dynpol.head) {
528*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_policy_dyn_t *dm =
529*1c60b9acSAndroid Build Coastguard Worker 			lws_container_of(d, lws_metric_policy_dyn_t, list);
530*1c60b9acSAndroid Build Coastguard Worker 
531*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_policy_dyn_destroy(dm, 0); /* don't keep */
532*1c60b9acSAndroid Build Coastguard Worker 
533*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
534*1c60b9acSAndroid Build Coastguard Worker 
535*1c60b9acSAndroid Build Coastguard Worker 	/* destroy metrics with no current policy too... */
536*1c60b9acSAndroid Build Coastguard Worker 
537*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
538*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner_mtr_no_pol.head) {
539*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
540*1c60b9acSAndroid Build Coastguard Worker 
541*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_destroy(&mt, 0); /* don't keep */
542*1c60b9acSAndroid Build Coastguard Worker 
543*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
544*1c60b9acSAndroid Build Coastguard Worker 
545*1c60b9acSAndroid Build Coastguard Worker 	/* ... that's the whole allocated metrics footprint gone... */
546*1c60b9acSAndroid Build Coastguard Worker }
547*1c60b9acSAndroid Build Coastguard Worker 
548*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_hist_bump_(lws_metric_pub_t * pub,const char * name)549*1c60b9acSAndroid Build Coastguard Worker lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name)
550*1c60b9acSAndroid Build Coastguard Worker {
551*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_bucket_t *buck = pub->u.hist.head;
552*1c60b9acSAndroid Build Coastguard Worker 	size_t nl = strlen(name);
553*1c60b9acSAndroid Build Coastguard Worker 	char *nm;
554*1c60b9acSAndroid Build Coastguard Worker 
555*1c60b9acSAndroid Build Coastguard Worker 	if (!(pub->flags & LWSMTFL_REPORT_HIST)) {
556*1c60b9acSAndroid Build Coastguard Worker 		lwsl_err("%s: %s not histogram: flags %d\n", __func__,
557*1c60b9acSAndroid Build Coastguard Worker 				pub->name, pub->flags);
558*1c60b9acSAndroid Build Coastguard Worker 		assert(0);
559*1c60b9acSAndroid Build Coastguard Worker 	}
560*1c60b9acSAndroid Build Coastguard Worker 	assert(nl < 255);
561*1c60b9acSAndroid Build Coastguard Worker 
562*1c60b9acSAndroid Build Coastguard Worker 	pub->us_last = lws_now_usecs();
563*1c60b9acSAndroid Build Coastguard Worker 	if (!pub->us_first)
564*1c60b9acSAndroid Build Coastguard Worker 		pub->us_first = pub->us_last;
565*1c60b9acSAndroid Build Coastguard Worker 
566*1c60b9acSAndroid Build Coastguard Worker 	while (buck) {
567*1c60b9acSAndroid Build Coastguard Worker 		if (lws_metric_bucket_name_len(buck) == nl &&
568*1c60b9acSAndroid Build Coastguard Worker 		    !strcmp(name, lws_metric_bucket_name(buck))) {
569*1c60b9acSAndroid Build Coastguard Worker 			buck->count++;
570*1c60b9acSAndroid Build Coastguard Worker 			goto happy;
571*1c60b9acSAndroid Build Coastguard Worker 		}
572*1c60b9acSAndroid Build Coastguard Worker 		buck = buck->next;
573*1c60b9acSAndroid Build Coastguard Worker 	}
574*1c60b9acSAndroid Build Coastguard Worker 
575*1c60b9acSAndroid Build Coastguard Worker 	buck = lws_malloc(sizeof(*buck) + nl + 2, __func__);
576*1c60b9acSAndroid Build Coastguard Worker 	if (!buck)
577*1c60b9acSAndroid Build Coastguard Worker 		return 1;
578*1c60b9acSAndroid Build Coastguard Worker 
579*1c60b9acSAndroid Build Coastguard Worker 	nm = (char *)buck + sizeof(*buck);
580*1c60b9acSAndroid Build Coastguard Worker 	/* length byte at beginning of name, avoid struct alignment overhead */
581*1c60b9acSAndroid Build Coastguard Worker 	*nm = (char)nl;
582*1c60b9acSAndroid Build Coastguard Worker 	memcpy(nm + 1, name, nl + 1);
583*1c60b9acSAndroid Build Coastguard Worker 
584*1c60b9acSAndroid Build Coastguard Worker 	buck->next = pub->u.hist.head;
585*1c60b9acSAndroid Build Coastguard Worker 	pub->u.hist.head = buck;
586*1c60b9acSAndroid Build Coastguard Worker 	buck->count = 1;
587*1c60b9acSAndroid Build Coastguard Worker 	pub->u.hist.list_size++;
588*1c60b9acSAndroid Build Coastguard Worker 
589*1c60b9acSAndroid Build Coastguard Worker happy:
590*1c60b9acSAndroid Build Coastguard Worker 	pub->u.hist.total_count++;
591*1c60b9acSAndroid Build Coastguard Worker 
592*1c60b9acSAndroid Build Coastguard Worker 	return 0;
593*1c60b9acSAndroid Build Coastguard Worker }
594*1c60b9acSAndroid Build Coastguard Worker 
595*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_hist_bump_describe_wsi(struct lws * wsi,lws_metric_pub_t * pub,const char * name)596*1c60b9acSAndroid Build Coastguard Worker lws_metrics_hist_bump_describe_wsi(struct lws *wsi, lws_metric_pub_t *pub,
597*1c60b9acSAndroid Build Coastguard Worker 				   const char *name)
598*1c60b9acSAndroid Build Coastguard Worker {
599*1c60b9acSAndroid Build Coastguard Worker 	char desc[192], d1[48], *p = desc, *end = desc + sizeof(desc);
600*1c60b9acSAndroid Build Coastguard Worker 
601*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS)
602*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
603*1c60b9acSAndroid Build Coastguard Worker 	if (wsi->client_bound_sspc) {
604*1c60b9acSAndroid Build Coastguard Worker 		lws_sspc_handle_t *h = (lws_sspc_handle_t *)wsi->a.opaque_user_data;
605*1c60b9acSAndroid Build Coastguard Worker 		if (h)
606*1c60b9acSAndroid Build Coastguard Worker 			p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "ss=\"%s\",",
607*1c60b9acSAndroid Build Coastguard Worker 				  h->ssi.streamtype);
608*1c60b9acSAndroid Build Coastguard Worker 	} else
609*1c60b9acSAndroid Build Coastguard Worker 		if (wsi->client_proxy_onward) {
610*1c60b9acSAndroid Build Coastguard Worker 			lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
611*1c60b9acSAndroid Build Coastguard Worker 			struct conn *conn = h->conn_if_sspc_onw;
612*1c60b9acSAndroid Build Coastguard Worker 
613*1c60b9acSAndroid Build Coastguard Worker 			if (conn && conn->ss)
614*1c60b9acSAndroid Build Coastguard Worker 				p += lws_snprintf(p, lws_ptr_diff_size_t(end, p),
615*1c60b9acSAndroid Build Coastguard Worker 						  "ss=\"%s\",",
616*1c60b9acSAndroid Build Coastguard Worker 						  conn->ss->info.streamtype);
617*1c60b9acSAndroid Build Coastguard Worker 		} else
618*1c60b9acSAndroid Build Coastguard Worker #endif
619*1c60b9acSAndroid Build Coastguard Worker 	if (wsi->for_ss) {
620*1c60b9acSAndroid Build Coastguard Worker 		lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
621*1c60b9acSAndroid Build Coastguard Worker 		if (h)
622*1c60b9acSAndroid Build Coastguard Worker 			p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "ss=\"%s\",",
623*1c60b9acSAndroid Build Coastguard Worker 				  h->info.streamtype);
624*1c60b9acSAndroid Build Coastguard Worker 	}
625*1c60b9acSAndroid Build Coastguard Worker #endif
626*1c60b9acSAndroid Build Coastguard Worker 
627*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_CLIENT)
628*1c60b9acSAndroid Build Coastguard Worker 	if (wsi->stash && wsi->stash->cis[CIS_HOST])
629*1c60b9acSAndroid Build Coastguard Worker 		p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "hostname=\"%s\",",
630*1c60b9acSAndroid Build Coastguard Worker 				wsi->stash->cis[CIS_HOST]);
631*1c60b9acSAndroid Build Coastguard Worker #endif
632*1c60b9acSAndroid Build Coastguard Worker 
633*1c60b9acSAndroid Build Coastguard Worker 	lws_sa46_write_numeric_address(&wsi->sa46_peer, d1, sizeof(d1));
634*1c60b9acSAndroid Build Coastguard Worker 	p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "peer=\"%s\",", d1);
635*1c60b9acSAndroid Build Coastguard Worker 
636*1c60b9acSAndroid Build Coastguard Worker 	p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "%s", name);
637*1c60b9acSAndroid Build Coastguard Worker 
638*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_hist_bump_(pub, desc);
639*1c60b9acSAndroid Build Coastguard Worker 
640*1c60b9acSAndroid Build Coastguard Worker 	return 0;
641*1c60b9acSAndroid Build Coastguard Worker }
642*1c60b9acSAndroid Build Coastguard Worker 
643*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_foreach(struct lws_context * ctx,void * user,int (* cb)(lws_metric_pub_t * pub,void * user))644*1c60b9acSAndroid Build Coastguard Worker lws_metrics_foreach(struct lws_context *ctx, void *user,
645*1c60b9acSAndroid Build Coastguard Worker 		    int (*cb)(lws_metric_pub_t *pub, void *user))
646*1c60b9acSAndroid Build Coastguard Worker {
647*1c60b9acSAndroid Build Coastguard Worker 	int n;
648*1c60b9acSAndroid Build Coastguard Worker 
649*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
650*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner_mtr_no_pol.head) {
651*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_t *mt = lws_container_of(d, lws_metric_t, list);
652*1c60b9acSAndroid Build Coastguard Worker 
653*1c60b9acSAndroid Build Coastguard Worker 		n = cb(lws_metrics_priv_to_pub(mt), user);
654*1c60b9acSAndroid Build Coastguard Worker 		if (n)
655*1c60b9acSAndroid Build Coastguard Worker 			return n;
656*1c60b9acSAndroid Build Coastguard Worker 
657*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d, d1);
658*1c60b9acSAndroid Build Coastguard Worker 
659*1c60b9acSAndroid Build Coastguard Worker 	lws_start_foreach_dll_safe(struct lws_dll2 *, d2, d3,
660*1c60b9acSAndroid Build Coastguard Worker 				   ctx->owner_mtr_dynpol.head) {
661*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_policy_dyn_t *dm =
662*1c60b9acSAndroid Build Coastguard Worker 			lws_container_of(d2, lws_metric_policy_dyn_t, list);
663*1c60b9acSAndroid Build Coastguard Worker 
664*1c60b9acSAndroid Build Coastguard Worker 		lws_start_foreach_dll_safe(struct lws_dll2 *, e, e1,
665*1c60b9acSAndroid Build Coastguard Worker 					   dm->owner.head) {
666*1c60b9acSAndroid Build Coastguard Worker 
667*1c60b9acSAndroid Build Coastguard Worker 			lws_metric_t *mt = lws_container_of(e, lws_metric_t, list);
668*1c60b9acSAndroid Build Coastguard Worker 
669*1c60b9acSAndroid Build Coastguard Worker 			n = cb(lws_metrics_priv_to_pub(mt), user);
670*1c60b9acSAndroid Build Coastguard Worker 			if (n)
671*1c60b9acSAndroid Build Coastguard Worker 				return n;
672*1c60b9acSAndroid Build Coastguard Worker 
673*1c60b9acSAndroid Build Coastguard Worker 		} lws_end_foreach_dll_safe(e, e1);
674*1c60b9acSAndroid Build Coastguard Worker 
675*1c60b9acSAndroid Build Coastguard Worker 	} lws_end_foreach_dll_safe(d2, d3);
676*1c60b9acSAndroid Build Coastguard Worker 
677*1c60b9acSAndroid Build Coastguard Worker 	return 0;
678*1c60b9acSAndroid Build Coastguard Worker }
679*1c60b9acSAndroid Build Coastguard Worker 
680*1c60b9acSAndroid Build Coastguard Worker static int
lws_metrics_dump_cb(lws_metric_pub_t * pub,void * user)681*1c60b9acSAndroid Build Coastguard Worker lws_metrics_dump_cb(lws_metric_pub_t *pub, void *user)
682*1c60b9acSAndroid Build Coastguard Worker {
683*1c60b9acSAndroid Build Coastguard Worker 	struct lws_context *ctx = (struct lws_context *)user;
684*1c60b9acSAndroid Build Coastguard Worker 	int n;
685*1c60b9acSAndroid Build Coastguard Worker 
686*1c60b9acSAndroid Build Coastguard Worker 	if (!ctx->system_ops || !ctx->system_ops->metric_report)
687*1c60b9acSAndroid Build Coastguard Worker 		return 0;
688*1c60b9acSAndroid Build Coastguard Worker 
689*1c60b9acSAndroid Build Coastguard Worker 	/*
690*1c60b9acSAndroid Build Coastguard Worker 	 * return nonzero to reset stats
691*1c60b9acSAndroid Build Coastguard Worker 	 */
692*1c60b9acSAndroid Build Coastguard Worker 
693*1c60b9acSAndroid Build Coastguard Worker 	n = ctx->system_ops->metric_report(pub);
694*1c60b9acSAndroid Build Coastguard Worker 
695*1c60b9acSAndroid Build Coastguard Worker 	/* track when we dumped it... */
696*1c60b9acSAndroid Build Coastguard Worker 
697*1c60b9acSAndroid Build Coastguard Worker 	pub->us_first = pub->us_dumped = lws_now_usecs();
698*1c60b9acSAndroid Build Coastguard Worker 	pub->us_last = 0;
699*1c60b9acSAndroid Build Coastguard Worker 
700*1c60b9acSAndroid Build Coastguard Worker 	if (!n)
701*1c60b9acSAndroid Build Coastguard Worker 		return 0;
702*1c60b9acSAndroid Build Coastguard Worker 
703*1c60b9acSAndroid Build Coastguard Worker 	/* ... and clear it back to 0 */
704*1c60b9acSAndroid Build Coastguard Worker 
705*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_HIST) {
706*1c60b9acSAndroid Build Coastguard Worker 		lws_metric_bucket_t *b = pub->u.hist.head, *b1;
707*1c60b9acSAndroid Build Coastguard Worker 		pub->u.hist.head = NULL;
708*1c60b9acSAndroid Build Coastguard Worker 
709*1c60b9acSAndroid Build Coastguard Worker 		while (b) {
710*1c60b9acSAndroid Build Coastguard Worker 			b1 = b->next;
711*1c60b9acSAndroid Build Coastguard Worker 			lws_free(b);
712*1c60b9acSAndroid Build Coastguard Worker 			b = b1;
713*1c60b9acSAndroid Build Coastguard Worker 		}
714*1c60b9acSAndroid Build Coastguard Worker 		pub->u.hist.total_count = 0;
715*1c60b9acSAndroid Build Coastguard Worker 		pub->u.hist.list_size = 0;
716*1c60b9acSAndroid Build Coastguard Worker 	} else
717*1c60b9acSAndroid Build Coastguard Worker 		memset(&pub->u.agg, 0, sizeof(pub->u.agg));
718*1c60b9acSAndroid Build Coastguard Worker 
719*1c60b9acSAndroid Build Coastguard Worker 	return 0;
720*1c60b9acSAndroid Build Coastguard Worker }
721*1c60b9acSAndroid Build Coastguard Worker 
722*1c60b9acSAndroid Build Coastguard Worker void
lws_metrics_dump(struct lws_context * ctx)723*1c60b9acSAndroid Build Coastguard Worker lws_metrics_dump(struct lws_context *ctx)
724*1c60b9acSAndroid Build Coastguard Worker {
725*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_foreach(ctx, ctx, lws_metrics_dump_cb);
726*1c60b9acSAndroid Build Coastguard Worker }
727*1c60b9acSAndroid Build Coastguard Worker 
728*1c60b9acSAndroid Build Coastguard Worker static int
_lws_metrics_format(lws_metric_pub_t * pub,lws_usec_t now,int gng,char * buf,size_t len)729*1c60b9acSAndroid Build Coastguard Worker _lws_metrics_format(lws_metric_pub_t *pub, lws_usec_t now, int gng,
730*1c60b9acSAndroid Build Coastguard Worker 		    char *buf, size_t len)
731*1c60b9acSAndroid Build Coastguard Worker {
732*1c60b9acSAndroid Build Coastguard Worker 	const lws_humanize_unit_t *schema = humanize_schema_si;
733*1c60b9acSAndroid Build Coastguard Worker 	char *end = buf + len - 1, *obuf = buf;
734*1c60b9acSAndroid Build Coastguard Worker 
735*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US)
736*1c60b9acSAndroid Build Coastguard Worker 		schema = humanize_schema_us;
737*1c60b9acSAndroid Build Coastguard Worker 
738*1c60b9acSAndroid Build Coastguard Worker 	if (!(pub->flags & LWSMTFL_REPORT_MEAN)) {
739*1c60b9acSAndroid Build Coastguard Worker 		/* only the sum is meaningful */
740*1c60b9acSAndroid Build Coastguard Worker 		if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US) {
741*1c60b9acSAndroid Build Coastguard Worker 
742*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), " %u, ",
743*1c60b9acSAndroid Build Coastguard Worker 						(unsigned int)pub->u.agg.count[gng]);
744*1c60b9acSAndroid Build Coastguard Worker 
745*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
746*1c60b9acSAndroid Build Coastguard Worker 					    (uint64_t)pub->u.agg.sum[gng],
747*1c60b9acSAndroid Build Coastguard Worker 					    humanize_schema_us);
748*1c60b9acSAndroid Build Coastguard Worker 
749*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), " / ");
750*1c60b9acSAndroid Build Coastguard Worker 
751*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
752*1c60b9acSAndroid Build Coastguard Worker 					    (uint64_t)(now - pub->us_first),
753*1c60b9acSAndroid Build Coastguard Worker 					    humanize_schema_us);
754*1c60b9acSAndroid Build Coastguard Worker 
755*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
756*1c60b9acSAndroid Build Coastguard Worker 					    " (%d%%)", (int)((100 * pub->u.agg.sum[gng]) /
757*1c60b9acSAndroid Build Coastguard Worker 						(unsigned long)(now - pub->us_first)));
758*1c60b9acSAndroid Build Coastguard Worker 		} else {
759*1c60b9acSAndroid Build Coastguard Worker 			/* it's a monotonic ordinal, like total tx */
760*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "(%u) ",
761*1c60b9acSAndroid Build Coastguard Worker 					(unsigned int)pub->u.agg.count[gng]);
762*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
763*1c60b9acSAndroid Build Coastguard Worker 					    (uint64_t)pub->u.agg.sum[gng],
764*1c60b9acSAndroid Build Coastguard Worker 					    humanize_schema_si);
765*1c60b9acSAndroid Build Coastguard Worker 		}
766*1c60b9acSAndroid Build Coastguard Worker 
767*1c60b9acSAndroid Build Coastguard Worker 	} else {
768*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%u, mean: ", (unsigned int)pub->u.agg.count[gng]);
769*1c60b9acSAndroid Build Coastguard Worker 		/* the average over the period is meaningful */
770*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf),
771*1c60b9acSAndroid Build Coastguard Worker 				    (uint64_t)(pub->u.agg.count[gng] ?
772*1c60b9acSAndroid Build Coastguard Worker 					 pub->u.agg.sum[gng] / pub->u.agg.count[gng] : 0),
773*1c60b9acSAndroid Build Coastguard Worker 				    schema);
774*1c60b9acSAndroid Build Coastguard Worker 	}
775*1c60b9acSAndroid Build Coastguard Worker 
776*1c60b9acSAndroid Build Coastguard Worker 	return lws_ptr_diff(buf, obuf);
777*1c60b9acSAndroid Build Coastguard Worker }
778*1c60b9acSAndroid Build Coastguard Worker 
779*1c60b9acSAndroid Build Coastguard Worker int
lws_metrics_format(lws_metric_pub_t * pub,lws_metric_bucket_t ** sub,char * buf,size_t len)780*1c60b9acSAndroid Build Coastguard Worker lws_metrics_format(lws_metric_pub_t *pub, lws_metric_bucket_t **sub, char *buf, size_t len)
781*1c60b9acSAndroid Build Coastguard Worker {
782*1c60b9acSAndroid Build Coastguard Worker 	char *end = buf + len - 1, *obuf = buf;
783*1c60b9acSAndroid Build Coastguard Worker 	lws_usec_t t = lws_now_usecs();
784*1c60b9acSAndroid Build Coastguard Worker 	const lws_humanize_unit_t *schema = humanize_schema_si;
785*1c60b9acSAndroid Build Coastguard Worker 
786*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_DUTY_WALLCLOCK_US)
787*1c60b9acSAndroid Build Coastguard Worker 		schema = humanize_schema_us;
788*1c60b9acSAndroid Build Coastguard Worker 
789*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_HIST) {
790*1c60b9acSAndroid Build Coastguard Worker 
791*1c60b9acSAndroid Build Coastguard Worker 		if (*sub == NULL)
792*1c60b9acSAndroid Build Coastguard Worker 			return 0;
793*1c60b9acSAndroid Build Coastguard Worker 
794*1c60b9acSAndroid Build Coastguard Worker 		if (*sub) {
795*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
796*1c60b9acSAndroid Build Coastguard Worker 					    "%s{%s} %llu", pub->name,
797*1c60b9acSAndroid Build Coastguard Worker 					    lws_metric_bucket_name(*sub),
798*1c60b9acSAndroid Build Coastguard Worker 					    (unsigned long long)(*sub)->count);
799*1c60b9acSAndroid Build Coastguard Worker 
800*1c60b9acSAndroid Build Coastguard Worker 			*sub = (*sub)->next;
801*1c60b9acSAndroid Build Coastguard Worker 		}
802*1c60b9acSAndroid Build Coastguard Worker 
803*1c60b9acSAndroid Build Coastguard Worker 		goto happy;
804*1c60b9acSAndroid Build Coastguard Worker 	}
805*1c60b9acSAndroid Build Coastguard Worker 
806*1c60b9acSAndroid Build Coastguard Worker 	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s: ",
807*1c60b9acSAndroid Build Coastguard Worker 				pub->name);
808*1c60b9acSAndroid Build Coastguard Worker 
809*1c60b9acSAndroid Build Coastguard Worker 	if (!pub->u.agg.count[METRES_GO] && !pub->u.agg.count[METRES_NOGO])
810*1c60b9acSAndroid Build Coastguard Worker 		return 0;
811*1c60b9acSAndroid Build Coastguard Worker 
812*1c60b9acSAndroid Build Coastguard Worker 	if (pub->u.agg.count[METRES_GO]) {
813*1c60b9acSAndroid Build Coastguard Worker 		if (!(pub->flags & LWSMTFL_REPORT_ONLY_GO))
814*1c60b9acSAndroid Build Coastguard Worker 			buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
815*1c60b9acSAndroid Build Coastguard Worker 					    "Go: ");
816*1c60b9acSAndroid Build Coastguard Worker 		buf += _lws_metrics_format(pub, t, METRES_GO, buf,
817*1c60b9acSAndroid Build Coastguard Worker 					   lws_ptr_diff_size_t(end, buf));
818*1c60b9acSAndroid Build Coastguard Worker 	}
819*1c60b9acSAndroid Build Coastguard Worker 
820*1c60b9acSAndroid Build Coastguard Worker 	if (!(pub->flags & LWSMTFL_REPORT_ONLY_GO) && pub->u.agg.count[METRES_NOGO]) {
821*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), ", NoGo: ");
822*1c60b9acSAndroid Build Coastguard Worker 		buf += _lws_metrics_format(pub, t, METRES_NOGO, buf,
823*1c60b9acSAndroid Build Coastguard Worker 					   lws_ptr_diff_size_t(end, buf));
824*1c60b9acSAndroid Build Coastguard Worker 	}
825*1c60b9acSAndroid Build Coastguard Worker 
826*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_MEAN) {
827*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), ", min: ");
828*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf), pub->u.agg.min,
829*1c60b9acSAndroid Build Coastguard Worker 				    schema);
830*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), ", max: ");
831*1c60b9acSAndroid Build Coastguard Worker 		buf += lws_humanize(buf, lws_ptr_diff_size_t(end, buf), pub->u.agg.max,
832*1c60b9acSAndroid Build Coastguard Worker 				    schema);
833*1c60b9acSAndroid Build Coastguard Worker 	}
834*1c60b9acSAndroid Build Coastguard Worker 
835*1c60b9acSAndroid Build Coastguard Worker happy:
836*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_HIST)
837*1c60b9acSAndroid Build Coastguard Worker 		return 1;
838*1c60b9acSAndroid Build Coastguard Worker 
839*1c60b9acSAndroid Build Coastguard Worker 	*sub = NULL;
840*1c60b9acSAndroid Build Coastguard Worker 
841*1c60b9acSAndroid Build Coastguard Worker 	return lws_ptr_diff(buf, obuf);
842*1c60b9acSAndroid Build Coastguard Worker }
843*1c60b9acSAndroid Build Coastguard Worker 
844*1c60b9acSAndroid Build Coastguard Worker /*
845*1c60b9acSAndroid Build Coastguard Worker  * We want to, at least internally, record an event... depending on the policy,
846*1c60b9acSAndroid Build Coastguard Worker  * that might cause us to call through to the lws_system apis, or just update
847*1c60b9acSAndroid Build Coastguard Worker  * our local stats about it and dump at the next periodic chance (also set by
848*1c60b9acSAndroid Build Coastguard Worker  * the policy)
849*1c60b9acSAndroid Build Coastguard Worker  */
850*1c60b9acSAndroid Build Coastguard Worker 
851*1c60b9acSAndroid Build Coastguard Worker void
lws_metric_event(lws_metric_t * mt,char go_nogo,u_mt_t val)852*1c60b9acSAndroid Build Coastguard Worker lws_metric_event(lws_metric_t *mt, char go_nogo, u_mt_t val)
853*1c60b9acSAndroid Build Coastguard Worker {
854*1c60b9acSAndroid Build Coastguard Worker 	lws_metric_pub_t *pub;
855*1c60b9acSAndroid Build Coastguard Worker 
856*1c60b9acSAndroid Build Coastguard Worker 	assert((go_nogo & 0xfe) == 0);
857*1c60b9acSAndroid Build Coastguard Worker 
858*1c60b9acSAndroid Build Coastguard Worker 	if (!mt)
859*1c60b9acSAndroid Build Coastguard Worker 		return;
860*1c60b9acSAndroid Build Coastguard Worker 
861*1c60b9acSAndroid Build Coastguard Worker 	pub = lws_metrics_priv_to_pub(mt);
862*1c60b9acSAndroid Build Coastguard Worker 	assert(!(pub->flags & LWSMTFL_REPORT_HIST));
863*1c60b9acSAndroid Build Coastguard Worker 
864*1c60b9acSAndroid Build Coastguard Worker 	pub->us_last = lws_now_usecs();
865*1c60b9acSAndroid Build Coastguard Worker 	if (!pub->us_first)
866*1c60b9acSAndroid Build Coastguard Worker 		pub->us_first = pub->us_last;
867*1c60b9acSAndroid Build Coastguard Worker 	pub->u.agg.count[(int)go_nogo]++;
868*1c60b9acSAndroid Build Coastguard Worker 	pub->u.agg.sum[(int)go_nogo] += val;
869*1c60b9acSAndroid Build Coastguard Worker 	if (val > pub->u.agg.max)
870*1c60b9acSAndroid Build Coastguard Worker 		pub->u.agg.max = val;
871*1c60b9acSAndroid Build Coastguard Worker 	if (val < pub->u.agg.min)
872*1c60b9acSAndroid Build Coastguard Worker 		pub->u.agg.min = val;
873*1c60b9acSAndroid Build Coastguard Worker 
874*1c60b9acSAndroid Build Coastguard Worker 	if (pub->flags & LWSMTFL_REPORT_OOB)
875*1c60b9acSAndroid Build Coastguard Worker 		lws_metrics_report_and_maybe_clear(mt->ctx, pub);
876*1c60b9acSAndroid Build Coastguard Worker }
877*1c60b9acSAndroid Build Coastguard Worker 
878*1c60b9acSAndroid Build Coastguard Worker 
879*1c60b9acSAndroid Build Coastguard Worker void
lws_metrics_hist_bump_priv_tagged(lws_metric_pub_t * mt,lws_dll2_owner_t * tow,lws_dll2_owner_t * tow2)880*1c60b9acSAndroid Build Coastguard Worker lws_metrics_hist_bump_priv_tagged(lws_metric_pub_t *mt, lws_dll2_owner_t *tow,
881*1c60b9acSAndroid Build Coastguard Worker 				  lws_dll2_owner_t *tow2)
882*1c60b9acSAndroid Build Coastguard Worker {
883*1c60b9acSAndroid Build Coastguard Worker 	char qual[192];
884*1c60b9acSAndroid Build Coastguard Worker 	size_t p;
885*1c60b9acSAndroid Build Coastguard Worker 
886*1c60b9acSAndroid Build Coastguard Worker 	p = lws_metrics_tags_serialize(tow, qual, sizeof(qual));
887*1c60b9acSAndroid Build Coastguard Worker 	if (tow2)
888*1c60b9acSAndroid Build Coastguard Worker 		lws_metrics_tags_serialize(tow2, qual + p,
889*1c60b9acSAndroid Build Coastguard Worker 				sizeof(qual) - p);
890*1c60b9acSAndroid Build Coastguard Worker 
891*1c60b9acSAndroid Build Coastguard Worker 	lws_metrics_hist_bump(mt, qual);
892*1c60b9acSAndroid Build Coastguard Worker }
893