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