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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23 * 24 * Common routines for acquiring snapshots of kstats for 25 * iostat, mpstat, and vmstat. 26 */ 27 28 #ifndef _STATCOMMON_H 29 #define _STATCOMMON_H 30 31 #ifdef __cplusplus 32 extern "C" { 33 #endif 34 35 #include <stdio.h> 36 #include <kstat.h> 37 #include <sys/time.h> 38 #include <sys/types.h> 39 #include <sys/buf.h> 40 #include <sys/dnlc.h> 41 #include <sys/sysinfo.h> 42 #include <sys/processor.h> 43 #include <sys/pset.h> 44 #include <sys/avl.h> 45 46 /* No CPU present at this CPU position */ 47 #define ID_NO_CPU -1 48 /* CPU belongs to no pset (we number this as "pset 0") */ 49 #define ID_NO_PSET 0 50 /* CPU is usable */ 51 #define CPU_ONLINE(s) ((s) == P_ONLINE || (s) == P_NOINTR) 52 /* will the CPU have kstats */ 53 #define CPU_ACTIVE(c) (CPU_ONLINE((c)->cs_state) && (c)->cs_id != ID_NO_CPU) 54 /* IO device has no identified ID */ 55 #define IODEV_NO_ID -1 56 /* no limit to iodevs to collect */ 57 #define UNLIMITED_IODEVS ((size_t)-1) 58 59 #define NODATE 0 /* Default: No time stamp */ 60 #define DDATE 1 /* Standard date format */ 61 #define UDATE 2 /* Internal representation of Unix time */ 62 63 64 enum snapshot_types { 65 /* All CPUs separately */ 66 SNAP_CPUS = 1 << 0, 67 /* Aggregated processor sets */ 68 SNAP_PSETS = 1 << 1, 69 /* sys-wide stats including aggregated CPU stats */ 70 SNAP_SYSTEM = 1 << 2, 71 /* interrupt sources and counts */ 72 SNAP_INTERRUPTS = 1 << 3, 73 /* disk etc. stats */ 74 SNAP_IODEVS = 1 << 4, 75 /* disk controller aggregates */ 76 SNAP_CONTROLLERS = 1 << 5, 77 /* mpxio L I (multipath) paths: -X: Lun,LunInitiator */ 78 SNAP_IOPATHS_LI = 1 << 6, 79 /* mpxio LTI (multipath) paths: -Y: Lun,LunTarget,LunTargetInitiator */ 80 SNAP_IOPATHS_LTI = 1 << 7, 81 /* disk error stats */ 82 SNAP_IODEV_ERRORS = 1 << 8, 83 /* pretty names for iodevs */ 84 SNAP_IODEV_PRETTY = 1 << 9, 85 /* devid for iodevs */ 86 SNAP_IODEV_DEVID = 1 << 10 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 /* AVL structures to speedup insertion */ 192 avl_tree_t *avl_list; /* list this element belongs to */ 193 avl_node_t avl_link; 194 }; 195 196 /* which iodevs to show. */ 197 struct iodev_filter { 198 /* nr. of iodevs to choose */ 199 size_t if_max_iodevs; 200 /* bit mask of enum io_types to allow */ 201 int if_allowed_types; 202 /* should we show floppy ? if_names can override this */ 203 int if_skip_floppy; 204 /* nr. of named iodevs */ 205 size_t if_nr_names; 206 char **if_names; 207 }; 208 209 /* The primary structure of a system snapshot. */ 210 struct snapshot { 211 /* what types were *requested* */ 212 enum snapshot_types s_types; 213 size_t s_nr_cpus; 214 struct cpu_snapshot *s_cpus; 215 size_t s_nr_psets; 216 struct pset_snapshot *s_psets; 217 size_t s_nr_intrs; 218 struct intr_snapshot *s_intrs; 219 size_t s_nr_iodevs; 220 struct iodev_snapshot *s_iodevs; 221 size_t s_iodevs_is_name_maxlen; 222 struct sys_snapshot s_sys; 223 struct biostats s_biostats; 224 }; 225 226 /* print a message and exit with failure */ 227 void fail(int do_perror, char *message, ...); 228 229 /* strdup str, or exit with failure */ 230 char *safe_strdup(char *str); 231 232 /* malloc successfully, or exit with failure */ 233 void *safe_alloc(size_t size); 234 235 /* 236 * Copy a kstat from src to dst. If the source kstat contains no data, 237 * then set the destination kstat data to NULL and size to zero. 238 * Returns 0 on success. 239 */ 240 int kstat_copy(const kstat_t *src, kstat_t *dst); 241 242 /* 243 * Look up the named kstat, and give the ui64 difference i.e. 244 * new - old, or if old is NULL, return new. 245 */ 246 uint64_t kstat_delta(kstat_t *old, kstat_t *new, char *name); 247 248 /* Return the number of ticks delta between two hrtime_t values. */ 249 uint64_t hrtime_delta(hrtime_t old, hrtime_t new); 250 251 /* 252 * Add the integer-valued stats from "src" to the 253 * existing ones in "dst". If "dst" does not contain 254 * stats, then a kstat_copy() is performed. 255 */ 256 int kstat_add(const kstat_t *src, kstat_t *dst); 257 258 /* return the number of CPUs with kstats (i.e. present and online) */ 259 int nr_active_cpus(struct snapshot *ss); 260 261 /* 262 * Return the difference in CPU ticks between the two sys 263 * kstats. 264 */ 265 uint64_t cpu_ticks_delta(kstat_t *old, kstat_t *new); 266 267 /* 268 * Open the kstat chain. Cannot fail. 269 */ 270 kstat_ctl_t *open_kstat(void); 271 272 /* 273 * Return a struct snapshot based on the snapshot_types parameter 274 * passed in. iodev_filter may be NULL in which case all iodevs 275 * are selected if SNAP_IODEVS is passed. 276 */ 277 struct snapshot *acquire_snapshot(kstat_ctl_t *, int, struct iodev_filter *); 278 279 /* free a snapshot */ 280 void free_snapshot(struct snapshot *ss); 281 282 typedef void (*snapshot_cb)(void *old, void *new, void *data); 283 284 /* 285 * Call the call back for each pair of data items of the given type, 286 * passing the data pointer passed in as well. If an item has been 287 * added, the first pointer will be NULL; if removed, the second pointer 288 * will be NULL. 289 * 290 * A non-zero return value indicates configuration has changed. 291 */ 292 int snapshot_walk(enum snapshot_types type, struct snapshot *old, 293 struct snapshot *new, snapshot_cb cb, void *data); 294 295 /* 296 * Output a line detailing any configuration changes such as a CPU 297 * brought online, etc, bracketed by << >>. 298 */ 299 void snapshot_report_changes(struct snapshot *old, struct snapshot *new); 300 301 /* Return non-zero if configuration has changed. */ 302 int snapshot_has_changed(struct snapshot *old, struct snapshot *new); 303 304 /* free the given iodev */ 305 void free_iodev(struct iodev_snapshot *iodev); 306 307 /* acquire the I/O devices */ 308 int acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, 309 struct iodev_filter *df); 310 311 /* strcmp-style I/O device comparator */ 312 int iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2); 313 314 /* sleep until *wakeup + interval, keeping cadence where desired */ 315 void sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever, 316 int *caught_cont); 317 318 /* signal handler - so we can be aware of SIGCONT */ 319 void cont_handler(int sig_number); 320 321 /* Print a timestamp in either Unix or standard format. */ 322 void print_timestamp(uint_t); 323 324 #ifdef __cplusplus 325 } 326 #endif 327 328 #endif /* _STATCOMMON_H */ 329