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 66 stats_init(int ext) 67 { 68 Ext = ext; 69 } 70 71 void 72 stats_fini(void) 73 { 74 } 75 76 static struct stats * 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 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 * 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 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 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 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 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 * 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 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 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 * 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 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 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