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
38struct 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
57static int Ext;			/* true if extended stats are enabled */
58static struct stats *Statslist;
59static struct stats *Laststats;
60
61
62/*
63 * stats_init -- initialize the stats module
64 *
65 */
66
67void
68stats_init(int ext)
69{
70	Ext = ext;
71}
72
73void
74stats_fini(void)
75{
76}
77
78static struct stats *
79stats_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
97void
98stats_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
125struct stats *
126stats_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
134void
135stats_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
145void
146stats_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
156void
157stats_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
167int
168stats_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
178struct stats *
179stats_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
187void
188stats_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
198void
199stats_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
209struct stats *
210stats_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
218void
219stats_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
234void
235stats_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