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 26 #include <stdio.h> 27 #include <string.h> 28 29 #include <kstat.h> 30 #include <sys/inttypes.h> 31 32 #include <nsctl.h> 33 34 #include "dsstat.h" 35 #include "common.h" 36 37 #include "sdbc_stats.h" 38 #include "report.h" 39 40 extern short dflags; 41 42 /* 43 * Return the number of ticks delta between two hrtime_t 44 * values. Attempt to cater for various kinds of overflow 45 * in hrtime_t - no matter how improbable. 46 */ 47 uint64_t 48 hrtime_delta(hrtime_t old, hrtime_t new) 49 { 50 51 uint64_t del; 52 53 if ((new >= old) && (old >= 0L)) { 54 return (new - old); 55 } else { 56 /* 57 * We've overflowed the positive portion of an 58 * hrtime_t. 59 */ 60 if (new < 0L) { 61 /* 62 * The new value is negative. Handle the 63 * case where the old value is positive or 64 * negative. 65 */ 66 uint64_t n1; 67 uint64_t o1; 68 69 n1 = -new; 70 71 if (old > 0L) { 72 return (n1 - old); 73 } else { 74 o1 = -old; 75 del = n1 - o1; 76 return (del); 77 } 78 } else { 79 /* 80 * Either we've just gone from being negative 81 * to positive *or* the last entry was positive 82 * and the new entry is also positive but *less* 83 * than the old entry. This implies we waited 84 * quite a few days on a very fast system between 85 * iostat displays. 86 */ 87 if (old < 0L) { 88 uint64_t o2; 89 90 o2 = -old; 91 del = UINT64_MAX - o2; 92 } else { 93 del = UINT64_MAX - old; 94 } 95 96 del += new; 97 98 return (del); 99 } 100 } 101 } 102 103 /* 104 * Take the difference of an unsigned 32 105 * bit int attempting to cater for 106 * overflow. 107 */ 108 uint32_t 109 u32_delta(uint32_t old, uint32_t new) 110 { 111 112 if (new >= old) 113 return (new - old); 114 else 115 return ((UINT32_MAX - old) + new + 1); 116 } 117 118 /* 119 * Take the difference of an unsigned 64 120 * bit int attempting to cater for 121 * overflow. 122 */ 123 uint64_t 124 u64_delta(uint64_t old, uint64_t new) 125 { 126 127 if (new >= old) 128 return (new - old); 129 else 130 return ((UINT64_MAX - old) + new + 1); 131 } 132 133 /* 134 * io_report() - diffs and reports data contained in 135 * kstat_io_t structures. 136 * 137 * parameters 138 * kstat_io_t *cur - pointer to current data 139 * 140 * kstat_io_t *pre - pointer to data as it was 141 * at the beginning of an interval. 142 */ 143 void 144 io_report(kstat_io_t *cur, kstat_io_t *pre, sdbcstat_t *sdbcstat) 145 { 146 sdbcvals_t vals; 147 148 double rd_cnt, wr_cnt; 149 double rd_kb, wr_kb, hr_etime; 150 151 double rtm, tps, avs, etime; 152 153 if (sdbcstat && 154 sdbc_getvalues(sdbcstat, &vals, (SDBC_KBYTES | SDBC_INTAVG))) 155 return; 156 157 /* Time */ 158 hr_etime = hrtime_delta(pre->wlastupdate, cur->wlastupdate); 159 etime = hr_etime / (double)NANOSEC; 160 161 /* Read count */ 162 rd_cnt = (double)u32_delta(pre->reads, cur->reads); 163 if (rd_cnt) rd_cnt /= etime; 164 165 /* Bytes read */ 166 rd_kb = (double)u64_delta(pre->nread, cur->nread) / KILOBYTE; 167 if (rd_kb) rd_kb /= etime; 168 169 /* Write count */ 170 wr_cnt = (double)u32_delta(pre->writes, cur->writes); 171 if (wr_cnt) wr_cnt /= etime; 172 173 /* Bytes written */ 174 wr_kb = (double)u64_delta(pre->nwritten, cur->nwritten) / KILOBYTE; 175 if (wr_kb) wr_kb /= etime; 176 177 /* Calculate service times */ 178 avs = (double)hrtime_delta(pre->rlentime, cur->rlentime) / hr_etime; 179 tps = (double)rd_cnt + wr_cnt; 180 181 if (tps > 0) 182 rtm = (1000 / tps) * avs; 183 else 184 rtm = 0.0; 185 186 /* Output */ 187 if (dflags & SUMMARY) { 188 if ((mode & MULTI) && (mode & SDBC)) { 189 if (sdbcstat) { 190 printf(KPS_INF_FMT, (float)vals.total_cache); 191 printf(KPS_INF_FMT, (float)vals.total_disk); 192 } else { 193 printf(DATA_C6, NO_INFO); 194 printf(KPS_INF_FMT, rd_kb + wr_kb); 195 } 196 } else 197 printf(KPS_INF_FMT, rd_kb + wr_kb); 198 199 printf(TPS_INF_FMT, (uint32_t)(rd_cnt + wr_cnt)); 200 printf(SVT_INF_FMT, rtm); 201 202 goto done; 203 } 204 205 if (dflags & READ) { 206 if ((mode & MULTI) && (mode & SDBC)) { 207 if (sdbcstat) { 208 printf(KPS_INF_FMT, (float)vals.cache_read); 209 printf(KPS_INF_FMT, (float)vals.disk_read); 210 } else { 211 printf(DATA_C6, NO_INFO); 212 printf(KPS_INF_FMT, rd_kb); 213 } 214 215 } else 216 printf(KPS_INF_FMT, rd_kb); 217 218 printf(TPS_INF_FMT, (uint32_t)rd_cnt); 219 } 220 221 if (dflags & WRITE) { 222 if ((mode & MULTI) && (mode & SDBC)) { 223 if (sdbcstat) { 224 printf(KPS_INF_FMT, (float)vals.cache_write); 225 printf(KPS_INF_FMT, (float)vals.disk_write); 226 } else { 227 printf(DATA_C6, NO_INFO); 228 printf(KPS_INF_FMT, wr_kb); 229 } 230 231 } else 232 printf(KPS_INF_FMT, wr_kb); 233 234 printf(TPS_INF_FMT, (uint32_t)wr_cnt); 235 } 236 237 if (dflags & TIMING) { 238 printf(SVT_INF_FMT, rtm); 239 } 240 241 done: 242 linesout++; 243 } 244 245 int 246 io_value_check(kstat_io_t *pre, kstat_io_t *cur) 247 { 248 if (u32_delta(pre->reads, cur->reads)) 249 return (1); 250 if (u32_delta(pre->writes, cur->writes)) 251 return (1); 252 253 return (0); 254 } 255 256 /* 257 * cd_report() - reports cache desriptor related statistics 258 * based on the dflags global variable 259 * 260 * parameters 261 * sdbcstat_t *sdbcstat - pointer to the cache structure 262 * to be reported on. 263 */ 264 void 265 cd_report(sdbcstat_t *sdbcstat) 266 { 267 sdbcvals_t vals; 268 269 /* Extract statistics, average for time */ 270 if (sdbc_getvalues(sdbcstat, &vals, (SDBC_KBYTES | SDBC_INTAVG))) 271 return; 272 273 /* Output */ 274 if (rflags & MULTI) { 275 printf(VOL_HDR_FMT, ""); 276 277 if (dflags & FLAGS) { 278 printf(STAT_HDR_FMT, ""); 279 printf(STAT_HDR_FMT, ""); 280 } 281 282 if (dflags & PCTS) 283 printf(PCT_HDR_FMT, ""); 284 285 if (dflags & SUMMARY) { 286 printf(KPS_INF_FMT, (float)vals.total_cache); 287 printf(DATA_C4, NO_INFO); 288 printf(DATA_C4, NO_INFO); 289 printf("\n"); 290 linesout++; 291 return; 292 } 293 294 if (dflags & READ) { 295 printf(KPS_INF_FMT, (float)vals.cache_read); 296 printf(DATA_C4, NO_INFO); 297 } 298 299 if (dflags & WRITE) { 300 printf(KPS_INF_FMT, (float)vals.cache_write); 301 printf(DATA_C4, NO_INFO); 302 } 303 304 if (dflags & TIMING) { 305 printf(DATA_C4, NO_INFO); 306 } 307 308 linesout++; 309 printf("\n"); 310 return; 311 } 312 313 if (dflags & SUMMARY) { 314 (void) printf(DATA_I32, vals.total_cache); 315 (void) printf(DATA_I32, vals.total_disk); 316 (void) printf(HIT_INF_FMT, vals.cache_hit); 317 318 linesout++; 319 printf("\n"); 320 return; 321 } 322 323 if (dflags & READ) { 324 (void) printf(DATA_I32, vals.cache_read); 325 (void) printf(DATA_I32, vals.disk_read); 326 (void) printf(HIT_INF_FMT, vals.read_hit); 327 } 328 329 if (dflags & WRITE) { 330 (void) printf(DATA_I32, vals.cache_write); 331 (void) printf(DATA_I32, vals.disk_write); 332 (void) printf(HIT_INF_FMT, vals.write_hit); 333 } 334 335 if (dflags & DESTAGED) 336 (void) printf(DATA_I32, vals.destaged); 337 338 if (dflags & WRCANCEL) 339 (void) printf(DATA_I32, vals.write_cancellations); 340 341 linesout++; 342 printf("\n"); 343 } 344 345 /* 346 * header() - outputs an appropriate header by referencing the 347 * global variables dflsgs and rflags 348 * 349 */ 350 void 351 header() 352 { 353 if (hflags & HEADERS_EXL) 354 if ((linesout % DISPLAY_LINES) != 0) 355 return; 356 357 if (hflags & HEADERS_BOR) 358 if (linesout != 0) 359 return; 360 361 if (hflags & HEADERS_ATT) 362 if (hflags & HEADERS_OUT) 363 return; 364 else 365 hflags |= HEADERS_OUT; 366 367 if (linesout) 368 (void) printf("\n"); 369 370 printf(VOL_HDR_FMT, SET_HDR_TXT); 371 372 if (dflags & FLAGS) { 373 printf(STAT_HDR_FMT, TYPE_HDR_TXT); 374 printf(STAT_HDR_FMT, STAT_HDR_TXT); 375 } 376 377 if (dflags & ASYNC_QUEUE) 378 printf(STAT_HDR_FMT, QUEUE_HDR_TXT); 379 380 if (dflags & PCTS) 381 printf(PCT_HDR_FMT, PCT_HDR_TXT); 382 383 printf(ROLE_HDR_FMT, ROLE_HDR_TXT); 384 385 if (dflags & ASYNC_QUEUE) { 386 printf(TPS_HDR_FMT, QUEUE_ITEMS_TXT); 387 printf(KPS_HDR_FMT, QUEUE_KBYTES_TXT); 388 printf(TPS_HDR_FMT, QUEUE_ITEMS_HW_TXT); 389 printf(KPS_HDR_FMT, QUEUE_KBYTES_HW_TXT); 390 } 391 392 if (dflags & SUMMARY) { 393 if ((mode & MULTI) && (mode & SDBC)) { 394 printf(KPS_HDR_FMT, CKPS_HDR_TXT); 395 printf(KPS_HDR_FMT, DKPS_HDR_TXT); 396 } else 397 printf(KPS_HDR_FMT, KPS_HDR_TXT); 398 printf(TPS_HDR_FMT, TPS_HDR_TXT); 399 printf(SVT_HDR_FMT, SVT_HDR_TXT); 400 401 printf("\n"); 402 403 return; 404 } 405 406 if (dflags & READ) { 407 if ((mode & MULTI) && (mode & SDBC)) { 408 printf(KPS_HDR_FMT, CRKPS_HDR_TXT); 409 printf(KPS_HDR_FMT, DRKPS_HDR_TXT); 410 } else 411 printf(KPS_HDR_FMT, RKPS_HDR_TXT); 412 413 printf(TPS_HDR_FMT, RTPS_HDR_TXT); 414 } 415 416 if (dflags & WRITE) { 417 if ((mode & MULTI) && (mode & SDBC)) { 418 printf(KPS_HDR_FMT, CWKPS_HDR_TXT); 419 printf(KPS_HDR_FMT, DWKPS_HDR_TXT); 420 } else 421 printf(KPS_HDR_FMT, WKPS_HDR_TXT); 422 423 printf(TPS_HDR_FMT, WTPS_HDR_TXT); 424 } 425 426 if (dflags & TIMING) 427 printf(SVT_HDR_FMT, SVT_HDR_TXT); 428 429 (void) printf("\n"); 430 } 431