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