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