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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Common routines for acquiring snapshots of kstats for 26 * iostat, mpstat, and vmstat. 27 */ 28 29 #ifndef _STATCOMMON_H 30 #define _STATCOMMON_H 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #ifdef __cplusplus 35 extern "C" { 36 #endif 37 38 #include <stdio.h> 39 #include <kstat.h> 40 #include <sys/time.h> 41 #include <sys/types.h> 42 #include <sys/buf.h> 43 #include <sys/dnlc.h> 44 #include <sys/sysinfo.h> 45 #include <sys/vmmeter.h> 46 #include <sys/processor.h> 47 #include <sys/pset.h> 48 49 /* No CPU present at this CPU position */ 50 #define ID_NO_CPU -1 51 /* CPU belongs to no pset (we number this as "pset 0") */ 52 #define ID_NO_PSET 0 53 /* CPU is usable */ 54 #define CPU_ONLINE(s) ((s) == P_ONLINE || (s) == P_NOINTR) 55 /* will the CPU have kstats */ 56 #define CPU_ACTIVE(c) (CPU_ONLINE((c)->cs_state) && (c)->cs_id != ID_NO_CPU) 57 /* IO device has no identified ID */ 58 #define IODEV_NO_ID -1 59 /* no limit to iodevs to collect */ 60 #define UNLIMITED_IODEVS ((size_t)-1) 61 62 enum snapshot_types { 63 /* All CPUs separately */ 64 SNAP_CPUS = 1 << 0, 65 /* Aggregated processor sets */ 66 SNAP_PSETS = 1 << 1, 67 /* sys-wide stats including aggregated CPU stats */ 68 SNAP_SYSTEM = 1 << 2, 69 /* interrupt sources and counts */ 70 SNAP_INTERRUPTS = 1 << 3, 71 /* cache flushes */ 72 SNAP_FLUSHES = 1 << 4, 73 /* disk etc. stats */ 74 SNAP_IODEVS = 1 << 5, 75 /* disk controller aggregates */ 76 SNAP_CONTROLLERS = 1 << 6, 77 /* mpxio (multipath) paths */ 78 SNAP_IOPATHS = 1 << 7, 79 /* disk error stats */ 80 SNAP_IODEV_ERRORS = 1 << 8, 81 /* pretty names for iodevs */ 82 SNAP_IODEV_PRETTY = 1 << 9, 83 /* devid for iodevs */ 84 SNAP_IODEV_DEVID = 1 << 10 85 }; 86 87 struct cpu_snapshot { 88 /* may be ID_NO_CPU if no CPU present */ 89 processorid_t cs_id; 90 /* may be ID_NO_PSET if no pset */ 91 psetid_t cs_pset_id; 92 /* as in p_online(2) */ 93 int cs_state; 94 /* stats for this CPU */ 95 kstat_t cs_vm; 96 kstat_t cs_sys; 97 }; 98 99 struct pset_snapshot { 100 /* ID may be zero to indicate the "none set" */ 101 psetid_t ps_id; 102 /* number of CPUs in set */ 103 size_t ps_nr_cpus; 104 /* the CPUs in this set */ 105 struct cpu_snapshot **ps_cpus; 106 }; 107 108 struct intr_snapshot { 109 /* name of interrupt source */ 110 char is_name[KSTAT_STRLEN]; 111 /* total number of interrupts from this source */ 112 ulong_t is_total; 113 }; 114 115 struct sys_snapshot { 116 sysinfo_t ss_sysinfo; 117 vminfo_t ss_vminfo; 118 struct nc_stats ss_nc; 119 /* vm/sys stats aggregated across all CPUs */ 120 kstat_t ss_agg_vm; 121 kstat_t ss_agg_sys; 122 /* ticks since boot */ 123 ulong_t ss_ticks; 124 long ss_deficit; 125 }; 126 127 /* order is significant (see sort_before()) */ 128 enum iodev_type { 129 IODEV_CONTROLLER = 1 << 0, 130 IODEV_DISK = 1 << 1, 131 IODEV_PARTITION = 1 << 2, 132 IODEV_TAPE = 1 << 3, 133 IODEV_NFS = 1 << 4, 134 IODEV_IOPATH = 1 << 5, 135 IODEV_UNKNOWN = 1 << 6 136 }; 137 138 /* identify a disk, partition, etc. */ 139 struct iodev_id { 140 int id; 141 /* target id (for disks) */ 142 char tid[KSTAT_STRLEN]; 143 }; 144 145 /* 146 * Used for disks, partitions, tapes, nfs, controllers, iopaths 147 * Each entry can be a branch of a tree; for example, the disks 148 * of a controller constitute the children of the controller 149 * iodev_snapshot. This relationship is not strictly maintained 150 * if is_pretty can't be found. 151 */ 152 struct iodev_snapshot { 153 /* original kstat name */ 154 char is_name[KSTAT_STRLEN]; 155 enum iodev_type is_type; 156 /* ID if meaningful */ 157 struct iodev_id is_id; 158 /* parent ID if meaningful */ 159 struct iodev_id is_parent_id; 160 /* user-friendly name if found */ 161 char *is_pretty; 162 /* device ID if applicable */ 163 char *is_devid; 164 /* mount-point if applicable */ 165 char *is_dname; 166 /* number of direct children */ 167 int is_nr_children; 168 /* children of this I/O device */ 169 struct iodev_snapshot *is_children; 170 /* standard I/O stats */ 171 kstat_io_t is_stats; 172 /* iodev error stats */ 173 kstat_t is_errors; 174 /* creation time of the stats */ 175 hrtime_t is_crtime; 176 /* time at which iodev snapshot was taken */ 177 hrtime_t is_snaptime; 178 /* kstat module */ 179 char is_module[KSTAT_STRLEN]; 180 /* kstat instance */ 181 int is_instance; 182 /* kstat (only used temporarily) */ 183 kstat_t *is_ksp; 184 struct iodev_snapshot *is_prev; 185 struct iodev_snapshot *is_next; 186 }; 187 188 /* which iodevs to show. */ 189 struct iodev_filter { 190 /* nr. of iodevs to choose */ 191 size_t if_max_iodevs; 192 /* bit mask of enum io_types to allow */ 193 int if_allowed_types; 194 /* should we show floppy ? if_names can override this */ 195 int if_skip_floppy; 196 /* nr. of named iodevs */ 197 size_t if_nr_names; 198 char **if_names; 199 }; 200 201 /* The primary structure of a system snapshot. */ 202 struct snapshot { 203 /* what types were *requested* */ 204 enum snapshot_types s_types; 205 size_t s_nr_cpus; 206 struct cpu_snapshot *s_cpus; 207 size_t s_nr_psets; 208 struct pset_snapshot *s_psets; 209 size_t s_nr_intrs; 210 struct intr_snapshot *s_intrs; 211 size_t s_nr_iodevs; 212 struct iodev_snapshot *s_iodevs; 213 struct sys_snapshot s_sys; 214 struct biostats s_biostats; 215 struct flushmeter s_flushes; 216 }; 217 218 /* print a message and exit with failure */ 219 void fail(int do_perror, char *message, ...); 220 221 /* strdup str, or exit with failure */ 222 char *safe_strdup(char *str); 223 224 /* malloc successfully, or exit with failure */ 225 void *safe_alloc(size_t size); 226 227 /* 228 * Copy a kstat from src to dst. If the source kstat contains no data, 229 * then set the destination kstat data to NULL and size to zero. 230 * Returns 0 on success. 231 */ 232 int kstat_copy(const kstat_t *src, kstat_t *dst); 233 234 /* 235 * Look up the named kstat, and give the ui64 difference i.e. 236 * new - old, or if old is NULL, return new. 237 */ 238 uint64_t kstat_delta(kstat_t *old, kstat_t *new, char *name); 239 240 /* 241 * Add the integer-valued stats from "src" to the 242 * existing ones in "dst". If "dst" does not contain 243 * stats, then a kstat_copy() is performed. 244 */ 245 int kstat_add(const kstat_t *src, kstat_t *dst); 246 247 /* return the number of CPUs with kstats (i.e. present and online) */ 248 int nr_active_cpus(struct snapshot *ss); 249 250 /* 251 * Return the difference in CPU ticks between the two sys 252 * kstats. 253 */ 254 uint64_t cpu_ticks_delta(kstat_t *old, kstat_t *new); 255 256 /* 257 * Open the kstat chain. Cannot fail. 258 */ 259 kstat_ctl_t *open_kstat(void); 260 261 /* 262 * Return a struct snapshot based on the snapshot_types parameter 263 * passed in. iodev_filter may be NULL in which case all iodevs 264 * are selected if SNAP_IODEVS is passed. 265 */ 266 struct snapshot *acquire_snapshot(kstat_ctl_t *, int, struct iodev_filter *); 267 268 /* free a snapshot */ 269 void free_snapshot(struct snapshot *ss); 270 271 typedef void (*snapshot_cb)(void *old, void *new, void *data); 272 273 /* 274 * Call the call back for each pair of data items of the given type, 275 * passing the data pointer passed in as well. If an item has been 276 * added, the first pointer will be NULL; if removed, the second pointer 277 * will be NULL. 278 * 279 * A non-zero return value indicates configuration has changed. 280 */ 281 int snapshot_walk(enum snapshot_types type, struct snapshot *old, 282 struct snapshot *new, snapshot_cb cb, void *data); 283 284 /* 285 * Output a line detailing any configuration changes such as a CPU 286 * brought online, etc, bracketed by << >>. 287 */ 288 void snapshot_report_changes(struct snapshot *old, struct snapshot *new); 289 290 /* Return non-zero if configuration has changed. */ 291 int snapshot_has_changed(struct snapshot *old, struct snapshot *new); 292 293 /* free the given iodev */ 294 void free_iodev(struct iodev_snapshot *iodev); 295 296 /* acquire the I/O devices */ 297 int acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, 298 struct iodev_filter *df); 299 300 /* strcmp-style I/O device comparator */ 301 int iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2); 302 303 #ifdef __cplusplus 304 } 305 #endif 306 307 #endif /* _STATCOMMON_H */ 308