1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * stats.c -- simple stats tracking table module
27  *
28  */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <sys/types.h>
33 #include <strings.h>
34 #include "stats.h"
35 #include "alloc.h"
36 #include "out.h"
37 
38 struct stats {
39 	struct stats *next;
40 	const char *name;
41 	const char *desc;
42 	enum stats_type {
43 		STATS_COUNTER = 3000,
44 		STATS_ELAPSE,
45 		STATS_STRING
46 	} t;
47 	union {
48 		int counter;
49 		struct {
50 			hrtime_t start;
51 			hrtime_t stop;
52 		} elapse;
53 		const char *string;
54 	} u;
55 };
56 
57 static int Ext;			/* true if extended stats are enabled */
58 static struct stats *Statslist;
59 static struct stats *Laststats;
60 
61 
62 /*
63  * stats_init -- initialize the stats module
64  *
65  */
66 
67 void
stats_init(int ext)68 stats_init(int ext)
69 {
70 	Ext = ext;
71 }
72 
73 void
stats_fini(void)74 stats_fini(void)
75 {
76 }
77 
78 static struct stats *
stats_new(const char * name,const char * desc,enum stats_type t)79 stats_new(const char *name, const char *desc, enum stats_type t)
80 {
81 	struct stats *ret = MALLOC(sizeof (*ret));
82 
83 	bzero(ret, sizeof (*ret));
84 	ret->t = t;
85 	ret->name = STRDUP(name);
86 	ret->desc = STRDUP(desc);
87 
88 	if (Laststats == NULL)
89 		Statslist = ret;
90 	else
91 		Laststats->next = ret;
92 	Laststats = ret;
93 
94 	return (ret);
95 }
96 
97 void
stats_delete(struct stats * sp)98 stats_delete(struct stats *sp)
99 {
100 	struct stats *p, *s;
101 
102 	if (sp == NULL)
103 		return;
104 
105 	for (p = NULL, s = Statslist; s != NULL; s = s->next)
106 		if (s == sp)
107 			break;
108 
109 	if (s == NULL)
110 		return;
111 
112 	if (p == NULL)
113 		Statslist = s->next;
114 	else
115 		p->next = s->next;
116 
117 	if (s == Laststats)
118 		Laststats = p;
119 
120 	FREE((void *)sp->name);
121 	FREE((void *)sp->desc);
122 	FREE(sp);
123 }
124 
125 struct stats *
stats_new_counter(const char * name,const char * desc,int ext)126 stats_new_counter(const char *name, const char *desc, int ext)
127 {
128 	if (ext && !Ext)
129 		return (NULL);		/* extended stats not enabled */
130 
131 	return (stats_new(name, desc, STATS_COUNTER));
132 }
133 
134 void
stats_counter_bump(struct stats * sp)135 stats_counter_bump(struct stats *sp)
136 {
137 	if (sp == NULL)
138 		return;
139 
140 	ASSERT(sp->t == STATS_COUNTER);
141 
142 	sp->u.counter++;
143 }
144 
145 void
stats_counter_add(struct stats * sp,int n)146 stats_counter_add(struct stats *sp, int n)
147 {
148 	if (sp == NULL)
149 		return;
150 
151 	ASSERT(sp->t == STATS_COUNTER);
152 
153 	sp->u.counter += n;
154 }
155 
156 void
stats_counter_reset(struct stats * sp)157 stats_counter_reset(struct stats *sp)
158 {
159 	if (sp == NULL)
160 		return;
161 
162 	ASSERT(sp->t == STATS_COUNTER);
163 
164 	sp->u.counter = 0;
165 }
166 
167 int
stats_counter_value(struct stats * sp)168 stats_counter_value(struct stats *sp)
169 {
170 	if (sp == NULL)
171 		return (0);
172 
173 	ASSERT(sp->t == STATS_COUNTER);
174 
175 	return (sp->u.counter);
176 }
177 
178 struct stats *
stats_new_elapse(const char * name,const char * desc,int ext)179 stats_new_elapse(const char *name, const char *desc, int ext)
180 {
181 	if (ext && !Ext)
182 		return (NULL);		/* extended stats not enabled */
183 
184 	return (stats_new(name, desc, STATS_ELAPSE));
185 }
186 
187 void
stats_elapse_start(struct stats * sp)188 stats_elapse_start(struct stats *sp)
189 {
190 	if (sp == NULL)
191 		return;
192 
193 	ASSERT(sp->t == STATS_ELAPSE);
194 
195 	sp->u.elapse.start = gethrtime();
196 }
197 
198 void
stats_elapse_stop(struct stats * sp)199 stats_elapse_stop(struct stats *sp)
200 {
201 	if (sp == NULL)
202 		return;
203 
204 	ASSERT(sp->t == STATS_ELAPSE);
205 
206 	sp->u.elapse.stop = gethrtime();
207 }
208 
209 struct stats *
stats_new_string(const char * name,const char * desc,int ext)210 stats_new_string(const char *name, const char *desc, int ext)
211 {
212 	if (ext && !Ext)
213 		return (NULL);		/* extended stats not enabled */
214 
215 	return (stats_new(name, desc, STATS_STRING));
216 }
217 
218 void
stats_string_set(struct stats * sp,const char * s)219 stats_string_set(struct stats *sp, const char *s)
220 {
221 	if (sp == NULL)
222 		return;
223 
224 	ASSERT(sp->t == STATS_STRING);
225 
226 	sp->u.string = s;
227 }
228 
229 /*
230  * stats_publish -- spew all stats
231  *
232  */
233 
234 void
stats_publish(void)235 stats_publish(void)
236 {
237 	struct stats *sp;
238 
239 	for (sp = Statslist; sp; sp = sp->next)
240 		switch (sp->t) {
241 		case STATS_COUNTER:
242 			out(O_OK, "%32s %13d %s", sp->name,
243 			    sp->u.counter, sp->desc);
244 			break;
245 
246 		case STATS_ELAPSE:
247 			if (sp->u.elapse.start && sp->u.elapse.stop) {
248 				hrtime_t delta =
249 				    sp->u.elapse.stop - sp->u.elapse.start;
250 
251 				out(O_OK, "%32s %11lldns %s", sp->name,
252 				    delta, sp->desc);
253 			}
254 			break;
255 
256 		case STATS_STRING:
257 			out(O_OK, "%32s %13s %s", sp->name, sp->u.string,
258 			    sp->desc);
259 			break;
260 
261 		default:
262 			out(O_DIE, "stats_publish: unknown type %d", sp->t);
263 		}
264 }
265