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 #include <sys/types.h>
31 #include <strings.h>
32 #include "stats.h"
33 #include "alloc.h"
34 #include "out.h"
35 
36 struct stats {
37 	struct stats *next;
38 	const char *name;
39 	const char *desc;
40 	enum stats_type {
41 		STATS_COUNTER = 3000,
42 		STATS_ELAPSE,
43 		STATS_STRING
44 	} t;
45 	union {
46 		int counter;
47 		struct {
48 			hrtime_t start;
49 			hrtime_t stop;
50 		} elapse;
51 		const char *string;
52 	} u;
53 };
54 
55 static int Ext;			/* true if extended stats are enabled */
56 static struct stats *Statslist;
57 static struct stats *Laststats;
58 
59 
60 /*
61  * stats_init -- initialize the stats module
62  *
63  */
64 
65 void
stats_init(int ext)66 stats_init(int ext)
67 {
68 	Ext = ext;
69 }
70 
71 void
stats_fini(void)72 stats_fini(void)
73 {
74 }
75 
76 static struct stats *
stats_new(const char * name,const char * desc,enum stats_type t)77 stats_new(const char *name, const char *desc, enum stats_type t)
78 {
79 	struct stats *ret = MALLOC(sizeof (*ret));
80 
81 	bzero(ret, sizeof (*ret));
82 	ret->t = t;
83 	ret->name = STRDUP(name);
84 	ret->desc = STRDUP(desc);
85 
86 	if (Laststats == NULL)
87 		Statslist = ret;
88 	else
89 		Laststats->next = ret;
90 	Laststats = ret;
91 
92 	return (ret);
93 }
94 
95 void
stats_delete(struct stats * sp)96 stats_delete(struct stats *sp)
97 {
98 	struct stats *p, *s;
99 
100 	if (sp == NULL)
101 		return;
102 
103 	for (p = NULL, s = Statslist; s != NULL; s = s->next)
104 		if (s == sp)
105 			break;
106 
107 	if (s == NULL)
108 		return;
109 
110 	if (p == NULL)
111 		Statslist = s->next;
112 	else
113 		p->next = s->next;
114 
115 	if (s == Laststats)
116 		Laststats = p;
117 
118 	FREE((void *)sp->name);
119 	FREE((void *)sp->desc);
120 	FREE(sp);
121 }
122 
123 struct stats *
stats_new_counter(const char * name,const char * desc,int ext)124 stats_new_counter(const char *name, const char *desc, int ext)
125 {
126 	if (ext && !Ext)
127 		return (NULL);		/* extended stats not enabled */
128 
129 	return (stats_new(name, desc, STATS_COUNTER));
130 }
131 
132 void
stats_counter_bump(struct stats * sp)133 stats_counter_bump(struct stats *sp)
134 {
135 	if (sp == NULL)
136 		return;
137 
138 	ASSERT(sp->t == STATS_COUNTER);
139 
140 	sp->u.counter++;
141 }
142 
143 void
stats_counter_add(struct stats * sp,int n)144 stats_counter_add(struct stats *sp, int n)
145 {
146 	if (sp == NULL)
147 		return;
148 
149 	ASSERT(sp->t == STATS_COUNTER);
150 
151 	sp->u.counter += n;
152 }
153 
154 void
stats_counter_reset(struct stats * sp)155 stats_counter_reset(struct stats *sp)
156 {
157 	if (sp == NULL)
158 		return;
159 
160 	ASSERT(sp->t == STATS_COUNTER);
161 
162 	sp->u.counter = 0;
163 }
164 
165 int
stats_counter_value(struct stats * sp)166 stats_counter_value(struct stats *sp)
167 {
168 	if (sp == NULL)
169 		return (0);
170 
171 	ASSERT(sp->t == STATS_COUNTER);
172 
173 	return (sp->u.counter);
174 }
175 
176 struct stats *
stats_new_elapse(const char * name,const char * desc,int ext)177 stats_new_elapse(const char *name, const char *desc, int ext)
178 {
179 	if (ext && !Ext)
180 		return (NULL);		/* extended stats not enabled */
181 
182 	return (stats_new(name, desc, STATS_ELAPSE));
183 }
184 
185 void
stats_elapse_start(struct stats * sp)186 stats_elapse_start(struct stats *sp)
187 {
188 	if (sp == NULL)
189 		return;
190 
191 	ASSERT(sp->t == STATS_ELAPSE);
192 
193 	sp->u.elapse.start = gethrtime();
194 }
195 
196 void
stats_elapse_stop(struct stats * sp)197 stats_elapse_stop(struct stats *sp)
198 {
199 	if (sp == NULL)
200 		return;
201 
202 	ASSERT(sp->t == STATS_ELAPSE);
203 
204 	sp->u.elapse.stop = gethrtime();
205 }
206 
207 struct stats *
stats_new_string(const char * name,const char * desc,int ext)208 stats_new_string(const char *name, const char *desc, int ext)
209 {
210 	if (ext && !Ext)
211 		return (NULL);		/* extended stats not enabled */
212 
213 	return (stats_new(name, desc, STATS_STRING));
214 }
215 
216 void
stats_string_set(struct stats * sp,const char * s)217 stats_string_set(struct stats *sp, const char *s)
218 {
219 	if (sp == NULL)
220 		return;
221 
222 	ASSERT(sp->t == STATS_STRING);
223 
224 	sp->u.string = s;
225 }
226 
227 /*
228  * stats_publish -- spew all stats
229  *
230  */
231 
232 void
stats_publish(void)233 stats_publish(void)
234 {
235 	struct stats *sp;
236 
237 	for (sp = Statslist; sp; sp = sp->next)
238 		switch (sp->t) {
239 		case STATS_COUNTER:
240 			out(O_OK, "%32s %13d %s", sp->name,
241 			    sp->u.counter, sp->desc);
242 			break;
243 
244 		case STATS_ELAPSE:
245 			if (sp->u.elapse.start && sp->u.elapse.stop) {
246 				hrtime_t delta =
247 				    sp->u.elapse.stop - sp->u.elapse.start;
248 
249 				out(O_OK, "%32s %11lldns %s", sp->name,
250 				    delta, sp->desc);
251 			}
252 			break;
253 
254 		case STATS_STRING:
255 			out(O_OK, "%32s %13s %s", sp->name, sp->u.string,
256 			    sp->desc);
257 			break;
258 
259 		default:
260 			out(O_DIE, "stats_publish: unknown type %d", sp->t);
261 		}
262 }
263