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