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