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 2008 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 #include <sys/avl.h> 49 50 /* No CPU present at this CPU position */ 51 #define ID_NO_CPU -1 52 /* CPU belongs to no pset (we number this as "pset 0") */ 53 #define ID_NO_PSET 0 54 /* CPU is usable */ 55 #define CPU_ONLINE(s) ((s) == P_ONLINE || (s) == P_NOINTR) 56 /* will the CPU have kstats */ 57 #define CPU_ACTIVE(c) (CPU_ONLINE((c)->cs_state) && (c)->cs_id != ID_NO_CPU) 58 /* IO device has no identified ID */ 59 #define IODEV_NO_ID -1 60 /* no limit to iodevs to collect */ 61 #define UNLIMITED_IODEVS ((size_t)-1) 62 63 enum snapshot_types { 64 /* All CPUs separately */ 65 SNAP_CPUS = 1 << 0, 66 /* Aggregated processor sets */ 67 SNAP_PSETS = 1 << 1, 68 /* sys-wide stats including aggregated CPU stats */ 69 SNAP_SYSTEM = 1 << 2, 70 /* interrupt sources and counts */ 71 SNAP_INTERRUPTS = 1 << 3, 72 /* cache flushes */ 73 SNAP_FLUSHES = 1 << 4, 74 /* disk etc. stats */ 75 SNAP_IODEVS = 1 << 5, 76 /* disk controller aggregates */ 77 SNAP_CONTROLLERS = 1 << 6, 78 /* mpxio L I (multipath) paths: -X: Lun,LunInitiator */ 79 SNAP_IOPATHS_LI = 1 << 7, 80 /* mpxio LTI (multipath) paths: -Y: Lun,LunTarget,LunTargetInitiator */ 81 SNAP_IOPATHS_LTI = 1 << 8, 82 /* disk error stats */ 83 SNAP_IODEV_ERRORS = 1 << 9, 84 /* pretty names for iodevs */ 85 SNAP_IODEV_PRETTY = 1 << 10, 86 /* devid for iodevs */ 87 SNAP_IODEV_DEVID = 1 << 11 88 }; 89 90 struct cpu_snapshot { 91 /* may be ID_NO_CPU if no CPU present */ 92 processorid_t cs_id; 93 /* may be ID_NO_PSET if no pset */ 94 psetid_t cs_pset_id; 95 /* as in p_online(2) */ 96 int cs_state; 97 /* stats for this CPU */ 98 kstat_t cs_vm; 99 kstat_t cs_sys; 100 }; 101 102 struct pset_snapshot { 103 /* ID may be zero to indicate the "none set" */ 104 psetid_t ps_id; 105 /* number of CPUs in set */ 106 size_t ps_nr_cpus; 107 /* the CPUs in this set */ 108 struct cpu_snapshot **ps_cpus; 109 }; 110 111 struct intr_snapshot { 112 /* name of interrupt source */ 113 char is_name[KSTAT_STRLEN]; 114 /* total number of interrupts from this source */ 115 ulong_t is_total; 116 }; 117 118 struct sys_snapshot { 119 sysinfo_t ss_sysinfo; 120 vminfo_t ss_vminfo; 121 struct nc_stats ss_nc; 122 /* vm/sys stats aggregated across all CPUs */ 123 kstat_t ss_agg_vm; 124 kstat_t ss_agg_sys; 125 /* ticks since boot */ 126 ulong_t ss_ticks; 127 long ss_deficit; 128 }; 129 130 /* order is significant (see sort_before()) */ 131 enum iodev_type { 132 IODEV_CONTROLLER = 1 << 0, 133 IODEV_DISK = 1 << 1, 134 IODEV_PARTITION = 1 << 2, 135 IODEV_TAPE = 1 << 3, 136 IODEV_NFS = 1 << 4, 137 IODEV_IOPATH_LT = 1 << 5, /* synthetic LunTarget */ 138 IODEV_IOPATH_LI = 1 << 6, /* synthetic LunInitiator */ 139 IODEV_IOPATH_LTI = 1 << 7, /* LunTgtInitiator (pathinfo) */ 140 IODEV_UNKNOWN = 1 << 8 141 }; 142 143 /* identify a disk, partition, etc. */ 144 struct iodev_id { 145 int id; 146 /* target id (for disks) */ 147 char tid[KSTAT_STRLEN]; 148 }; 149 150 /* 151 * Used for disks, partitions, tapes, nfs, controllers, iopaths 152 * Each entry can be a branch of a tree; for example, the disks 153 * of a controller constitute the children of the controller 154 * iodev_snapshot. This relationship is not strictly maintained 155 * if is_pretty can't be found. 156 */ 157 struct iodev_snapshot { 158 /* original kstat name */ 159 char is_name[KSTAT_STRLEN]; 160 /* type of kstat */ 161 enum iodev_type is_type; 162 /* ID if meaningful */ 163 struct iodev_id is_id; 164 /* parent ID if meaningful */ 165 struct iodev_id is_parent_id; 166 /* user-friendly name if found */ 167 char *is_pretty; 168 /* device ID if applicable */ 169 char *is_devid; 170 /* mount-point if applicable */ 171 char *is_dname; 172 /* number of direct children */ 173 int is_nr_children; 174 /* children of this I/O device */ 175 struct iodev_snapshot *is_children; 176 /* standard I/O stats */ 177 kstat_io_t is_stats; 178 /* iodev error stats */ 179 kstat_t is_errors; 180 /* creation time of the stats */ 181 hrtime_t is_crtime; 182 /* time at which iodev snapshot was taken */ 183 hrtime_t is_snaptime; 184 /* kstat module */ 185 char is_module[KSTAT_STRLEN]; 186 /* kstat instance */ 187 int is_instance; 188 /* kstat (only used temporarily) */ 189 kstat_t *is_ksp; 190 struct iodev_snapshot *is_prev; 191 struct iodev_snapshot *is_next; 192 /* AVL structures to speedup insertion */ 193 avl_tree_t *avl_list; /* list this element belongs to */ 194 avl_node_t avl_link; 195 }; 196 197 /* which iodevs to show. */ 198 struct iodev_filter { 199 /* nr. of iodevs to choose */ 200 size_t if_max_iodevs; 201 /* bit mask of enum io_types to allow */ 202 int if_allowed_types; 203 /* should we show floppy ? if_names can override this */ 204 int if_skip_floppy; 205 /* nr. of named iodevs */ 206 size_t if_nr_names; 207 char **if_names; 208 }; 209 210 /* The primary structure of a system snapshot. */ 211 struct snapshot { 212 /* what types were *requested* */ 213 enum snapshot_types s_types; 214 size_t s_nr_cpus; 215 struct cpu_snapshot *s_cpus; 216 size_t s_nr_psets; 217 struct pset_snapshot *s_psets; 218 size_t s_nr_intrs; 219 struct intr_snapshot *s_intrs; 220 size_t s_nr_iodevs; 221 struct iodev_snapshot *s_iodevs; 222 size_t s_iodevs_is_name_maxlen; 223 struct sys_snapshot s_sys; 224 struct biostats s_biostats; 225 struct flushmeter s_flushes; 226 }; 227 228 /* print a message and exit with failure */ 229 void fail(int do_perror, char *message, ...); 230 231 /* strdup str, or exit with failure */ 232 char *safe_strdup(char *str); 233 234 /* malloc successfully, or exit with failure */ 235 void *safe_alloc(size_t size); 236 237 /* 238 * Copy a kstat from src to dst. If the source kstat contains no data, 239 * then set the destination kstat data to NULL and size to zero. 240 * Returns 0 on success. 241 */ 242 int kstat_copy(const kstat_t *src, kstat_t *dst); 243 244 /* 245 * Look up the named kstat, and give the ui64 difference i.e. 246 * new - old, or if old is NULL, return new. 247 */ 248 uint64_t kstat_delta(kstat_t *old, kstat_t *new, char *name); 249 250 /* Return the number of ticks delta between two hrtime_t values. */ 251 uint64_t hrtime_delta(hrtime_t old, hrtime_t new); 252 253 /* 254 * Add the integer-valued stats from "src" to the 255 * existing ones in "dst". If "dst" does not contain 256 * stats, then a kstat_copy() is performed. 257 */ 258 int kstat_add(const kstat_t *src, kstat_t *dst); 259 260 /* return the number of CPUs with kstats (i.e. present and online) */ 261 int nr_active_cpus(struct snapshot *ss); 262 263 /* 264 * Return the difference in CPU ticks between the two sys 265 * kstats. 266 */ 267 uint64_t cpu_ticks_delta(kstat_t *old, kstat_t *new); 268 269 /* 270 * Open the kstat chain. Cannot fail. 271 */ 272 kstat_ctl_t *open_kstat(void); 273 274 /* 275 * Return a struct snapshot based on the snapshot_types parameter 276 * passed in. iodev_filter may be NULL in which case all iodevs 277 * are selected if SNAP_IODEVS is passed. 278 */ 279 struct snapshot *acquire_snapshot(kstat_ctl_t *, int, struct iodev_filter *); 280 281 /* free a snapshot */ 282 void free_snapshot(struct snapshot *ss); 283 284 typedef void (*snapshot_cb)(void *old, void *new, void *data); 285 286 /* 287 * Call the call back for each pair of data items of the given type, 288 * passing the data pointer passed in as well. If an item has been 289 * added, the first pointer will be NULL; if removed, the second pointer 290 * will be NULL. 291 * 292 * A non-zero return value indicates configuration has changed. 293 */ 294 int snapshot_walk(enum snapshot_types type, struct snapshot *old, 295 struct snapshot *new, snapshot_cb cb, void *data); 296 297 /* 298 * Output a line detailing any configuration changes such as a CPU 299 * brought online, etc, bracketed by << >>. 300 */ 301 void snapshot_report_changes(struct snapshot *old, struct snapshot *new); 302 303 /* Return non-zero if configuration has changed. */ 304 int snapshot_has_changed(struct snapshot *old, struct snapshot *new); 305 306 /* free the given iodev */ 307 void free_iodev(struct iodev_snapshot *iodev); 308 309 /* acquire the I/O devices */ 310 int acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, 311 struct iodev_filter *df); 312 313 /* strcmp-style I/O device comparator */ 314 int iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2); 315 316 /* sleep until *wakeup + interval, keeping cadence where desired */ 317 void sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever, 318 int *caught_cont); 319 320 /* signal handler - so we can be aware of SIGCONT */ 321 void cont_handler(int sig_number); 322 323 #ifdef __cplusplus 324 } 325 #endif 326 327 #endif /* _STATCOMMON_H */ 328