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 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_t *cur_kstat, kstat_t *pre_kstat, 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 kstat_io_t *cur = cur_kstat->ks_data; 154 kstat_io_t *pre = pre_kstat->ks_data; 155 156 if (sdbcstat && 157 sdbc_getvalues(sdbcstat, &vals, (SDBC_KBYTES | SDBC_INTAVG))) 158 return; 159 160 /* Time */ 161 hr_etime = hrtime_delta(pre_kstat->ks_snaptime, cur_kstat->ks_snaptime); 162 etime = hr_etime / (double)NANOSEC; 163 164 /* Read count */ 165 rd_cnt = (double)u32_delta(pre->reads, cur->reads); 166 if (rd_cnt) rd_cnt /= etime; 167 168 /* Bytes read */ 169 rd_kb = (double)u64_delta(pre->nread, cur->nread) / KILOBYTE; 170 if (rd_kb) rd_kb /= etime; 171 172 /* Write count */ 173 wr_cnt = (double)u32_delta(pre->writes, cur->writes); 174 if (wr_cnt) wr_cnt /= etime; 175 176 /* Bytes written */ 177 wr_kb = (double)u64_delta(pre->nwritten, cur->nwritten) / KILOBYTE; 178 if (wr_kb) wr_kb /= etime; 179 180 /* Calculate service times */ 181 avs = (double)hrtime_delta(pre->rlentime, cur->rlentime) / hr_etime; 182 tps = (double)rd_cnt + wr_cnt; 183 184 if (tps > 0) 185 rtm = (1000 / tps) * avs; 186 else 187 rtm = 0.0; 188 189 /* Output */ 190 if (dflags & SUMMARY) { 191 if ((mode & MULTI) && (mode & SDBC)) { 192 if (sdbcstat) { 193 printf(KPS_INF_FMT, (float)vals.total_cache); 194 printf(KPS_INF_FMT, (float)vals.total_disk); 195 } else { 196 printf(DATA_C6, NO_INFO); 197 printf(KPS_INF_FMT, rd_kb + wr_kb); 198 } 199 } else 200 printf(KPS_INF_FMT, rd_kb + wr_kb); 201 202 printf(TPS_INF_FMT, (uint32_t)(rd_cnt + wr_cnt)); 203 printf(SVT_INF_FMT, rtm); 204 205 goto done; 206 } 207 208 if (dflags & READ) { 209 if ((mode & MULTI) && (mode & SDBC)) { 210 if (sdbcstat) { 211 printf(KPS_INF_FMT, (float)vals.cache_read); 212 printf(KPS_INF_FMT, (float)vals.disk_read); 213 } else { 214 printf(DATA_C6, NO_INFO); 215 printf(KPS_INF_FMT, rd_kb); 216 } 217 218 } else 219 printf(KPS_INF_FMT, rd_kb); 220 221 printf(TPS_INF_FMT, (uint32_t)rd_cnt); 222 } 223 224 if (dflags & WRITE) { 225 if ((mode & MULTI) && (mode & SDBC)) { 226 if (sdbcstat) { 227 printf(KPS_INF_FMT, (float)vals.cache_write); 228 printf(KPS_INF_FMT, (float)vals.disk_write); 229 } else { 230 printf(DATA_C6, NO_INFO); 231 printf(KPS_INF_FMT, wr_kb); 232 } 233 234 } else 235 printf(KPS_INF_FMT, wr_kb); 236 237 printf(TPS_INF_FMT, (uint32_t)wr_cnt); 238 } 239 240 if (dflags & TIMING) { 241 printf(SVT_INF_FMT, rtm); 242 } 243 244 done: 245 linesout++; 246 } 247 248 int 249 io_value_check(kstat_io_t *pre, kstat_io_t *cur) 250 { 251 if (u32_delta(pre->reads, cur->reads)) 252 return (1); 253 if (u32_delta(pre->writes, cur->writes)) 254 return (1); 255 256 return (0); 257 } 258 259 /* 260 * cd_report() - reports cache desriptor related statistics 261 * based on the dflags global variable 262 * 263 * parameters 264 * sdbcstat_t *sdbcstat - pointer to the cache structure 265 * to be reported on. 266 */ 267 void 268 cd_report(sdbcstat_t *sdbcstat) 269 { 270 sdbcvals_t vals; 271 272 /* Extract statistics, average for time */ 273 if (sdbc_getvalues(sdbcstat, &vals, (SDBC_KBYTES | SDBC_INTAVG))) 274 return; 275 276 /* Output */ 277 if (rflags & MULTI) { 278 printf(VOL_HDR_FMT, ""); 279 280 if (dflags & FLAGS) { 281 printf(STAT_HDR_FMT, ""); 282 printf(STAT_HDR_FMT, ""); 283 } 284 285 if (dflags & PCTS) 286 printf(PCT_HDR_FMT, ""); 287 288 if (dflags & SUMMARY) { 289 printf(KPS_INF_FMT, (float)vals.total_cache); 290 printf(DATA_C4, NO_INFO); 291 printf(DATA_C4, NO_INFO); 292 printf("\n"); 293 linesout++; 294 return; 295 } 296 297 if (dflags & READ) { 298 printf(KPS_INF_FMT, (float)vals.cache_read); 299 printf(DATA_C4, NO_INFO); 300 } 301 302 if (dflags & WRITE) { 303 printf(KPS_INF_FMT, (float)vals.cache_write); 304 printf(DATA_C4, NO_INFO); 305 } 306 307 if (dflags & TIMING) { 308 printf(DATA_C4, NO_INFO); 309 } 310 311 linesout++; 312 printf("\n"); 313 return; 314 } 315 316 if (dflags & SUMMARY) { 317 (void) printf(DATA_I32, vals.total_cache); 318 (void) printf(DATA_I32, vals.total_disk); 319 (void) printf(HIT_INF_FMT, vals.cache_hit); 320 321 linesout++; 322 printf("\n"); 323 return; 324 } 325 326 if (dflags & READ) { 327 (void) printf(DATA_I32, vals.cache_read); 328 (void) printf(DATA_I32, vals.disk_read); 329 (void) printf(HIT_INF_FMT, vals.read_hit); 330 } 331 332 if (dflags & WRITE) { 333 (void) printf(DATA_I32, vals.cache_write); 334 (void) printf(DATA_I32, vals.disk_write); 335 (void) printf(HIT_INF_FMT, vals.write_hit); 336 } 337 338 if (dflags & DESTAGED) 339 (void) printf(DATA_I32, vals.destaged); 340 341 if (dflags & WRCANCEL) 342 (void) printf(DATA_I32, vals.write_cancellations); 343 344 linesout++; 345 printf("\n"); 346 } 347 348 /* 349 * header() - outputs an appropriate header by referencing the 350 * global variables dflsgs and rflags 351 * 352 */ 353 void 354 header() 355 { 356 if (hflags & HEADERS_EXL) 357 if ((linesout % DISPLAY_LINES) != 0) 358 return; 359 360 if (hflags & HEADERS_BOR) 361 if (linesout != 0) 362 return; 363 364 if (hflags & HEADERS_ATT) 365 if (hflags & HEADERS_OUT) 366 return; 367 else 368 hflags |= HEADERS_OUT; 369 370 if (linesout) 371 (void) printf("\n"); 372 373 printf(VOL_HDR_FMT, SET_HDR_TXT); 374 375 if (dflags & FLAGS) { 376 printf(STAT_HDR_FMT, TYPE_HDR_TXT); 377 printf(STAT_HDR_FMT, STAT_HDR_TXT); 378 } 379 380 if (dflags & ASYNC_QUEUE) 381 printf(STAT_HDR_FMT, QUEUE_HDR_TXT); 382 383 if (dflags & PCTS) 384 printf(PCT_HDR_FMT, PCT_HDR_TXT); 385 386 printf(ROLE_HDR_FMT, ROLE_HDR_TXT); 387 388 if (dflags & ASYNC_QUEUE) { 389 printf(TPS_HDR_FMT, QUEUE_ITEMS_TXT); 390 printf(KPS_HDR_FMT, QUEUE_KBYTES_TXT); 391 printf(TPS_HDR_FMT, QUEUE_ITEMS_HW_TXT); 392 printf(KPS_HDR_FMT, QUEUE_KBYTES_HW_TXT); 393 } 394 395 if (dflags & SUMMARY) { 396 if ((mode & MULTI) && (mode & SDBC)) { 397 printf(KPS_HDR_FMT, CKPS_HDR_TXT); 398 printf(KPS_HDR_FMT, DKPS_HDR_TXT); 399 } else 400 printf(KPS_HDR_FMT, KPS_HDR_TXT); 401 printf(TPS_HDR_FMT, TPS_HDR_TXT); 402 printf(SVT_HDR_FMT, SVT_HDR_TXT); 403 404 printf("\n"); 405 406 return; 407 } 408 409 if (dflags & READ) { 410 if ((mode & MULTI) && (mode & SDBC)) { 411 printf(KPS_HDR_FMT, CRKPS_HDR_TXT); 412 printf(KPS_HDR_FMT, DRKPS_HDR_TXT); 413 } else 414 printf(KPS_HDR_FMT, RKPS_HDR_TXT); 415 416 printf(TPS_HDR_FMT, RTPS_HDR_TXT); 417 } 418 419 if (dflags & WRITE) { 420 if ((mode & MULTI) && (mode & SDBC)) { 421 printf(KPS_HDR_FMT, CWKPS_HDR_TXT); 422 printf(KPS_HDR_FMT, DWKPS_HDR_TXT); 423 } else 424 printf(KPS_HDR_FMT, WKPS_HDR_TXT); 425 426 printf(TPS_HDR_FMT, WTPS_HDR_TXT); 427 } 428 429 if (dflags & TIMING) 430 printf(SVT_HDR_FMT, SVT_HDR_TXT); 431 432 (void) printf("\n"); 433 } 434